Add software
This commit is contained in:
		
							
								
								
									
										107
									
								
								Software/portapack-mayhem/firmware/common/acars_packet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Software/portapack-mayhem/firmware/common/acars_packet.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "acars_packet.hpp"
 | 
			
		||||
 | 
			
		||||
#include "crc.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
 | 
			
		||||
namespace acars {
 | 
			
		||||
 | 
			
		||||
size_t Packet::length() const {
 | 
			
		||||
	return packet_.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::is_valid() const {
 | 
			
		||||
	return true;	//length_valid() && crc_ok();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Timestamp Packet::received_at() const {
 | 
			
		||||
	return packet_.timestamp();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t Packet::block_id() const {
 | 
			
		||||
	return field_.read(96, 8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string Packet::registration_number() const {
 | 
			
		||||
	std::string result;
 | 
			
		||||
	result.reserve(7);
 | 
			
		||||
	
 | 
			
		||||
	const size_t character_length = 8;
 | 
			
		||||
	for(size_t i=16; i<(16+7*character_length); i+=character_length) {
 | 
			
		||||
		result += (field_.read(i, character_length) & 0x7F);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t Packet::read(const size_t start_bit, const size_t length) const {
 | 
			
		||||
	return field_.read(start_bit, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*std::string Packet::text(
 | 
			
		||||
	const size_t start_bit,
 | 
			
		||||
	const size_t character_count
 | 
			
		||||
) const {
 | 
			
		||||
	std::string result;
 | 
			
		||||
	result.reserve(character_count);
 | 
			
		||||
	
 | 
			
		||||
	const size_t character_length = 6;
 | 
			
		||||
	const size_t end_bit = start_bit + character_count * character_length;
 | 
			
		||||
	for(size_t i=start_bit; i<end_bit; i+=character_length) {
 | 
			
		||||
		result += char_to_ascii(field_.read(i, character_length));
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
bool Packet::crc_ok() const {
 | 
			
		||||
	CRCReader field_crc { packet_ };
 | 
			
		||||
	CRC<16> acars_fcs { 0x1021, 0x0000, 0x0000 };
 | 
			
		||||
	
 | 
			
		||||
	for(size_t i=0; i<data_length(); i+=8) {
 | 
			
		||||
		acars_fcs.process_byte(field_crc.read(i, 8));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (acars_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Packet::data_and_fcs_length() const {
 | 
			
		||||
	return length() - 8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Packet::data_length() const {
 | 
			
		||||
	return data_and_fcs_length() - fcs_length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::length_valid() const {
 | 
			
		||||
	const size_t extra_bits = data_and_fcs_length() & 7;
 | 
			
		||||
	if( extra_bits != 0 ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace ais */
 | 
			
		||||
							
								
								
									
										75
									
								
								Software/portapack-mayhem/firmware/common/acars_packet.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								Software/portapack-mayhem/firmware/common/acars_packet.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __ACARS_PACKET_H__
 | 
			
		||||
#define __ACARS_PACKET_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
#include "field_reader.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace acars {
 | 
			
		||||
 | 
			
		||||
class Packet {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr Packet(
 | 
			
		||||
		const baseband::Packet& packet
 | 
			
		||||
	) : packet_ { packet },
 | 
			
		||||
		field_ { packet_ }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t length() const;
 | 
			
		||||
	
 | 
			
		||||
	bool is_valid() const;
 | 
			
		||||
 | 
			
		||||
	Timestamp received_at() const;
 | 
			
		||||
 | 
			
		||||
	uint8_t block_id() const;
 | 
			
		||||
	std::string registration_number() const;
 | 
			
		||||
 | 
			
		||||
	uint32_t read(const size_t start_bit, const size_t length) const;
 | 
			
		||||
	//std::string text(const size_t start_bit, const size_t character_count) const;
 | 
			
		||||
 | 
			
		||||
	bool crc_ok() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
 | 
			
		||||
	using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
 | 
			
		||||
	
 | 
			
		||||
	const baseband::Packet packet_;
 | 
			
		||||
	const Reader field_;
 | 
			
		||||
 | 
			
		||||
	const size_t fcs_length = 16;
 | 
			
		||||
 | 
			
		||||
	size_t data_and_fcs_length() const;
 | 
			
		||||
	size_t data_length() const;
 | 
			
		||||
 | 
			
		||||
	bool length_valid() const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace acars */
 | 
			
		||||
 | 
			
		||||
#endif/*__ACARS_PACKET_H__*/
 | 
			
		||||
							
								
								
									
										135
									
								
								Software/portapack-mayhem/firmware/common/adc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								Software/portapack-mayhem/firmware/common/adc.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __ADC_H__
 | 
			
		||||
#define __ADC_H__
 | 
			
		||||
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
 | 
			
		||||
namespace lpc43xx {
 | 
			
		||||
namespace adc {
 | 
			
		||||
 | 
			
		||||
constexpr size_t clock_rate_max = 4500000U;
 | 
			
		||||
 | 
			
		||||
struct CR {
 | 
			
		||||
	uint32_t sel;
 | 
			
		||||
	uint32_t clkdiv;
 | 
			
		||||
	uint32_t resolution;
 | 
			
		||||
	uint32_t edge;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((sel & 0xff) << 0)
 | 
			
		||||
			| ((clkdiv & 0xff) << 8)
 | 
			
		||||
			| ((0 & 1) << 16)
 | 
			
		||||
			| (((10 - resolution) & 7) << 17)
 | 
			
		||||
			| ((1 & 1) << 21)
 | 
			
		||||
			| ((0 & 7) << 24)
 | 
			
		||||
			| ((edge & 1) << 27)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Config {
 | 
			
		||||
	uint32_t cr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<uint32_t BaseAddress>
 | 
			
		||||
class ADC {
 | 
			
		||||
public:
 | 
			
		||||
	static void power_up(const Config config) {
 | 
			
		||||
		adcp().CR = config.cr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void clock_enable() {
 | 
			
		||||
		if( &adcp() == LPC_ADC0 ) {
 | 
			
		||||
			LPC_CCU1->CLK_APB3_ADC0_CFG.AUTO = 1;
 | 
			
		||||
			LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 1;
 | 
			
		||||
		}
 | 
			
		||||
		if( &adcp() == LPC_ADC1 ) {
 | 
			
		||||
			LPC_CCU1->CLK_APB3_ADC1_CFG.AUTO = 1;
 | 
			
		||||
			LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void clock_disable() {
 | 
			
		||||
		if( &adcp() == LPC_ADC0 ) {
 | 
			
		||||
			LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 0;
 | 
			
		||||
		}  
 | 
			
		||||
		if( &adcp() == LPC_ADC1 ) {
 | 
			
		||||
			LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 0;
 | 
			
		||||
		}  
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void disable() {
 | 
			
		||||
		adcp().INTEN = 0;
 | 
			
		||||
		adcp().CR = 0;
 | 
			
		||||
 | 
			
		||||
		clock_disable();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void interrupts_disable() {
 | 
			
		||||
		adcp().INTEN = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void interrupts_enable(const uint32_t mask) {
 | 
			
		||||
		adcp().INTEN = mask;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void start_burst() {
 | 
			
		||||
		adcp().CR |= (1U << 16);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void start_once() {
 | 
			
		||||
		adcp().CR |= (1U << 24);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void start_once(size_t n) {
 | 
			
		||||
		uint32_t cr = adcp().CR;
 | 
			
		||||
		cr &= ~(0xffU);
 | 
			
		||||
		cr |= (1 << 24) | (1 << n);
 | 
			
		||||
		adcp().CR = cr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void stop_burst() {
 | 
			
		||||
		adcp().CR &= ~(1U << 16);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static uint32_t convert(size_t n) {
 | 
			
		||||
		start_once(n);
 | 
			
		||||
		while(true) {
 | 
			
		||||
			const uint32_t data = adcp().DR[n];
 | 
			
		||||
			if( (data >> 31) & 1 ) {
 | 
			
		||||
				return (data >> 6) & 0x3ff;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static LPC_ADCx_Type& adcp() {
 | 
			
		||||
		return *reinterpret_cast<LPC_ADCx_Type*>(BaseAddress);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace adc */
 | 
			
		||||
} /* namespace lpc43xx */
 | 
			
		||||
 | 
			
		||||
#endif/*__ADC_H__*/
 | 
			
		||||
							
								
								
									
										384
									
								
								Software/portapack-mayhem/firmware/common/adsb.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								Software/portapack-mayhem/firmware/common/adsb.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,384 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "adsb.hpp"
 | 
			
		||||
#include "sine_table.hpp"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
namespace adsb {
 | 
			
		||||
 | 
			
		||||
void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address) {
 | 
			
		||||
	frame.clear();
 | 
			
		||||
	frame.push_byte((DF_ADSB << 3) | 5);	// DF and CA
 | 
			
		||||
	frame.push_byte(ICAO_address >> 16);
 | 
			
		||||
	frame.push_byte(ICAO_address >> 8);
 | 
			
		||||
	frame.push_byte(ICAO_address & 0xFF);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void encode_frame_id(ADSBFrame& frame, const uint32_t ICAO_address, const std::string& callsign) {
 | 
			
		||||
	std::string callsign_formatted(8, '_');
 | 
			
		||||
	uint64_t callsign_coded = 0;
 | 
			
		||||
	uint32_t c, s;
 | 
			
		||||
	char ch;
 | 
			
		||||
	
 | 
			
		||||
	make_frame_adsb(frame, ICAO_address);
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte(TC_IDENT << 3);		// No aircraft category
 | 
			
		||||
	
 | 
			
		||||
	// Translate and encode callsign
 | 
			
		||||
	for (c = 0; c < 8; c++) {
 | 
			
		||||
		ch = callsign[c];
 | 
			
		||||
		
 | 
			
		||||
		for (s = 0; s < 64; s++)
 | 
			
		||||
			if (ch == icao_id_lut[s]) break;
 | 
			
		||||
		
 | 
			
		||||
		if (s == 64) {
 | 
			
		||||
			ch = ' ';		// Invalid character
 | 
			
		||||
			s = 32;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		callsign_coded <<= 6;
 | 
			
		||||
		callsign_coded |= s;
 | 
			
		||||
		
 | 
			
		||||
		//callsign[c] = ch;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Insert callsign in frame
 | 
			
		||||
	for (c = 0; c < 6; c++)
 | 
			
		||||
		frame.push_byte((callsign_coded >> ((5 - c) * 8)) & 0xFF);
 | 
			
		||||
	
 | 
			
		||||
	frame.make_CRC();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string decode_frame_id(ADSBFrame& frame) {
 | 
			
		||||
	std::string callsign = "";
 | 
			
		||||
	uint8_t * raw_data = frame.get_raw_data();
 | 
			
		||||
	uint64_t callsign_coded = 0;
 | 
			
		||||
	uint32_t c;
 | 
			
		||||
	
 | 
			
		||||
	// Frame bytes to long
 | 
			
		||||
	for (c = 5; c < 11; c++) {
 | 
			
		||||
		callsign_coded <<= 8;
 | 
			
		||||
		callsign_coded |= raw_data[c];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Long to 6-bit characters
 | 
			
		||||
	for (c = 0; c < 8; c++) {
 | 
			
		||||
		callsign.append(1, icao_id_lut[(callsign_coded >> 42) & 0x3F]);
 | 
			
		||||
		callsign_coded <<= 6;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return callsign;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*void generate_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code) {
 | 
			
		||||
	make_frame_mode_s(frame, ICAO_address);
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte((28 << 3) + 1);	// TC = 28 (Emergency), subtype = 1 (Emergency)
 | 
			
		||||
	frame.push_byte(code << 5);
 | 
			
		||||
	
 | 
			
		||||
	frame.make_CRC();
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
void encode_frame_squawk(ADSBFrame& frame, const uint32_t squawk) {
 | 
			
		||||
	uint32_t squawk_coded;
 | 
			
		||||
	
 | 
			
		||||
	frame.clear();
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte(DF_EHS_SQUAWK << 3);	// DF
 | 
			
		||||
	frame.push_byte(0);
 | 
			
		||||
	
 | 
			
		||||
	// 12 11 10  9  8  7  6  5  4  3  2  1  0
 | 
			
		||||
	// 31 30 29 28 27 26 25 24 23 22 21 20 19
 | 
			
		||||
	// D4 B4 D2 B2 D1 B1 __ A4 C4 A2 C2 A1 C1
 | 
			
		||||
	// ABCD = code (octal, 0000~7777)
 | 
			
		||||
	
 | 
			
		||||
	// FEDCBA9876543210
 | 
			
		||||
	// xAAAxBBBxCCCxDDD
 | 
			
		||||
	// x421x421x421x421
 | 
			
		||||
	
 | 
			
		||||
	squawk_coded = ((squawk << 10) & 0x1000) |	// D4
 | 
			
		||||
					((squawk << 1) & 0x0800) |	// B4
 | 
			
		||||
					((squawk << 9) & 0x0400) |	// D2
 | 
			
		||||
					((squawk << 0) & 0x0200) |	// B2
 | 
			
		||||
					((squawk << 8) & 0x0100) |	// D1
 | 
			
		||||
					((squawk >> 1) & 0x0080) |	// B1
 | 
			
		||||
					
 | 
			
		||||
					((squawk >> 9) & 0x0020) |	// A4
 | 
			
		||||
					((squawk >> 2) & 0x0010) |	// C4
 | 
			
		||||
					((squawk >> 10) & 0x0008) |	// A2
 | 
			
		||||
					((squawk >> 3) & 0x0004) |	// C2
 | 
			
		||||
					((squawk >> 11) & 0x0002) |	// A1
 | 
			
		||||
					((squawk >> 4) & 0x0001);	// C1
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte(squawk_coded >> 5);
 | 
			
		||||
	frame.push_byte(squawk_coded << 3);
 | 
			
		||||
	
 | 
			
		||||
	frame.make_CRC();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float cpr_mod(float a, float b) {
 | 
			
		||||
	return a - (b * floor(a / b));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cpr_NL_precise(float lat) {
 | 
			
		||||
	return (int) floor(2 * PI / acos(1 - ((1 - cos(PI / (2 * NZ))) / pow(cos(PI * lat / 180), 2))));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cpr_NL_approx(float lat) {
 | 
			
		||||
	if (lat < 0)
 | 
			
		||||
		lat = -lat;		// Symmetry
 | 
			
		||||
	
 | 
			
		||||
	for (size_t c = 0; c < 58; c++) {
 | 
			
		||||
		if (lat < adsb_lat_lut[c])
 | 
			
		||||
			return 59 - c;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return 1;	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cpr_NL(float lat) {
 | 
			
		||||
	// TODO prove that the approximate function is good
 | 
			
		||||
	// enough for the precision we need. Uncomment if
 | 
			
		||||
	// that is true. No performance penalty was noticed
 | 
			
		||||
	// from testing, but if you find it might be an issue,
 | 
			
		||||
	// switch to cpr_NL_approx() instead:
 | 
			
		||||
 | 
			
		||||
	//return cpr_NL_approx(lat);
 | 
			
		||||
 | 
			
		||||
	return cpr_NL_precise(lat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cpr_N(float lat, int is_odd) {
 | 
			
		||||
    int nl = cpr_NL(lat) - is_odd;
 | 
			
		||||
    
 | 
			
		||||
    if (nl < 1)
 | 
			
		||||
		nl = 1;
 | 
			
		||||
	
 | 
			
		||||
    return nl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float cpr_Dlon(float lat, int is_odd) {
 | 
			
		||||
    return 360.0 / cpr_N(lat, is_odd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
 | 
			
		||||
	const float latitude, const float longitude, const uint32_t time_parity) {
 | 
			
		||||
	
 | 
			
		||||
	uint32_t altitude_coded;
 | 
			
		||||
	uint32_t lat, lon;
 | 
			
		||||
	float delta_lat, yz, rlat, delta_lon, xz;
 | 
			
		||||
	
 | 
			
		||||
	make_frame_adsb(frame, ICAO_address);
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte(TC_AIRBORNE_POS << 3);		// Bits 2~1: Surveillance Status, bit 0: NICsb
 | 
			
		||||
	
 | 
			
		||||
	altitude_coded = (altitude + 1000) / 25;	// 25ft precision, insert Q-bit (1)
 | 
			
		||||
	altitude_coded = ((altitude_coded & 0x7F0) << 1) | 0x10 | (altitude_coded & 0x0F);
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte(altitude_coded >> 4);		// Top-most altitude bits
 | 
			
		||||
	
 | 
			
		||||
	// CPR encoding
 | 
			
		||||
	// Info from: http://antena.fe.uni-lj.si/literatura/Razno/Avionika/modes/CPRencoding.pdf
 | 
			
		||||
	
 | 
			
		||||
	delta_lat = 360.0 / ((4.0 * NZ) - time_parity);		// NZ = 15
 | 
			
		||||
	yz = floor(CPR_MAX_VALUE * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
 | 
			
		||||
	rlat = delta_lat * ((yz / CPR_MAX_VALUE) + floor(latitude / delta_lat));
 | 
			
		||||
	
 | 
			
		||||
	if ((cpr_NL(rlat) - time_parity) > 0)
 | 
			
		||||
		delta_lon = 360.0 / cpr_N(rlat, time_parity);
 | 
			
		||||
	else
 | 
			
		||||
		delta_lon = 360.0;
 | 
			
		||||
	xz = floor(CPR_MAX_VALUE * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
 | 
			
		||||
	
 | 
			
		||||
	lat = cpr_mod(yz, CPR_MAX_VALUE);
 | 
			
		||||
	lon = cpr_mod(xz, CPR_MAX_VALUE);
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte((altitude_coded << 4) | ((uint32_t)time_parity << 2) | (lat >> 15));	// T = 0
 | 
			
		||||
	frame.push_byte(lat >> 7);
 | 
			
		||||
	frame.push_byte((lat << 1) | (lon >> 16));
 | 
			
		||||
	frame.push_byte(lon >> 8);
 | 
			
		||||
	frame.push_byte(lon);
 | 
			
		||||
	
 | 
			
		||||
	frame.make_CRC();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decoding method from dump1090
 | 
			
		||||
adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
 | 
			
		||||
	uint8_t * raw_data;
 | 
			
		||||
	uint32_t latcprE, latcprO, loncprE, loncprO;
 | 
			
		||||
	float latE, latO, m, Dlon, cpr_lon_odd, cpr_lon_even, cpr_lat_odd, cpr_lat_even;
 | 
			
		||||
	int ni;
 | 
			
		||||
	adsb_pos position { false, 0, 0, 0 };
 | 
			
		||||
	
 | 
			
		||||
	uint32_t time_even = frame_even.get_rx_timestamp();
 | 
			
		||||
	uint32_t time_odd = frame_odd.get_rx_timestamp();
 | 
			
		||||
	uint8_t * frame_data_even = frame_even.get_raw_data();
 | 
			
		||||
	uint8_t * frame_data_odd = frame_odd.get_raw_data();
 | 
			
		||||
	
 | 
			
		||||
	// Return most recent altitude
 | 
			
		||||
	if (time_even > time_odd)
 | 
			
		||||
		raw_data = frame_data_even;
 | 
			
		||||
	else
 | 
			
		||||
		raw_data = frame_data_odd;
 | 
			
		||||
 | 
			
		||||
	// Q-bit must be present
 | 
			
		||||
	if (raw_data[5] & 1)
 | 
			
		||||
		position.altitude = ((((raw_data[5] & 0xFE) << 3) | ((raw_data[6] & 0xF0) >> 4)) * 25) - 1000;
 | 
			
		||||
 | 
			
		||||
	// Position
 | 
			
		||||
	latcprE = ((frame_data_even[6] & 3) << 15) | (frame_data_even[7] << 7) | (frame_data_even[8] >> 1);
 | 
			
		||||
	loncprE = ((frame_data_even[8] & 1) << 16) | (frame_data_even[9] << 8) | frame_data_even[10];
 | 
			
		||||
	
 | 
			
		||||
	latcprO = ((frame_data_odd[6] & 3) << 15) | (frame_data_odd[7] << 7) | (frame_data_odd[8] >> 1);
 | 
			
		||||
	loncprO = ((frame_data_odd[8] & 1) << 16) | (frame_data_odd[9] << 8) | frame_data_odd[10];
 | 
			
		||||
 | 
			
		||||
	// Calculate the coefficients
 | 
			
		||||
	cpr_lon_even = loncprE / CPR_MAX_VALUE;
 | 
			
		||||
	cpr_lon_odd = loncprO / CPR_MAX_VALUE;
 | 
			
		||||
 | 
			
		||||
	cpr_lat_odd = latcprO / CPR_MAX_VALUE;
 | 
			
		||||
	cpr_lat_even = latcprE / CPR_MAX_VALUE;
 | 
			
		||||
 | 
			
		||||
	// Compute latitude index
 | 
			
		||||
	float j = floor(((59.0 * cpr_lat_even) - (60.0 * cpr_lat_odd)) + 0.5);
 | 
			
		||||
	latE = (360.0 / 60.0) * (cpr_mod(j, 60) + cpr_lat_even);
 | 
			
		||||
	latO = (360.0 / 59.0) * (cpr_mod(j, 59) + cpr_lat_odd);
 | 
			
		||||
 | 
			
		||||
	if (latE >= 270) latE -= 360;
 | 
			
		||||
	if (latO >= 270) latO -= 360;
 | 
			
		||||
 | 
			
		||||
	// Both frames must be in the same latitude zone
 | 
			
		||||
	if (cpr_NL(latE) != cpr_NL(latO))
 | 
			
		||||
		return position;
 | 
			
		||||
 | 
			
		||||
	// Compute longitude
 | 
			
		||||
	if (time_even > time_odd) {
 | 
			
		||||
		// Use even frame2
 | 
			
		||||
		ni = cpr_N(latE, 0);
 | 
			
		||||
		Dlon = 360.0 / ni;
 | 
			
		||||
		
 | 
			
		||||
		m = floor((cpr_lon_even * (cpr_NL(latE) - 1)) - (cpr_lon_odd * cpr_NL(latE)) + 0.5);
 | 
			
		||||
		
 | 
			
		||||
		position.longitude = Dlon * (cpr_mod(m, ni) + cpr_lon_even);
 | 
			
		||||
		
 | 
			
		||||
		position.latitude = latE;
 | 
			
		||||
	} else {
 | 
			
		||||
		// Use odd frame
 | 
			
		||||
		ni = cpr_N(latO, 1);
 | 
			
		||||
		Dlon = 360.0 / ni;
 | 
			
		||||
		
 | 
			
		||||
		m = floor((cpr_lon_even * (cpr_NL(latO) - 1)) - (cpr_lon_odd * cpr_NL(latO)) + 0.5);
 | 
			
		||||
		
 | 
			
		||||
		position.longitude = Dlon * (cpr_mod(m, ni) + cpr_lon_odd);
 | 
			
		||||
		
 | 
			
		||||
		position.latitude = latO;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (position.longitude >= 180) position.longitude -= 360;
 | 
			
		||||
	
 | 
			
		||||
	position.valid = true;
 | 
			
		||||
 | 
			
		||||
	return position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// speed is in knots
 | 
			
		||||
// vertical rate is in ft/min
 | 
			
		||||
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
 | 
			
		||||
	const float angle, const int32_t v_rate) {
 | 
			
		||||
	
 | 
			
		||||
	int32_t velo_ew, velo_ns, v_rate_coded;
 | 
			
		||||
	uint32_t velo_ew_abs, velo_ns_abs, v_rate_coded_abs;
 | 
			
		||||
	
 | 
			
		||||
	// To get NS and EW speeds from speed and bearing, a polar to cartesian conversion is enough
 | 
			
		||||
	velo_ew = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle) + (pi / 2)) * speed);
 | 
			
		||||
	velo_ns = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle)) * speed);
 | 
			
		||||
	
 | 
			
		||||
	v_rate_coded = (v_rate / 64) + 1;
 | 
			
		||||
	
 | 
			
		||||
	velo_ew_abs = abs(velo_ew) + 1; 
 | 
			
		||||
	velo_ns_abs = abs(velo_ns) + 1;
 | 
			
		||||
	v_rate_coded_abs = abs(v_rate_coded);
 | 
			
		||||
	
 | 
			
		||||
	make_frame_adsb(frame, ICAO_address);
 | 
			
		||||
	
 | 
			
		||||
	frame.push_byte((TC_AIRBORNE_VELO << 3) | 1);		// Subtype: 1 (subsonic)
 | 
			
		||||
	frame.push_byte(((velo_ew < 0 ? 1 : 0) << 2) | (velo_ew_abs >> 8));
 | 
			
		||||
	frame.push_byte(velo_ew_abs);
 | 
			
		||||
	frame.push_byte(((velo_ns < 0 ? 1 : 0) << 7) | (velo_ns_abs >> 3));
 | 
			
		||||
	frame.push_byte((velo_ns_abs << 5) | ((v_rate_coded < 0 ? 1 : 0) << 3) | (v_rate_coded_abs >> 6));	// VrSrc = 0
 | 
			
		||||
	frame.push_byte(v_rate_coded_abs << 2);
 | 
			
		||||
	frame.push_byte(0);
 | 
			
		||||
	
 | 
			
		||||
	frame.make_CRC();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decoding method from dump1090
 | 
			
		||||
adsb_vel decode_frame_velo(ADSBFrame& frame){
 | 
			
		||||
	adsb_vel velo {false, 0, 0, 0};
 | 
			
		||||
 | 
			
		||||
	uint8_t * frame_data = frame.get_raw_data();
 | 
			
		||||
	uint8_t velo_type = frame.get_msg_sub();
 | 
			
		||||
 | 
			
		||||
	if(velo_type >= 1 && velo_type <= 4){ //vertical rate is always present
 | 
			
		||||
 | 
			
		||||
		velo.v_rate = (((frame_data[8] & 0x07 ) << 6) | ((frame_data[9] >> 2) - 1)) * 64;
 | 
			
		||||
 | 
			
		||||
		if((frame_data[8] & 0x8) >> 3) velo.v_rate *= -1; //check v_rate sign
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(velo_type == 1 || velo_type == 2){ //Ground Speed
 | 
			
		||||
		int32_t raw_ew = ((frame_data[5] & 0x03) << 8) | frame_data[6];
 | 
			
		||||
		int32_t velo_ew = raw_ew - 1; //velocities are all offset by one (this is part of the spec)
 | 
			
		||||
 | 
			
		||||
		int32_t raw_ns = ((frame_data[7] & 0x7f) << 3) | (frame_data[8] >> 5);
 | 
			
		||||
		int32_t velo_ns = raw_ns - 1;
 | 
			
		||||
 | 
			
		||||
		if (velo_type == 2){ // supersonic indicator so multiply by 4
 | 
			
		||||
			velo_ew = velo_ew << 2;
 | 
			
		||||
			velo_ns = velo_ns << 2;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if(frame_data[5]&0x04) velo_ew *= -1; //check ew direction sign
 | 
			
		||||
		if(frame_data[7]&0x80) velo_ns *= -1; //check ns direction sign
 | 
			
		||||
 | 
			
		||||
		velo.speed = sqrt(velo_ns*velo_ns + velo_ew*velo_ew);
 | 
			
		||||
		
 | 
			
		||||
		if(velo.speed){
 | 
			
		||||
			//calculate heading in degrees from ew/ns velocities
 | 
			
		||||
			int16_t heading_temp = (int16_t)(atan2(velo_ew,velo_ns) * 180.0 / pi); 
 | 
			
		||||
			// We don't want negative values but a 0-360 scale. 
 | 
			
		||||
			if (heading_temp < 0) heading_temp += 360.0;
 | 
			
		||||
			velo.heading = (uint16_t)heading_temp;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}else if(velo_type == 3 || velo_type == 4){ //Airspeed
 | 
			
		||||
		velo.valid = frame_data[5] & (1<<2);
 | 
			
		||||
		velo.heading = ((((frame_data[5] & 0x03)<<8) | frame_data[6]) * 45) << 7;
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	return velo;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace adsb */
 | 
			
		||||
							
								
								
									
										111
									
								
								Software/portapack-mayhem/firmware/common/adsb.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								Software/portapack-mayhem/firmware/common/adsb.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __ADSB_H__
 | 
			
		||||
#define __ADSB_H__
 | 
			
		||||
 | 
			
		||||
#include "adsb_frame.hpp"
 | 
			
		||||
#include "ui.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace adsb {
 | 
			
		||||
 | 
			
		||||
enum downlink_format {
 | 
			
		||||
	DF_ADSB = 17,
 | 
			
		||||
	DF_EHS_SQUAWK = 21
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum type_code {
 | 
			
		||||
	TC_IDENT = 4,
 | 
			
		||||
	TC_AIRBORNE_POS = 11,
 | 
			
		||||
	TC_AIRBORNE_VELO = 19
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum data_selector {
 | 
			
		||||
	BDS_ID = 0x20,
 | 
			
		||||
	BDS_ID_MARKS = 0x21,
 | 
			
		||||
	BDS_INTENT = 0x40,
 | 
			
		||||
	BDS_HEADING = 0x60
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct adsb_pos {
 | 
			
		||||
	bool valid;
 | 
			
		||||
	float latitude;
 | 
			
		||||
	float longitude;
 | 
			
		||||
	int32_t altitude;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct adsb_vel {
 | 
			
		||||
	bool valid;
 | 
			
		||||
	int32_t speed;  //knot
 | 
			
		||||
	uint16_t heading; //degree
 | 
			
		||||
	int32_t v_rate; //ft/min
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const float CPR_MAX_VALUE = 131072.0;
 | 
			
		||||
 | 
			
		||||
const float adsb_lat_lut[58] = {
 | 
			
		||||
	10.47047130,    14.82817437,    18.18626357,    21.02939493,
 | 
			
		||||
    23.54504487,    25.82924707,    27.93898710,    29.91135686,
 | 
			
		||||
    31.77209708,    33.53993436,    35.22899598,    36.85025108,
 | 
			
		||||
    38.41241892,    39.92256684,    41.38651832,    42.80914012,
 | 
			
		||||
    44.19454951,    45.54626723,    46.86733252,    48.16039128,
 | 
			
		||||
    49.42776439,    50.67150166,    51.89342469,    53.09516153,
 | 
			
		||||
    54.27817472,    55.44378444,    56.59318756,    57.72747354,
 | 
			
		||||
    58.84763776,    59.95459277,    61.04917774,    62.13216659,
 | 
			
		||||
    63.20427479,    64.26616523,    65.31845310,    66.36171008,
 | 
			
		||||
    67.39646774,    68.42322022,    69.44242631,    70.45451075,
 | 
			
		||||
    71.45986473,    72.45884545,    73.45177442,    74.43893416,
 | 
			
		||||
    75.42056257,    76.39684391,    77.36789461,    78.33374083,
 | 
			
		||||
    79.29428225,    80.24923213,    81.19801349,    82.13956981,
 | 
			
		||||
    83.07199445,    83.99173563,    84.89166191,    85.75541621,
 | 
			
		||||
    86.53536998,    87.00000000
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const float PI = 3.14159265358979323846;
 | 
			
		||||
 | 
			
		||||
const float NZ = 15.0;
 | 
			
		||||
 | 
			
		||||
void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address);
 | 
			
		||||
 | 
			
		||||
void encode_frame_id(ADSBFrame& frame, const uint32_t ICAO_address, const std::string& callsign);
 | 
			
		||||
std::string decode_frame_id(ADSBFrame& frame);
 | 
			
		||||
 | 
			
		||||
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
 | 
			
		||||
	const float latitude, const float longitude, const uint32_t time_parity);
 | 
			
		||||
 | 
			
		||||
adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd);
 | 
			
		||||
 | 
			
		||||
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
 | 
			
		||||
	const float angle, const int32_t v_rate);
 | 
			
		||||
 | 
			
		||||
adsb_vel decode_frame_velo(ADSBFrame& frame);
 | 
			
		||||
 | 
			
		||||
//void encode_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code);
 | 
			
		||||
 | 
			
		||||
void encode_frame_squawk(ADSBFrame& frame, const uint32_t squawk);
 | 
			
		||||
 | 
			
		||||
} /* namespace adsb */
 | 
			
		||||
 | 
			
		||||
#endif/*__ADSB_H__*/
 | 
			
		||||
							
								
								
									
										27
									
								
								Software/portapack-mayhem/firmware/common/adsb_frame.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Software/portapack-mayhem/firmware/common/adsb_frame.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2017 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "adsb_frame.hpp"
 | 
			
		||||
 | 
			
		||||
namespace adsb {
 | 
			
		||||
 | 
			
		||||
} /* namespace adsb */
 | 
			
		||||
							
								
								
									
										131
									
								
								Software/portapack-mayhem/firmware/common/adsb_frame.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								Software/portapack-mayhem/firmware/common/adsb_frame.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2017 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
#ifndef __ADSB_FRAME_H__
 | 
			
		||||
#define __ADSB_FRAME_H__
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace adsb {
 | 
			
		||||
 | 
			
		||||
alignas(4) const uint8_t adsb_preamble[16] = { 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 };
 | 
			
		||||
alignas(4) const char icao_id_lut[65] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
 | 
			
		||||
 | 
			
		||||
class ADSBFrame {
 | 
			
		||||
public:
 | 
			
		||||
	uint8_t get_DF() {
 | 
			
		||||
		return (raw_data[0] >> 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t get_msg_type() {
 | 
			
		||||
		return (raw_data[4] >> 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t get_msg_sub() {
 | 
			
		||||
		return (raw_data[4] & 7);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t get_ICAO_address() {
 | 
			
		||||
		return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void set_rx_timestamp(uint32_t timestamp) {
 | 
			
		||||
		rx_timestamp = timestamp;
 | 
			
		||||
	}
 | 
			
		||||
	uint32_t get_rx_timestamp() {
 | 
			
		||||
		return rx_timestamp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void clear() {
 | 
			
		||||
		index = 0;
 | 
			
		||||
		memset(raw_data, 0, 14);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void push_byte(uint8_t byte) {
 | 
			
		||||
		if (index >= 14)
 | 
			
		||||
			return;
 | 
			
		||||
		
 | 
			
		||||
		raw_data[index++] = byte;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t * get_raw_data() const {
 | 
			
		||||
		return (uint8_t* )raw_data;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void make_CRC() {
 | 
			
		||||
		uint32_t computed_CRC = compute_CRC();
 | 
			
		||||
		
 | 
			
		||||
		// Insert CRC in frame
 | 
			
		||||
		raw_data[11] = (computed_CRC >> 16) & 0xFF;
 | 
			
		||||
		raw_data[12] = (computed_CRC >> 8) & 0xFF;
 | 
			
		||||
		raw_data[13] = computed_CRC & 0xFF;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool check_CRC() {
 | 
			
		||||
		uint32_t computed_CRC = compute_CRC();
 | 
			
		||||
		
 | 
			
		||||
		if ((raw_data[11] != ((computed_CRC >> 16) & 0xFF)) ||
 | 
			
		||||
			(raw_data[12] != ((computed_CRC >> 8) & 0xFF)) ||
 | 
			
		||||
			(raw_data[13] != (computed_CRC & 0xFF))) return false;
 | 
			
		||||
		
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	bool empty() {
 | 
			
		||||
		return (index == 0);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	static const uint8_t adsb_preamble[16];
 | 
			
		||||
	static const char icao_id_lut[65];
 | 
			
		||||
	alignas(4) uint8_t index { 0 };
 | 
			
		||||
	alignas(4) uint8_t raw_data[14] { };	// 112 bits at most
 | 
			
		||||
	uint32_t rx_timestamp { };
 | 
			
		||||
 | 
			
		||||
	uint32_t compute_CRC() {
 | 
			
		||||
		uint8_t adsb_crc[14] = { 0 };	// Temp buffer
 | 
			
		||||
		uint8_t b, c, s, bitn;
 | 
			
		||||
		const uint32_t crc_poly = 0x1205FFF;
 | 
			
		||||
		
 | 
			
		||||
		// Copy frame data
 | 
			
		||||
		memcpy(adsb_crc, raw_data, 11);
 | 
			
		||||
		
 | 
			
		||||
		// Compute CRC
 | 
			
		||||
		for (c = 0; c < 11; c++) {
 | 
			
		||||
			for (b = 0; b < 8; b++) {
 | 
			
		||||
				if ((adsb_crc[c] << b) & 0x80) {
 | 
			
		||||
					for (s = 0; s < 25; s++) {
 | 
			
		||||
						bitn = (c * 8) + b + s;
 | 
			
		||||
						if ((crc_poly >> s) & 1) adsb_crc[bitn >> 3] ^= (0x80 >> (bitn & 7));
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return (adsb_crc[11] << 16) + (adsb_crc[12] << 8) + adsb_crc[13];
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace adsb */
 | 
			
		||||
 | 
			
		||||
#endif/*__ADSB_FRAME_H__*/
 | 
			
		||||
							
								
								
									
										22
									
								
								Software/portapack-mayhem/firmware/common/ais_baseband.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Software/portapack-mayhem/firmware/common/ais_baseband.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ais_baseband.hpp"
 | 
			
		||||
							
								
								
									
										47
									
								
								Software/portapack-mayhem/firmware/common/ais_baseband.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Software/portapack-mayhem/firmware/common/ais_baseband.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AIS_BASEBAND_H__
 | 
			
		||||
#define __AIS_BASEBAND_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <complex>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
namespace ais {
 | 
			
		||||
 | 
			
		||||
// Translate+Rectangular window filter
 | 
			
		||||
// sample=38.4k, deviation=2400, symbol=9600
 | 
			
		||||
// Length: 4 taps, 1 symbol, 1/4 cycle of sinusoid
 | 
			
		||||
// Gain: 1.0 (sinusoid / len(taps))
 | 
			
		||||
constexpr std::array<std::complex<float>, 4> square_taps_38k4_1t_p { {
 | 
			
		||||
	{ 0.25000000f, 0.00000000f }, { 0.23096988f, 0.09567086f },
 | 
			
		||||
	{ 0.17677670f, 0.17677670f }, { 0.09567086f, 0.23096988f },
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
} /* namespace ais */
 | 
			
		||||
} /* namespace baseband */
 | 
			
		||||
 | 
			
		||||
#endif/*__AIS_BASEBAND_H__*/
 | 
			
		||||
							
								
								
									
										220
									
								
								Software/portapack-mayhem/firmware/common/ais_packet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								Software/portapack-mayhem/firmware/common/ais_packet.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ais_packet.hpp"
 | 
			
		||||
 | 
			
		||||
#include "crc.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
 | 
			
		||||
namespace ais {
 | 
			
		||||
 | 
			
		||||
struct PacketLengthRange {
 | 
			
		||||
	constexpr PacketLengthRange(
 | 
			
		||||
	) : min_bytes { 0 },
 | 
			
		||||
		max_bytes { 0 }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr PacketLengthRange(
 | 
			
		||||
		const uint16_t min_bits,
 | 
			
		||||
		const uint16_t max_bits
 | 
			
		||||
	) : min_bytes { static_cast<uint8_t>(min_bits / 8U) },
 | 
			
		||||
		max_bytes { static_cast<uint8_t>(max_bits / 8U) }
 | 
			
		||||
	{
 | 
			
		||||
		// static_assert((min_bits & 7) == 0, "minimum bits not a multiple of 8");
 | 
			
		||||
		// static_assert((max_bits & 7) == 0, "minimum bits not a multiple of 8");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr bool contains(const size_t bit_count) const {
 | 
			
		||||
		return !is_above(bit_count) && !is_below(bit_count);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr bool is_above(const size_t bit_count) const {
 | 
			
		||||
		return (min() > bit_count);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr bool is_below(const size_t bit_count) const {
 | 
			
		||||
		return (max() < bit_count);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr size_t min() const {
 | 
			
		||||
		return min_bytes * 8;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	constexpr size_t max() const {
 | 
			
		||||
		return max_bytes * 8;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const uint8_t min_bytes;
 | 
			
		||||
	const uint8_t max_bytes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static constexpr std::array<PacketLengthRange, 64> packet_length_range { {
 | 
			
		||||
	{    0,    0 },	// 0
 | 
			
		||||
	{  168,  168 },	// 1
 | 
			
		||||
	{  168,  168 },	// 2
 | 
			
		||||
	{  168,  168 }, // 3
 | 
			
		||||
	{  168,  168 }, // 4
 | 
			
		||||
	{  424,  424 }, // 5
 | 
			
		||||
	{    0,    0 }, // 6
 | 
			
		||||
	{    0,    0 }, // 7
 | 
			
		||||
	{    0, 1008 }, // 8
 | 
			
		||||
	{    0,    0 }, // 9
 | 
			
		||||
	{    0,    0 }, // 10
 | 
			
		||||
	{    0,    0 }, // 11
 | 
			
		||||
	{    0,    0 }, // 12
 | 
			
		||||
	{    0,    0 }, // 13
 | 
			
		||||
	{    0,    0 }, // 14
 | 
			
		||||
	{    0,    0 }, // 15
 | 
			
		||||
	{    0,    0 }, // 16
 | 
			
		||||
	{    0,    0 }, // 17
 | 
			
		||||
	{  168,  168 }, // 18
 | 
			
		||||
	{    0,    0 }, // 19
 | 
			
		||||
	{   72,  160 }, // 20
 | 
			
		||||
	{  272,  360 }, // 21
 | 
			
		||||
	{  168,  168 }, // 22
 | 
			
		||||
	{  160,  160 }, // 23
 | 
			
		||||
	{  160,  168 }, // 24
 | 
			
		||||
	{    0,  168 }, // 25
 | 
			
		||||
	{    0,    0 }, // 26
 | 
			
		||||
	{    0,    0 }, // 27
 | 
			
		||||
	{    0,    0 }, // 28
 | 
			
		||||
	{    0,    0 }, // 29
 | 
			
		||||
	{    0,    0 }, // 30
 | 
			
		||||
	{    0,    0 }, // 31
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
struct PacketLengthValidator {
 | 
			
		||||
	constexpr bool operator()(const uint_fast8_t message_id, const size_t length) const {
 | 
			
		||||
		return packet_length_range[message_id].contains(length);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PacketTooLong {
 | 
			
		||||
	constexpr bool operator()(const uint_fast8_t message_id, const size_t length) const {
 | 
			
		||||
		return packet_length_range[message_id].is_below(length);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static constexpr char char_to_ascii(const uint8_t c) {
 | 
			
		||||
	return (c ^ 32) + 32;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Packet::length() const {
 | 
			
		||||
	return packet_.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::is_valid() const {
 | 
			
		||||
	return length_valid() && crc_ok();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Timestamp Packet::received_at() const {
 | 
			
		||||
	return packet_.timestamp();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t Packet::message_id() const {
 | 
			
		||||
	return field_.read(0, 6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MMSI Packet::user_id() const {
 | 
			
		||||
	return field_.read(8, 30);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MMSI Packet::source_id() const {
 | 
			
		||||
	return field_.read(8, 30);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t Packet::read(const size_t start_bit, const size_t length) const {
 | 
			
		||||
	return field_.read(start_bit, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string Packet::text(
 | 
			
		||||
	const size_t start_bit,
 | 
			
		||||
	const size_t character_count
 | 
			
		||||
) const {
 | 
			
		||||
	std::string result;
 | 
			
		||||
	result.reserve(character_count);
 | 
			
		||||
	
 | 
			
		||||
	const size_t character_length = 6;
 | 
			
		||||
	const size_t end_bit = start_bit + character_count * character_length;
 | 
			
		||||
	for(size_t i=start_bit; i<end_bit; i+=character_length) {
 | 
			
		||||
		result += char_to_ascii(field_.read(i, character_length));
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DateTime Packet::datetime(const size_t start_bit) const {
 | 
			
		||||
	return {
 | 
			
		||||
		static_cast<uint16_t>(field_.read(start_bit +  0, 14)),
 | 
			
		||||
		static_cast<uint8_t >(field_.read(start_bit + 14,  4)),
 | 
			
		||||
		static_cast<uint8_t >(field_.read(start_bit + 18,  5)),
 | 
			
		||||
		static_cast<uint8_t >(field_.read(start_bit + 23,  5)),
 | 
			
		||||
		static_cast<uint8_t >(field_.read(start_bit + 28,  6)),
 | 
			
		||||
		static_cast<uint8_t >(field_.read(start_bit + 34,  6)),
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Latitude Packet::latitude(const size_t start_bit) const {
 | 
			
		||||
	return field_.read(start_bit, 27);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Longitude Packet::longitude(const size_t start_bit) const {
 | 
			
		||||
	return field_.read(start_bit, 28);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::crc_ok() const {
 | 
			
		||||
	CRCReader field_crc { packet_ };
 | 
			
		||||
	CRC<16> ais_fcs { 0x1021, 0xffff, 0xffff };
 | 
			
		||||
	
 | 
			
		||||
	for(size_t i=0; i<data_length(); i+=8) {
 | 
			
		||||
		ais_fcs.process_byte(field_crc.read(i, 8));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (ais_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Packet::data_and_fcs_length() const {
 | 
			
		||||
	// Subtract end flag (8 bits) - one unstuffing bit (occurs during end flag).
 | 
			
		||||
	return length() - 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Packet::data_length() const {
 | 
			
		||||
	return data_and_fcs_length() - fcs_length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::length_valid() const {
 | 
			
		||||
	const size_t extra_bits = data_and_fcs_length() & 7;
 | 
			
		||||
	if( extra_bits != 0 ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const PacketLengthValidator packet_length_valid;
 | 
			
		||||
	if( !packet_length_valid(message_id(), data_length()) ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace ais */
 | 
			
		||||
							
								
								
									
										148
									
								
								Software/portapack-mayhem/firmware/common/ais_packet.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								Software/portapack-mayhem/firmware/common/ais_packet.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AIS_PACKET_H__
 | 
			
		||||
#define __AIS_PACKET_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
#include "field_reader.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ais {
 | 
			
		||||
 | 
			
		||||
struct DateTime {
 | 
			
		||||
	uint16_t year;
 | 
			
		||||
	uint8_t month;
 | 
			
		||||
	uint8_t day;
 | 
			
		||||
	uint8_t hour;
 | 
			
		||||
	uint8_t minute;
 | 
			
		||||
	uint8_t second;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<size_t FieldSize, int32_t DegMax, uint32_t NAValue>
 | 
			
		||||
struct LatLonBase {
 | 
			
		||||
	
 | 
			
		||||
	constexpr LatLonBase(
 | 
			
		||||
	) : LatLonBase { raw_not_available }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	constexpr LatLonBase(
 | 
			
		||||
		const int32_t raw
 | 
			
		||||
	) : raw_ { raw }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr LatLonBase(
 | 
			
		||||
		const LatLonBase& other
 | 
			
		||||
	) : raw_ { other.raw_ }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	LatLonBase& operator=( const LatLonBase &)=default;
 | 
			
		||||
 | 
			
		||||
	int32_t normalized() const {
 | 
			
		||||
		return static_cast<int32_t>(raw() << sign_extend_shift) / (1 << sign_extend_shift);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int32_t raw() const {
 | 
			
		||||
		return raw_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_not_available() const {
 | 
			
		||||
		return raw() == raw_not_available;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_valid() const {
 | 
			
		||||
		return (normalized() >= raw_valid_min) && (normalized() <= raw_valid_max);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	int32_t raw_;
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t sign_extend_shift = 32 - FieldSize;
 | 
			
		||||
 | 
			
		||||
	static constexpr int32_t raw_not_available = NAValue;
 | 
			
		||||
	static constexpr int32_t raw_valid_min = -DegMax * 60 * 10000;
 | 
			
		||||
	static constexpr int32_t raw_valid_max =  DegMax * 60 * 10000;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using Latitude = LatLonBase<27, 90, 0x3412140>;
 | 
			
		||||
using Longitude = LatLonBase<28, 180, 0x6791AC0>;
 | 
			
		||||
 | 
			
		||||
using RateOfTurn = int8_t;
 | 
			
		||||
using SpeedOverGround = uint16_t;
 | 
			
		||||
using CourseOverGround = uint16_t;
 | 
			
		||||
using TrueHeading = uint16_t;
 | 
			
		||||
 | 
			
		||||
using MMSI = uint32_t;
 | 
			
		||||
 | 
			
		||||
class Packet {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr Packet(
 | 
			
		||||
		const baseband::Packet& packet
 | 
			
		||||
	) : packet_ { packet },
 | 
			
		||||
		field_ { packet_ }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t length() const;
 | 
			
		||||
	
 | 
			
		||||
	bool is_valid() const;
 | 
			
		||||
 | 
			
		||||
	Timestamp received_at() const;
 | 
			
		||||
 | 
			
		||||
	uint32_t message_id() const;
 | 
			
		||||
	MMSI user_id() const;
 | 
			
		||||
	MMSI source_id() const;
 | 
			
		||||
 | 
			
		||||
	uint32_t read(const size_t start_bit, const size_t length) const;
 | 
			
		||||
 | 
			
		||||
	std::string text(const size_t start_bit, const size_t character_count) const;
 | 
			
		||||
 | 
			
		||||
	DateTime datetime(const size_t start_bit) const;
 | 
			
		||||
 | 
			
		||||
	Latitude latitude(const size_t start_bit) const;
 | 
			
		||||
	Longitude longitude(const size_t start_bit) const;
 | 
			
		||||
 | 
			
		||||
	bool crc_ok() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
 | 
			
		||||
	using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
 | 
			
		||||
	
 | 
			
		||||
	const baseband::Packet packet_;
 | 
			
		||||
	const Reader field_;
 | 
			
		||||
 | 
			
		||||
	const size_t fcs_length = 16;
 | 
			
		||||
 | 
			
		||||
	size_t data_and_fcs_length() const;
 | 
			
		||||
	size_t data_length() const;
 | 
			
		||||
 | 
			
		||||
	bool length_valid() const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace ais */
 | 
			
		||||
 | 
			
		||||
#endif/*__AIS_PACKET_H__*/
 | 
			
		||||
							
								
								
									
										323
									
								
								Software/portapack-mayhem/firmware/common/ak4951.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								Software/portapack-mayhem/firmware/common/ak4951.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,323 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ak4951.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_io.hpp"
 | 
			
		||||
using namespace portapack;
 | 
			
		||||
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
 | 
			
		||||
namespace asahi_kasei {
 | 
			
		||||
namespace ak4951 {
 | 
			
		||||
 | 
			
		||||
void AK4951::configure_digital_interface_i2s() {
 | 
			
		||||
	// Configure for external slave mode.
 | 
			
		||||
	map.r.mode_control_1.DIF = 0b11;	// I2S compatible
 | 
			
		||||
	map.r.mode_control_1.BCKO = 0;		// BICK = 32fs
 | 
			
		||||
	update(Register::ModeControl1);
 | 
			
		||||
 | 
			
		||||
	map.r.mode_control_2.CM = 0b00;		// MCKI = 256fs
 | 
			
		||||
	map.r.mode_control_2.FS = 0b1011;	// fs = 48kHz
 | 
			
		||||
	update(Register::ModeControl2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::configure_digital_interface_external_slave() {
 | 
			
		||||
	map.r.power_management_2.MS = 0;	// Slave mode
 | 
			
		||||
	map.r.power_management_2.PMPLL = 0;	// EXT mode
 | 
			
		||||
	update(Register::PowerManagement2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::configure_digital_interface_external_master() {
 | 
			
		||||
	map.r.power_management_2.MS = 1;	// Master mode
 | 
			
		||||
	map.r.power_management_2.PMPLL = 0;	// EXT mode
 | 
			
		||||
	update(Register::PowerManagement2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::init() {
 | 
			
		||||
	reset();
 | 
			
		||||
 | 
			
		||||
	// Write dummy address to "release" the reset.
 | 
			
		||||
	write(0x00, 0x00);
 | 
			
		||||
 | 
			
		||||
	configure_digital_interface_i2s();
 | 
			
		||||
	configure_digital_interface_external_slave();
 | 
			
		||||
 | 
			
		||||
	map.r.power_management_1.PMVCM = 1;
 | 
			
		||||
	update(Register::PowerManagement1);
 | 
			
		||||
 | 
			
		||||
	// Headphone output is hi-Z when not active, reduces crosstalk from speaker output.
 | 
			
		||||
	map.r.beep_control.HPZ = 1;
 | 
			
		||||
	update(Register::BeepControl);
 | 
			
		||||
 | 
			
		||||
	// Pause for VCOM and REGFIL pins to stabilize.
 | 
			
		||||
	chThdSleepMilliseconds(2);
 | 
			
		||||
 | 
			
		||||
	headphone_mute();
 | 
			
		||||
 | 
			
		||||
	// SPK-Amp gain setting: SPKG1-0 bits = “00” → “01”
 | 
			
		||||
	map.r.signal_select_2.SPKG = 0b01;
 | 
			
		||||
	update(Register::SignalSelect2);
 | 
			
		||||
 | 
			
		||||
	map.r.signal_select_3.MONO = 0b00;
 | 
			
		||||
	update(Register::SignalSelect3);
 | 
			
		||||
 | 
			
		||||
	map.r.digital_filter_mode.PFSDO = 0;	// ADC bypass digital filter block.
 | 
			
		||||
	map.r.digital_filter_mode.ADCPF = 1;	// ADC output
 | 
			
		||||
	map.r.digital_filter_mode.PFDAC = 0b00;	// SDTI
 | 
			
		||||
	update(Register::DigitalFilterMode);
 | 
			
		||||
 | 
			
		||||
	// Set up FRN, FRATT and ADRST1-0 bits (Addr = 09H)
 | 
			
		||||
	// map.r.timer_select.FRN = 0;
 | 
			
		||||
	// map.r.timer_select.FRATT = 0;
 | 
			
		||||
	// map.r.timer_select.ADRST = 0b00;
 | 
			
		||||
	// update(Register::TimerSelect);
 | 
			
		||||
 | 
			
		||||
	// Set up ALC mode (Addr = 0AH, 0BH)
 | 
			
		||||
	// map.r.alc_timer_select. = ;
 | 
			
		||||
	// update(Register::ALCTimerSelect);
 | 
			
		||||
	// map.r.alc_mode_control_1. = ;
 | 
			
		||||
	// update(Register::ALCModeControl1);
 | 
			
		||||
 | 
			
		||||
	// Set up REF value of ALC (Addr = 0CH)
 | 
			
		||||
	// map.r.alc_mode_control_2. = ;
 | 
			
		||||
	// update(Register::ALCModeControl2);
 | 
			
		||||
 | 
			
		||||
	// Set up IVOL value of ALC operation start (Addr = 0DH)
 | 
			
		||||
	// map.r.l_ch_input_volume_control. = ;
 | 
			
		||||
	// update(Register::LchInputVolumeControl);
 | 
			
		||||
	// map.r.r_ch_input_volume_control. = ;
 | 
			
		||||
	// update(Register::RchInputVolumeControl);
 | 
			
		||||
 | 
			
		||||
	// Set up the output digital volume. (Addr = 13H)
 | 
			
		||||
	// set_headphone_volume(...);
 | 
			
		||||
 | 
			
		||||
	// Set up Programmable Filter Path: PFDAC1-0 bits=“01”, PFSDO=ADCPF bits=“0” (Addr = 1DH)
 | 
			
		||||
	// map.r.digital_filter_mode.PFDAC = 0b01;
 | 
			
		||||
	// update(Register::DigitalFilterMode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AK4951::detected() {
 | 
			
		||||
	return reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AK4951::reset() {
 | 
			
		||||
	io.audio_reset_state(true);
 | 
			
		||||
 | 
			
		||||
	// PDN# pulse must be >200ns
 | 
			
		||||
	chThdSleepMicroseconds(10);
 | 
			
		||||
 | 
			
		||||
	io.audio_reset_state(false);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::set_digtal_volume_control(const reg_t value) {
 | 
			
		||||
	map.r.l_ch_digital_volume_control.DV = value;
 | 
			
		||||
	update(Register::LchDigitalVolumeControl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::set_headphone_volume(const volume_t volume) {
 | 
			
		||||
	const auto normalized = headphone_gain_range().normalize(volume);
 | 
			
		||||
	auto n = normalized.centibel() / 5;
 | 
			
		||||
	set_digtal_volume_control(0xcb - n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::headphone_mute() {
 | 
			
		||||
	set_digtal_volume_control(0xff);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::set_dac_power(const bool enable) {
 | 
			
		||||
	map.r.power_management_1.PMDAC = enable;
 | 
			
		||||
	update(Register::PowerManagement1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::set_headphone_power(const bool enable) {
 | 
			
		||||
	map.r.power_management_2.PMHPL = map.r.power_management_2.PMHPR = enable;
 | 
			
		||||
	update(Register::PowerManagement2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::set_speaker_power(const bool enable) {
 | 
			
		||||
	map.r.power_management_2.PMSL = enable;
 | 
			
		||||
	update(Register::PowerManagement2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::select_line_out(const LineOutSelect value) {
 | 
			
		||||
	map.r.power_management_2.LOSEL = (value == LineOutSelect::Line) ? 1 : 0;
 | 
			
		||||
	update(Register::PowerManagement2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::headphone_enable() {
 | 
			
		||||
	set_dac_power(true);
 | 
			
		||||
	set_headphone_power(true);
 | 
			
		||||
 | 
			
		||||
	// Wait for headphone amplifier charge pump power-up.
 | 
			
		||||
	chThdSleepMilliseconds(35);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::headphone_disable() {
 | 
			
		||||
	set_headphone_power(false);
 | 
			
		||||
	set_dac_power(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::speaker_enable() {
 | 
			
		||||
	// Set up the path of DAC → SPK-Amp: DACS bit = “0” → “1”
 | 
			
		||||
	map.r.signal_select_1.DACS = 1;
 | 
			
		||||
	update(Register::SignalSelect1);
 | 
			
		||||
 | 
			
		||||
	// Enter Speaker-Amp Output Mode: LOSEL bit = “0”
 | 
			
		||||
	select_line_out(LineOutSelect::Speaker);
 | 
			
		||||
 | 
			
		||||
	// Power up DAC, Programmable Filter and Speaker-Amp: PMDAC=PMPFIL=PMSL bits=“0”→“1”
 | 
			
		||||
	set_dac_power(true);
 | 
			
		||||
	// map.r.power_management_1.PMPFIL = 1;
 | 
			
		||||
	// update(Register::PowerManagement1);
 | 
			
		||||
	set_speaker_power(true);
 | 
			
		||||
 | 
			
		||||
	// Time from PMSL=1 to SLPSN=1.
 | 
			
		||||
	chThdSleepMilliseconds(1);
 | 
			
		||||
 | 
			
		||||
	// Exit the power-save mode of Speaker-Amp: SLPSN bit = “0” → “1”
 | 
			
		||||
	map.r.signal_select_1.SLPSN = 1;
 | 
			
		||||
	update(Register::SignalSelect1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::speaker_disable() {
 | 
			
		||||
	// Enter Speaker-Amp Power Save Mode: SLPSN bit = “1” → “0”
 | 
			
		||||
	map.r.signal_select_1.SLPSN = 0;
 | 
			
		||||
	update(Register::SignalSelect1);
 | 
			
		||||
 | 
			
		||||
	// Disable the path of DAC → SPK-Amp: DACS bit = “1” → “0”
 | 
			
		||||
	map.r.signal_select_1.DACS = 0;
 | 
			
		||||
	update(Register::SignalSelect1);
 | 
			
		||||
 | 
			
		||||
	// Power down DAC, Programmable Filter and speaker: PMDAC=PMPFIL=PMSL bits= “1”→“0”
 | 
			
		||||
	set_dac_power(false);
 | 
			
		||||
	// map.r.power_management_1.PMPFIL = 0;
 | 
			
		||||
	// update(Register::PowerManagement1);
 | 
			
		||||
	set_speaker_power(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::microphone_enable() {
 | 
			
		||||
// map.r.digital_mic.DMIC = 0;
 | 
			
		||||
// update(Register::DigitalMic);
 | 
			
		||||
	
 | 
			
		||||
	const uint_fast8_t mgain = 0b0111;
 | 
			
		||||
	map.r.signal_select_1.MGAIN20 = mgain & 7;
 | 
			
		||||
	map.r.signal_select_1.PMMP = 1;
 | 
			
		||||
	map.r.signal_select_1.MPSEL = 1;	// MPWR2 pin
 | 
			
		||||
	map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1;
 | 
			
		||||
	update(Register::SignalSelect1);
 | 
			
		||||
 | 
			
		||||
	map.r.signal_select_2.INL = 0b01;	// Lch input signal = LIN2
 | 
			
		||||
	map.r.signal_select_2.INR = 0b01;	// Rch input signal = RIN2
 | 
			
		||||
	map.r.signal_select_2.MICL = 0;		// MPWR = 2.4V
 | 
			
		||||
	update(Register::SignalSelect2);
 | 
			
		||||
 | 
			
		||||
// map.r.r_ch_mic_gain_setting.MGR = 0x80;	// Microphone sensitivity correction = 0dB.
 | 
			
		||||
// update(Register::RchMicGainSetting);
 | 
			
		||||
/*
 | 
			
		||||
	map.r.timer_select.FRN = ?;
 | 
			
		||||
	map.r.timer_select.FRATT = ?;
 | 
			
		||||
	map.r.timer_select.ADRST = 0b??;
 | 
			
		||||
	update(Register::TimerSelect);
 | 
			
		||||
 | 
			
		||||
	map.r.alc_timer_select. = ?;
 | 
			
		||||
	update(Register::ALCTimerSelect);
 | 
			
		||||
	map.r.alc_mode_control_1. = ?;
 | 
			
		||||
	map.r.alc_mode_control_1.ALC = 1;
 | 
			
		||||
	update(Register::ALCModeControl1);
 | 
			
		||||
 | 
			
		||||
	map.r.alc_mode_control_2.REF = ?;
 | 
			
		||||
	update(Register::ALCModeControl2);
 | 
			
		||||
*/
 | 
			
		||||
// map.r.l_ch_input_volume_control.IV = 0xe1;
 | 
			
		||||
// update(Register::LchInputVolumeControl);
 | 
			
		||||
// map.r.r_ch_input_volume_control.IV = 0xe1;
 | 
			
		||||
// update(Register::RchInputVolumeControl);
 | 
			
		||||
/*
 | 
			
		||||
	map.r.auto_hpf_control.STG = 0b00;
 | 
			
		||||
	map.r.auto_hpf_control.SENC = 0b011;
 | 
			
		||||
	map.r.auto_hpf_control.AHPF = 0;
 | 
			
		||||
	update(Register::AutoHPFControl);
 | 
			
		||||
*/
 | 
			
		||||
	map.r.digital_filter_select_1.HPFAD = 1;	// HPF1 (after ADC) = on
 | 
			
		||||
	map.r.digital_filter_select_1.HPFC = 0b11;	// 2336.8 Hz @ fs=48k
 | 
			
		||||
	update(Register::DigitalFilterSelect1);
 | 
			
		||||
/*
 | 
			
		||||
	map.r.digital_filter_select_2.HPF = 0;
 | 
			
		||||
	map.r.digital_filter_select_2.LPF = 0;
 | 
			
		||||
	map.r.digital_filter_select_2.FIL3 = 0;
 | 
			
		||||
	map.r.digital_filter_select_2.EQ0 = 0;
 | 
			
		||||
	map.r.digital_filter_select_2.GN = 0b00;
 | 
			
		||||
	update(Register::DigitalFilterSelect2);
 | 
			
		||||
 | 
			
		||||
	map.r.digital_filter_select_3.EQ1 = 0;
 | 
			
		||||
	map.r.digital_filter_select_3.EQ2 = 0;
 | 
			
		||||
	map.r.digital_filter_select_3.EQ3 = 0;
 | 
			
		||||
	map.r.digital_filter_select_3.EQ4 = 0;
 | 
			
		||||
	map.r.digital_filter_select_3.EQ5 = 0;
 | 
			
		||||
	update(Register::DigitalFilterSelect3);
 | 
			
		||||
*/
 | 
			
		||||
	map.r.digital_filter_mode.PFSDO = 0;	// ADC (+ 1st order HPF) Output
 | 
			
		||||
	map.r.digital_filter_mode.ADCPF = 1;	// ADC Output (default)
 | 
			
		||||
	update(Register::DigitalFilterMode);
 | 
			
		||||
 | 
			
		||||
	// ... Set coefficients ...
 | 
			
		||||
 | 
			
		||||
	map.r.power_management_1.PMADL = 1;		// ADC Lch = Lch input signal
 | 
			
		||||
	map.r.power_management_1.PMADR = 1;		// ADC Rch = Rch input signal
 | 
			
		||||
	map.r.power_management_1.PMPFIL = 0;	// Programmable filter unused, routed around.
 | 
			
		||||
	update(Register::PowerManagement1);
 | 
			
		||||
 | 
			
		||||
	// 1059/fs, 22ms @ 48kHz
 | 
			
		||||
	chThdSleepMilliseconds(22);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::microphone_disable() {
 | 
			
		||||
	map.r.power_management_1.PMADL = 0;
 | 
			
		||||
	map.r.power_management_1.PMADR = 0;
 | 
			
		||||
	map.r.power_management_1.PMPFIL = 0;
 | 
			
		||||
	update(Register::PowerManagement1);
 | 
			
		||||
 | 
			
		||||
	map.r.alc_mode_control_1.ALC = 0;
 | 
			
		||||
	update(Register::ALCModeControl1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
reg_t AK4951::read(const address_t reg_address) {
 | 
			
		||||
	const std::array<uint8_t, 1> tx { reg_address };
 | 
			
		||||
	std::array<uint8_t, 1> rx { 0x00 };
 | 
			
		||||
	bus.transmit(bus_address, tx.data(), tx.size());
 | 
			
		||||
	bus.receive(bus_address, rx.data(), rx.size());
 | 
			
		||||
	return rx[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::update(const Register reg) {
 | 
			
		||||
	write(toUType(reg), map.w[toUType(reg)]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AK4951::write(const address_t reg_address, const reg_t value) {
 | 
			
		||||
	const std::array<uint8_t, 2> tx { reg_address, value };
 | 
			
		||||
	bus.transmit(bus_address, tx.data(), tx.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace ak4951 */
 | 
			
		||||
} /* namespace asahi_kasei */
 | 
			
		||||
							
								
								
									
										886
									
								
								Software/portapack-mayhem/firmware/common/ak4951.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										886
									
								
								Software/portapack-mayhem/firmware/common/ak4951.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,886 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AK4951_H__
 | 
			
		||||
#define __AK4951_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include "i2c_pp.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio.hpp"
 | 
			
		||||
 | 
			
		||||
namespace asahi_kasei {
 | 
			
		||||
namespace ak4951 {
 | 
			
		||||
 | 
			
		||||
using address_t = uint8_t;
 | 
			
		||||
using reg_t = uint8_t;
 | 
			
		||||
 | 
			
		||||
constexpr size_t reg_count = 0x50;
 | 
			
		||||
 | 
			
		||||
enum class Register : address_t {
 | 
			
		||||
	PowerManagement1 = 0x00,
 | 
			
		||||
	PowerManagement2 = 0x01,
 | 
			
		||||
	SignalSelect1 = 0x02,
 | 
			
		||||
	SignalSelect2 = 0x03,
 | 
			
		||||
	SignalSelect3 = 0x04,
 | 
			
		||||
	ModeControl1 = 0x05,
 | 
			
		||||
	ModeControl2 = 0x06,
 | 
			
		||||
	ModeControl3 = 0x07,
 | 
			
		||||
	DigitalMic = 0x08,
 | 
			
		||||
	TimerSelect = 0x09,
 | 
			
		||||
	ALCTimerSelect = 0x0a,
 | 
			
		||||
	ALCModeControl1 = 0x0b,
 | 
			
		||||
	ALCModeControl2 = 0x0c,
 | 
			
		||||
	LchInputVolumeControl = 0x0d,
 | 
			
		||||
	RchInputVolumeControl = 0x0e,
 | 
			
		||||
	ALCVolume = 0x0f,
 | 
			
		||||
	_Reserved_0x10 = 0x10,
 | 
			
		||||
	RchMicGainSetting = 0x11,
 | 
			
		||||
	BeepControl = 0x12,
 | 
			
		||||
	LchDigitalVolumeControl = 0x13,
 | 
			
		||||
	RchDigitalVolumeControl = 0x14,
 | 
			
		||||
	EQCommonGainSelect = 0x15,
 | 
			
		||||
	EQ2CommonGainSetting = 0x16,
 | 
			
		||||
	EQ3CommonGainSetting = 0x17,
 | 
			
		||||
	EQ4CommonGainSetting = 0x18,
 | 
			
		||||
	EQ5CommonGainSetting = 0x19,
 | 
			
		||||
	AutoHPFControl = 0x1a,
 | 
			
		||||
	DigitalFilterSelect1 = 0x1b,
 | 
			
		||||
	DigitalFilterSelect2 = 0x1c,
 | 
			
		||||
	DigitalFilterMode = 0x1d,
 | 
			
		||||
	HPF2Coefficient0 = 0x1e,
 | 
			
		||||
	HPF2Coefficient1 = 0x1f,
 | 
			
		||||
	HPF2Coefficient2 = 0x20,
 | 
			
		||||
	HPF2Coefficient3 = 0x21,
 | 
			
		||||
	LPFCoefficient0 = 0x22,
 | 
			
		||||
	LPFCoefficient1 = 0x23,
 | 
			
		||||
	LPFCoefficient2 = 0x24,
 | 
			
		||||
	LPFCoefficient3 = 0x25,
 | 
			
		||||
	FIL3Coefficient0 = 0x26,
 | 
			
		||||
	FIL3Coefficient1 = 0x27,
 | 
			
		||||
	FIL3Coefficient2 = 0x28,
 | 
			
		||||
	FIL3Coefficient3 = 0x29,
 | 
			
		||||
	EQCoefficient0 = 0x2a,
 | 
			
		||||
	EQCoefficient1 = 0x2b,
 | 
			
		||||
	EQCoefficient2 = 0x2c,
 | 
			
		||||
	EQCoefficient3 = 0x2d,
 | 
			
		||||
	EQCoefficient4 = 0x2e,
 | 
			
		||||
	EQCoefficient5 = 0x2f,
 | 
			
		||||
	DigitalFilterSelect3 = 0x30,
 | 
			
		||||
	DeviceInformation = 0x31,
 | 
			
		||||
	E1Coefficient0 = 0x32,
 | 
			
		||||
	E1Coefficient1 = 0x33,
 | 
			
		||||
	E1Coefficient2 = 0x34,
 | 
			
		||||
	E1Coefficient3 = 0x35,
 | 
			
		||||
	E1Coefficient4 = 0x36,
 | 
			
		||||
	E1Coefficient5 = 0x37,
 | 
			
		||||
	E2Coefficient0 = 0x38,
 | 
			
		||||
	E2Coefficient1 = 0x39,
 | 
			
		||||
	E2Coefficient2 = 0x3a,
 | 
			
		||||
	E2Coefficient3 = 0x3b,
 | 
			
		||||
	E2Coefficient4 = 0x3c,
 | 
			
		||||
	E2Coefficient5 = 0x3d,
 | 
			
		||||
	E3Coefficient0 = 0x3e,
 | 
			
		||||
	E3Coefficient1 = 0x3f,
 | 
			
		||||
	E3Coefficient2 = 0x40,
 | 
			
		||||
	E3Coefficient3 = 0x41,
 | 
			
		||||
	E3Coefficient4 = 0x42,
 | 
			
		||||
	E3Coefficient5 = 0x43,
 | 
			
		||||
	E4Coefficient0 = 0x44,
 | 
			
		||||
	E4Coefficient1 = 0x45,
 | 
			
		||||
	E4Coefficient2 = 0x46,
 | 
			
		||||
	E4Coefficient3 = 0x47,
 | 
			
		||||
	E4Coefficient4 = 0x48,
 | 
			
		||||
	E4Coefficient5 = 0x49,
 | 
			
		||||
	E5Coefficient0 = 0x4a,
 | 
			
		||||
	E5Coefficient1 = 0x4b,
 | 
			
		||||
	E5Coefficient2 = 0x4c,
 | 
			
		||||
	E5Coefficient3 = 0x4d,
 | 
			
		||||
	E5Coefficient4 = 0x4e,
 | 
			
		||||
	E5Coefficient5 = 0x4f,
 | 
			
		||||
	_count,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(toUType(Register::_count) == reg_count, "Register::_count != reg_count");
 | 
			
		||||
 | 
			
		||||
struct PowerManagement1 {
 | 
			
		||||
	reg_t PMADL     : 1;
 | 
			
		||||
	reg_t PMADR     : 1;
 | 
			
		||||
	reg_t PMDAC     : 1;
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
	reg_t PMBP      : 1;
 | 
			
		||||
	reg_t PMVCM     : 1;
 | 
			
		||||
	reg_t PMPFIL    : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(PowerManagement1) == sizeof(reg_t), "wrong size `struct");
 | 
			
		||||
 | 
			
		||||
struct PowerManagement2 {
 | 
			
		||||
	reg_t LOSEL     : 1;
 | 
			
		||||
	reg_t PMSL      : 1;
 | 
			
		||||
	reg_t PMPLL     : 1;
 | 
			
		||||
	reg_t MS        : 1;
 | 
			
		||||
	reg_t PMHPL     : 1;
 | 
			
		||||
	reg_t PMHPR     : 1;
 | 
			
		||||
	reg_t reserved0 : 1;
 | 
			
		||||
	reg_t PMOSC     : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(PowerManagement2) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct SignalSelect1 {
 | 
			
		||||
	reg_t MGAIN20   : 3;
 | 
			
		||||
	reg_t PMMP      : 1;
 | 
			
		||||
	reg_t MPSEL     : 1;
 | 
			
		||||
	reg_t DACS      : 1;
 | 
			
		||||
	reg_t MGAIN3    : 1;
 | 
			
		||||
	reg_t SLPSN     : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(SignalSelect1) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct SignalSelect2 {
 | 
			
		||||
	reg_t INR       : 2;
 | 
			
		||||
	reg_t INL       : 2;
 | 
			
		||||
	reg_t MICL      : 1;
 | 
			
		||||
	reg_t reserved0 : 1;
 | 
			
		||||
	reg_t SPKG      : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(SignalSelect2) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct SignalSelect3 {
 | 
			
		||||
	reg_t MONO      : 2;
 | 
			
		||||
	reg_t PTS       : 2;
 | 
			
		||||
	reg_t reserved0 : 1;
 | 
			
		||||
	reg_t DACL      : 1;
 | 
			
		||||
	reg_t LVCM      : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(SignalSelect3) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct ModeControl1 {
 | 
			
		||||
	reg_t DIF       : 2;
 | 
			
		||||
	reg_t CKOFF     : 1;
 | 
			
		||||
	reg_t BCKO      : 1;
 | 
			
		||||
	reg_t PLL       : 4;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(ModeControl1) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct ModeControl2 {
 | 
			
		||||
	reg_t FS        : 4;
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
	reg_t CM        : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(ModeControl2) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct ModeControl3 {
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
	reg_t IVOLC     : 1;
 | 
			
		||||
	reg_t reserved1 : 1;
 | 
			
		||||
	reg_t DVOLC     : 1;
 | 
			
		||||
	reg_t SMUTE     : 1;
 | 
			
		||||
	reg_t THDET     : 1;
 | 
			
		||||
	reg_t TSDSEL    : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(ModeControl3) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct DigitalMIC {
 | 
			
		||||
	reg_t DMIC      : 1;
 | 
			
		||||
	reg_t DCLKP     : 1;
 | 
			
		||||
	reg_t reserved0 : 1;
 | 
			
		||||
	reg_t DCLKE     : 1;
 | 
			
		||||
	reg_t PMDML     : 1;
 | 
			
		||||
	reg_t PMDMR     : 1;
 | 
			
		||||
	reg_t reserved1 : 1;
 | 
			
		||||
	reg_t READ      : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(DigitalMIC) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct TimerSelect {
 | 
			
		||||
	reg_t DVTM      : 1;
 | 
			
		||||
	reg_t MOFF      : 1;
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
	reg_t FRN       : 1;
 | 
			
		||||
	reg_t FRATT     : 1;
 | 
			
		||||
	reg_t ADRST     : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(TimerSelect) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct ALCTimerSelect {
 | 
			
		||||
	reg_t RFST      : 2;
 | 
			
		||||
	reg_t WTM       : 2;
 | 
			
		||||
	reg_t EQFC      : 2;
 | 
			
		||||
	reg_t IVTM      : 1;
 | 
			
		||||
	reg_t reserved0 : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(ALCTimerSelect) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct ALCModeControl1 {
 | 
			
		||||
	reg_t LMTH10    : 2;
 | 
			
		||||
	reg_t RGAIN     : 3;
 | 
			
		||||
	reg_t ALC       : 1;
 | 
			
		||||
	reg_t LMTH2     : 1;
 | 
			
		||||
	reg_t ALCEQN    : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(ALCModeControl1) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct ALCModeControl2 {
 | 
			
		||||
	reg_t REF       : 8;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(ALCModeControl2) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct InputVolumeControl {
 | 
			
		||||
	reg_t IV        : 8;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(InputVolumeControl) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
using LchInputVolumeControl = InputVolumeControl;
 | 
			
		||||
using RchInputVolumeControl = InputVolumeControl;
 | 
			
		||||
 | 
			
		||||
struct ALCVolume {
 | 
			
		||||
	reg_t VOL       : 8;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(ALCVolume) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct RchMICGainSetting {
 | 
			
		||||
	reg_t MGR       : 8;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(RchMICGainSetting) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct BeepControl {
 | 
			
		||||
	reg_t BPLVL     : 4;
 | 
			
		||||
	reg_t BEEPH     : 1;
 | 
			
		||||
	reg_t BEEPS     : 1;
 | 
			
		||||
	reg_t BPVCM     : 1;
 | 
			
		||||
	reg_t HPZ       : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(BeepControl) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct DigitalVolumeControl {
 | 
			
		||||
	reg_t DV        : 8;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(DigitalVolumeControl) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
using LchDigitalVolumeControl = DigitalVolumeControl;
 | 
			
		||||
using RchDigitalVolumeControl = DigitalVolumeControl;
 | 
			
		||||
 | 
			
		||||
struct EQCommonGainSelect {
 | 
			
		||||
	reg_t reserved0 : 1;
 | 
			
		||||
	reg_t EQC2      : 1;
 | 
			
		||||
	reg_t EQC3      : 1;
 | 
			
		||||
	reg_t EQC4      : 1;
 | 
			
		||||
	reg_t EQC5      : 1;
 | 
			
		||||
	reg_t reserved1 : 3;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(EQCommonGainSelect) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct EQCommonGainSetting {
 | 
			
		||||
	reg_t EQnT      : 2;
 | 
			
		||||
	reg_t EQnG      : 6;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(EQCommonGainSetting) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
using EQ2CommonGainSetting = EQCommonGainSetting;
 | 
			
		||||
using EQ3CommonGainSetting = EQCommonGainSetting;
 | 
			
		||||
using EQ4CommonGainSetting = EQCommonGainSetting;
 | 
			
		||||
using EQ5CommonGainSetting = EQCommonGainSetting;
 | 
			
		||||
 | 
			
		||||
struct AutoHPFControl {
 | 
			
		||||
	reg_t STG       : 2;
 | 
			
		||||
	reg_t SENC      : 3;
 | 
			
		||||
	reg_t AHPF      : 1;
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(AutoHPFControl) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct DigitalFilterSelect1 {
 | 
			
		||||
	reg_t HPFAD     : 1;
 | 
			
		||||
	reg_t HPFC      : 2;
 | 
			
		||||
	reg_t reserved0 : 5;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(DigitalFilterSelect1) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct DigitalFilterSelect2 {
 | 
			
		||||
	reg_t HPF       : 1;
 | 
			
		||||
	reg_t LPF       : 1;
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
	reg_t FIL3      : 1;
 | 
			
		||||
	reg_t EQ0       : 1;
 | 
			
		||||
	reg_t GN        : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(DigitalFilterSelect2) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct DigitalFilterMode {
 | 
			
		||||
	reg_t PFSDO     : 1;
 | 
			
		||||
	reg_t ADCPF     : 1;
 | 
			
		||||
	reg_t PFDAC     : 2;
 | 
			
		||||
	reg_t PFVOL     : 2;
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(DigitalFilterMode) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct Coefficient14L {
 | 
			
		||||
	reg_t l         : 8;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Coefficient14H {
 | 
			
		||||
	reg_t h         : 6;
 | 
			
		||||
	reg_t reserved0 : 2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(Coefficient14L) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
static_assert(sizeof(Coefficient14H) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
using Coefficient16L = Coefficient14L;
 | 
			
		||||
 | 
			
		||||
struct Coefficient16H {
 | 
			
		||||
	reg_t h         : 8;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(Coefficient16H) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
using HPF2Coefficient0 = Coefficient14L;
 | 
			
		||||
using HPF2Coefficient1 = Coefficient14H;
 | 
			
		||||
using HPF2Coefficient2 = Coefficient14L;
 | 
			
		||||
using HPF2Coefficient3 = Coefficient14H;
 | 
			
		||||
 | 
			
		||||
using LPFCoefficient0 = Coefficient14L;
 | 
			
		||||
using LPFCoefficient1 = Coefficient14H;
 | 
			
		||||
using LPFCoefficient2 = Coefficient14L;
 | 
			
		||||
using LPFCoefficient3 = Coefficient14H;
 | 
			
		||||
 | 
			
		||||
using FIL3Coefficient0 = Coefficient14L;
 | 
			
		||||
 | 
			
		||||
struct FIL3Coefficient1 {
 | 
			
		||||
	reg_t h : 6;
 | 
			
		||||
	reg_t reserved0 : 1;
 | 
			
		||||
	reg_t s : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(FIL3Coefficient1) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
using FIL3Coefficient2 = Coefficient14L;
 | 
			
		||||
using FIL3Coefficient3 = Coefficient14H;
 | 
			
		||||
 | 
			
		||||
using EQCoefficient0 = Coefficient16L;
 | 
			
		||||
using EQCoefficient1 = Coefficient16H;
 | 
			
		||||
using EQCoefficient2 = Coefficient14L;
 | 
			
		||||
using EQCoefficient3 = Coefficient14H;
 | 
			
		||||
using EQCoefficient4 = Coefficient16L;
 | 
			
		||||
using EQCoefficient5 = Coefficient16H;
 | 
			
		||||
 | 
			
		||||
struct DigitalFilterSelect3 {
 | 
			
		||||
	reg_t EQ1       : 1;
 | 
			
		||||
	reg_t EQ2       : 1;
 | 
			
		||||
	reg_t EQ3       : 1;
 | 
			
		||||
	reg_t EQ4       : 1;
 | 
			
		||||
	reg_t EQ5       : 1;
 | 
			
		||||
	reg_t reserved0 : 3;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(DigitalFilterSelect3) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
struct DeviceInformation {
 | 
			
		||||
	reg_t DVN       : 4;
 | 
			
		||||
	reg_t REV       : 4;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(DeviceInformation) == sizeof(reg_t), "wrong size struct");
 | 
			
		||||
 | 
			
		||||
using E1Coefficient0 = Coefficient16L;
 | 
			
		||||
using E1Coefficient1 = Coefficient16H;
 | 
			
		||||
using E1Coefficient2 = Coefficient16L;
 | 
			
		||||
using E1Coefficient3 = Coefficient16H;
 | 
			
		||||
using E1Coefficient4 = Coefficient16L;
 | 
			
		||||
using E1Coefficient5 = Coefficient16H;
 | 
			
		||||
 | 
			
		||||
using E2Coefficient0 = Coefficient16L;
 | 
			
		||||
using E2Coefficient1 = Coefficient16H;
 | 
			
		||||
using E2Coefficient2 = Coefficient16L;
 | 
			
		||||
using E2Coefficient3 = Coefficient16H;
 | 
			
		||||
using E2Coefficient4 = Coefficient16L;
 | 
			
		||||
using E2Coefficient5 = Coefficient16H;
 | 
			
		||||
 | 
			
		||||
using E3Coefficient0 = Coefficient16L;
 | 
			
		||||
using E3Coefficient1 = Coefficient16H;
 | 
			
		||||
using E3Coefficient2 = Coefficient16L;
 | 
			
		||||
using E3Coefficient3 = Coefficient16H;
 | 
			
		||||
using E3Coefficient4 = Coefficient16L;
 | 
			
		||||
using E3Coefficient5 = Coefficient16H;
 | 
			
		||||
 | 
			
		||||
using E4Coefficient0 = Coefficient16L;
 | 
			
		||||
using E4Coefficient1 = Coefficient16H;
 | 
			
		||||
using E4Coefficient2 = Coefficient16L;
 | 
			
		||||
using E4Coefficient3 = Coefficient16H;
 | 
			
		||||
using E4Coefficient4 = Coefficient16L;
 | 
			
		||||
using E4Coefficient5 = Coefficient16H;
 | 
			
		||||
 | 
			
		||||
using E5Coefficient0 = Coefficient16L;
 | 
			
		||||
using E5Coefficient1 = Coefficient16H;
 | 
			
		||||
using E5Coefficient2 = Coefficient16L;
 | 
			
		||||
using E5Coefficient3 = Coefficient16H;
 | 
			
		||||
using E5Coefficient4 = Coefficient16L;
 | 
			
		||||
using E5Coefficient5 = Coefficient16H;
 | 
			
		||||
 | 
			
		||||
struct Register_Type {
 | 
			
		||||
	PowerManagement1		power_management_1;
 | 
			
		||||
	PowerManagement2		power_management_2;
 | 
			
		||||
	SignalSelect1			signal_select_1;
 | 
			
		||||
	SignalSelect2			signal_select_2;
 | 
			
		||||
	SignalSelect3			signal_select_3;
 | 
			
		||||
	ModeControl1			mode_control_1;
 | 
			
		||||
	ModeControl2			mode_control_2;
 | 
			
		||||
	ModeControl3			mode_control_3;
 | 
			
		||||
	DigitalMIC				digital_mic;
 | 
			
		||||
	TimerSelect				timer_select;
 | 
			
		||||
	ALCTimerSelect			alc_timer_select;
 | 
			
		||||
	ALCModeControl1			alc_mode_control_1;
 | 
			
		||||
	ALCModeControl2			alc_mode_control_2;
 | 
			
		||||
	LchInputVolumeControl	l_ch_input_volume_control;
 | 
			
		||||
	RchInputVolumeControl	r_ch_input_volume_control;
 | 
			
		||||
	ALCVolume				alc_volume;
 | 
			
		||||
	reg_t					_reserved_0x10;
 | 
			
		||||
	RchMICGainSetting		r_ch_mic_gain_setting;
 | 
			
		||||
	BeepControl				beep_control;
 | 
			
		||||
	LchDigitalVolumeControl	l_ch_digital_volume_control;
 | 
			
		||||
	RchDigitalVolumeControl	r_ch_digital_volume_control;
 | 
			
		||||
	EQCommonGainSelect		eq_common_gain_select;
 | 
			
		||||
	EQ2CommonGainSetting	eq2_common_gain_setting;
 | 
			
		||||
	EQ3CommonGainSetting	eq3_common_gain_setting;
 | 
			
		||||
	EQ4CommonGainSetting	eq4_common_gain_setting;
 | 
			
		||||
	EQ5CommonGainSetting	eq5_common_gain_setting;
 | 
			
		||||
	AutoHPFControl			auto_hpf_control;
 | 
			
		||||
	DigitalFilterSelect1	digital_filter_select_1;
 | 
			
		||||
	DigitalFilterSelect2	digital_filter_select_2;
 | 
			
		||||
	DigitalFilterMode		digital_filter_mode;
 | 
			
		||||
	HPF2Coefficient0		hpf_2_coefficient_0;
 | 
			
		||||
	HPF2Coefficient1		hpf_2_coefficient_1;
 | 
			
		||||
	HPF2Coefficient2		hpf_2_coefficient_2;
 | 
			
		||||
	HPF2Coefficient3		hpf_2_coefficient_3;
 | 
			
		||||
	LPFCoefficient0			lpf_coefficient_0;
 | 
			
		||||
	LPFCoefficient1			lpf_coefficient_1;
 | 
			
		||||
	LPFCoefficient2			lpf_coefficient_2;
 | 
			
		||||
	LPFCoefficient3			lpf_coefficient_3;
 | 
			
		||||
	FIL3Coefficient0		fil_3_coefficient_0;
 | 
			
		||||
	FIL3Coefficient1		fil_3_coefficient_1;
 | 
			
		||||
	FIL3Coefficient2		fil_3_coefficient_2;
 | 
			
		||||
	FIL3Coefficient3		fil_3_coefficient_3;
 | 
			
		||||
	EQCoefficient0			eq_coefficient_0;
 | 
			
		||||
	EQCoefficient1			eq_coefficient_1;
 | 
			
		||||
	EQCoefficient2			eq_coefficient_2;
 | 
			
		||||
	EQCoefficient3			eq_coefficient_3;
 | 
			
		||||
	EQCoefficient4			eq_coefficient_4;
 | 
			
		||||
	EQCoefficient5			eq_coefficient_5;
 | 
			
		||||
	DigitalFilterSelect3	digital_filter_select_3;
 | 
			
		||||
	DeviceInformation		device_information;
 | 
			
		||||
	E1Coefficient0			e1_coefficient_0;
 | 
			
		||||
	E1Coefficient1			e1_coefficient_1;
 | 
			
		||||
	E1Coefficient2			e1_coefficient_2;
 | 
			
		||||
	E1Coefficient3			e1_coefficient_3;
 | 
			
		||||
	E1Coefficient4			e1_coefficient_4;
 | 
			
		||||
	E1Coefficient5			e1_coefficient_5;
 | 
			
		||||
	E2Coefficient0			e2_coefficient_0;
 | 
			
		||||
	E2Coefficient1			e2_coefficient_1;
 | 
			
		||||
	E2Coefficient2			e2_coefficient_2;
 | 
			
		||||
	E2Coefficient3			e2_coefficient_3;
 | 
			
		||||
	E2Coefficient4			e2_coefficient_4;
 | 
			
		||||
	E2Coefficient5			e2_coefficient_5;
 | 
			
		||||
	E3Coefficient0			e3_coefficient_0;
 | 
			
		||||
	E3Coefficient1			e3_coefficient_1;
 | 
			
		||||
	E3Coefficient2			e3_coefficient_2;
 | 
			
		||||
	E3Coefficient3			e3_coefficient_3;
 | 
			
		||||
	E3Coefficient4			e3_coefficient_4;
 | 
			
		||||
	E3Coefficient5			e3_coefficient_5;
 | 
			
		||||
	E4Coefficient0			e4_coefficient_0;
 | 
			
		||||
	E4Coefficient1			e4_coefficient_1;
 | 
			
		||||
	E4Coefficient2			e4_coefficient_2;
 | 
			
		||||
	E4Coefficient3			e4_coefficient_3;
 | 
			
		||||
	E4Coefficient4			e4_coefficient_4;
 | 
			
		||||
	E4Coefficient5			e4_coefficient_5;
 | 
			
		||||
	E5Coefficient0			e5_coefficient_0;
 | 
			
		||||
	E5Coefficient1			e5_coefficient_1;
 | 
			
		||||
	E5Coefficient2			e5_coefficient_2;
 | 
			
		||||
	E5Coefficient3			e5_coefficient_3;
 | 
			
		||||
	E5Coefficient4			e5_coefficient_4;
 | 
			
		||||
	E5Coefficient5			e5_coefficient_5;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(Register_Type) == reg_count * sizeof(reg_t), "Register_Type wrong size");
 | 
			
		||||
 | 
			
		||||
struct RegisterMap {
 | 
			
		||||
	constexpr RegisterMap(
 | 
			
		||||
		Register_Type values
 | 
			
		||||
	) : r(values)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		Register_Type r;
 | 
			
		||||
		std::array<reg_t, reg_count> w;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(RegisterMap) == reg_count * sizeof(reg_t), "RegisterMap type wrong size");
 | 
			
		||||
 | 
			
		||||
constexpr RegisterMap default_after_reset { Register_Type {
 | 
			
		||||
	.power_management_1 = {
 | 
			
		||||
		.PMADL = 0,
 | 
			
		||||
		.PMADR = 0,
 | 
			
		||||
		.PMDAC = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.PMBP = 0,
 | 
			
		||||
		.PMVCM = 0,
 | 
			
		||||
		.PMPFIL = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.power_management_2 = {
 | 
			
		||||
		.LOSEL = 0,
 | 
			
		||||
		.PMSL = 0,
 | 
			
		||||
		.PMPLL = 0,
 | 
			
		||||
		.MS = 0,
 | 
			
		||||
		.PMHPL = 0,
 | 
			
		||||
		.PMHPR = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.PMOSC = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.signal_select_1 = {
 | 
			
		||||
		.MGAIN20 = 0b110,
 | 
			
		||||
		.PMMP = 0,
 | 
			
		||||
		.MPSEL = 0,
 | 
			
		||||
		.DACS = 0,
 | 
			
		||||
		.MGAIN3 = 0,
 | 
			
		||||
		.SLPSN = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.signal_select_2 = {
 | 
			
		||||
		.INR = 0b00,
 | 
			
		||||
		.INL = 0b00,
 | 
			
		||||
		.MICL = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.SPKG = 0b00,
 | 
			
		||||
	},
 | 
			
		||||
	.signal_select_3 = {
 | 
			
		||||
		.MONO = 0b00,
 | 
			
		||||
		.PTS = 0b01,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.DACL = 0,
 | 
			
		||||
		.LVCM = 0b01,
 | 
			
		||||
	},
 | 
			
		||||
	.mode_control_1 = {
 | 
			
		||||
		.DIF = 0b10,
 | 
			
		||||
		.CKOFF = 0,
 | 
			
		||||
		.BCKO = 0,
 | 
			
		||||
		.PLL = 0b0101,
 | 
			
		||||
	},
 | 
			
		||||
	.mode_control_2 = {
 | 
			
		||||
		.FS = 0b1011,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.CM = 0b00,
 | 
			
		||||
	},
 | 
			
		||||
	.mode_control_3 = {
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.IVOLC = 1,
 | 
			
		||||
		.reserved1 = 0,
 | 
			
		||||
		.DVOLC = 1,
 | 
			
		||||
		.SMUTE = 0,
 | 
			
		||||
		.THDET = 0,
 | 
			
		||||
		.TSDSEL = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.digital_mic = {
 | 
			
		||||
		.DMIC = 0,
 | 
			
		||||
		.DCLKP = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.DCLKE = 0,
 | 
			
		||||
		.PMDML = 0,
 | 
			
		||||
		.PMDMR = 1,
 | 
			
		||||
		.reserved1 = 0,
 | 
			
		||||
		.READ = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.timer_select = {
 | 
			
		||||
		.DVTM = 0,
 | 
			
		||||
		.MOFF = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.FRN = 0,
 | 
			
		||||
		.FRATT = 0,
 | 
			
		||||
		.ADRST = 0b00,
 | 
			
		||||
	},
 | 
			
		||||
	.alc_timer_select = {
 | 
			
		||||
		.RFST = 0b00,
 | 
			
		||||
		.WTM = 0b00,
 | 
			
		||||
		.EQFC = 0b10,
 | 
			
		||||
		.IVTM = 1,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.alc_mode_control_1 = {
 | 
			
		||||
		.LMTH10 = 0b00,
 | 
			
		||||
		.RGAIN = 0b000,
 | 
			
		||||
		.ALC = 0,
 | 
			
		||||
		.LMTH2 = 0,
 | 
			
		||||
		.ALCEQN = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.alc_mode_control_2 = {
 | 
			
		||||
		.REF = 0xe1,
 | 
			
		||||
	},
 | 
			
		||||
	.l_ch_input_volume_control = {
 | 
			
		||||
		.IV = 0xe1,
 | 
			
		||||
	},
 | 
			
		||||
	.r_ch_input_volume_control = {
 | 
			
		||||
		.IV = 0xe1,
 | 
			
		||||
	},
 | 
			
		||||
	.alc_volume = {
 | 
			
		||||
		.VOL = 0x00,	// Read-only.
 | 
			
		||||
	},
 | 
			
		||||
	._reserved_0x10 = 0x80,
 | 
			
		||||
	.r_ch_mic_gain_setting = {
 | 
			
		||||
		.MGR = 0x80,
 | 
			
		||||
	},
 | 
			
		||||
	.beep_control = {
 | 
			
		||||
		.BPLVL = 0b0000,
 | 
			
		||||
		.BEEPH = 0,
 | 
			
		||||
		.BEEPS = 0,
 | 
			
		||||
		.BPVCM = 0,
 | 
			
		||||
		.HPZ = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.l_ch_digital_volume_control = {
 | 
			
		||||
		.DV = 0x18,
 | 
			
		||||
	},
 | 
			
		||||
	.r_ch_digital_volume_control = {
 | 
			
		||||
		.DV = 0x18,
 | 
			
		||||
	},
 | 
			
		||||
	.eq_common_gain_select = {
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.EQC2 = 0,
 | 
			
		||||
		.EQC3 = 0,
 | 
			
		||||
		.EQC4 = 0,
 | 
			
		||||
		.EQC5 = 0,
 | 
			
		||||
		.reserved1 = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.eq2_common_gain_setting = {
 | 
			
		||||
		.EQnT = 0b00,
 | 
			
		||||
		.EQnG = 0b000000,
 | 
			
		||||
	},
 | 
			
		||||
	.eq3_common_gain_setting = {
 | 
			
		||||
		.EQnT = 0b00,
 | 
			
		||||
		.EQnG = 0b000000,
 | 
			
		||||
	},
 | 
			
		||||
	.eq4_common_gain_setting = {
 | 
			
		||||
		.EQnT = 0b00,
 | 
			
		||||
		.EQnG = 0b000000,
 | 
			
		||||
	},
 | 
			
		||||
	.eq5_common_gain_setting = {
 | 
			
		||||
		.EQnT = 0b00,
 | 
			
		||||
		.EQnG = 0b000000,
 | 
			
		||||
	},
 | 
			
		||||
	.auto_hpf_control = {
 | 
			
		||||
		.STG = 0b00,
 | 
			
		||||
		.SENC = 0b011,
 | 
			
		||||
		.AHPF = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.digital_filter_select_1 = {
 | 
			
		||||
		.HPFAD = 1,
 | 
			
		||||
		.HPFC = 0b00,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.digital_filter_select_2 = {
 | 
			
		||||
		.HPF = 0,
 | 
			
		||||
		.LPF = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
		.FIL3 = 0,
 | 
			
		||||
		.EQ0 = 0,
 | 
			
		||||
		.GN = 0b00,
 | 
			
		||||
	},
 | 
			
		||||
	.digital_filter_mode = {
 | 
			
		||||
		.PFSDO = 1,
 | 
			
		||||
		.ADCPF = 1,
 | 
			
		||||
		.PFDAC = 0b00,
 | 
			
		||||
		.PFVOL = 0b00,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	.hpf_2_coefficient_0 = { .l = 0xb0 },
 | 
			
		||||
	.hpf_2_coefficient_1 = { .h = 0x1f, .reserved0 = 0 },
 | 
			
		||||
	.hpf_2_coefficient_2 = { .l = 0x9f },
 | 
			
		||||
	.hpf_2_coefficient_3 = { .h = 0x20, .reserved0 = 0 },
 | 
			
		||||
	
 | 
			
		||||
	.lpf_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.lpf_coefficient_1 = { .h = 0x00, .reserved0 = 0 },
 | 
			
		||||
	.lpf_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.lpf_coefficient_3 = { .h = 0x00, .reserved0 = 0 },
 | 
			
		||||
	
 | 
			
		||||
	.fil_3_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.fil_3_coefficient_1 = { .h = 0x00, .reserved0 = 0, .s = 0 },
 | 
			
		||||
	.fil_3_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.fil_3_coefficient_3 = { .h = 0x00, .reserved0 = 0 },
 | 
			
		||||
	
 | 
			
		||||
	.eq_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.eq_coefficient_1 = { .h = 0x00 },
 | 
			
		||||
	.eq_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.eq_coefficient_3 = { .h = 0x00, .reserved0 = 0 },
 | 
			
		||||
	.eq_coefficient_4 = { .l = 0x00 },
 | 
			
		||||
	.eq_coefficient_5 = { .h = 0x00 },
 | 
			
		||||
 | 
			
		||||
	.digital_filter_select_3 = {
 | 
			
		||||
		.EQ1 = 0,
 | 
			
		||||
		.EQ2 = 0,
 | 
			
		||||
		.EQ3 = 0,
 | 
			
		||||
		.EQ4 = 0,
 | 
			
		||||
		.EQ5 = 0,
 | 
			
		||||
		.reserved0 = 0,
 | 
			
		||||
	},
 | 
			
		||||
	.device_information = {
 | 
			
		||||
		.DVN = 0b0001,
 | 
			
		||||
		.REV = 0b1100,
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	.e1_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.e1_coefficient_1 = { .h = 0x00 },
 | 
			
		||||
	.e1_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.e1_coefficient_3 = { .h = 0x00 },
 | 
			
		||||
	.e1_coefficient_4 = { .l = 0x00 },
 | 
			
		||||
	.e1_coefficient_5 = { .h = 0x00 },
 | 
			
		||||
	
 | 
			
		||||
	.e2_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.e2_coefficient_1 = { .h = 0x00 },
 | 
			
		||||
	.e2_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.e2_coefficient_3 = { .h = 0x00 },
 | 
			
		||||
	.e2_coefficient_4 = { .l = 0x00 },
 | 
			
		||||
	.e2_coefficient_5 = { .h = 0x00 },
 | 
			
		||||
	
 | 
			
		||||
	.e3_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.e3_coefficient_1 = { .h = 0x00 },
 | 
			
		||||
	.e3_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.e3_coefficient_3 = { .h = 0x00 },
 | 
			
		||||
	.e3_coefficient_4 = { .l = 0x00 },
 | 
			
		||||
	.e3_coefficient_5 = { .h = 0x00 },
 | 
			
		||||
	
 | 
			
		||||
	.e4_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.e4_coefficient_1 = { .h = 0x00 },
 | 
			
		||||
	.e4_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.e4_coefficient_3 = { .h = 0x00 },
 | 
			
		||||
	.e4_coefficient_4 = { .l = 0x00 },
 | 
			
		||||
	.e4_coefficient_5 = { .h = 0x00 },
 | 
			
		||||
 | 
			
		||||
	.e5_coefficient_0 = { .l = 0x00 },
 | 
			
		||||
	.e5_coefficient_1 = { .h = 0x00 },
 | 
			
		||||
	.e5_coefficient_2 = { .l = 0x00 },
 | 
			
		||||
	.e5_coefficient_3 = { .h = 0x00 },
 | 
			
		||||
	.e5_coefficient_4 = { .l = 0x00 },
 | 
			
		||||
	.e5_coefficient_5 = { .h = 0x00 },
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
class AK4951 : public audio::Codec  {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr AK4951(
 | 
			
		||||
		I2C& bus,
 | 
			
		||||
		const I2C::address_t bus_address
 | 
			
		||||
	) : bus(bus),
 | 
			
		||||
		bus_address(bus_address)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string name() const override {
 | 
			
		||||
		return "AK4951";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool detected();
 | 
			
		||||
	
 | 
			
		||||
	void init() override;
 | 
			
		||||
	bool reset() override;
 | 
			
		||||
 | 
			
		||||
	volume_range_t headphone_gain_range() const override {
 | 
			
		||||
		return { -89.5_dB, 12.0_dB }; 
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void headphone_enable() override;
 | 
			
		||||
	void headphone_disable() override;
 | 
			
		||||
 | 
			
		||||
	void speaker_enable();
 | 
			
		||||
	void speaker_disable();
 | 
			
		||||
 | 
			
		||||
	void set_headphone_volume(const volume_t volume) override;
 | 
			
		||||
	void headphone_mute();
 | 
			
		||||
 | 
			
		||||
	void microphone_enable();
 | 
			
		||||
	void microphone_disable();
 | 
			
		||||
 | 
			
		||||
	size_t reg_count() const override {
 | 
			
		||||
		return asahi_kasei::ak4951::reg_count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t reg_bits() const override {
 | 
			
		||||
		return 8;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t reg_read(const size_t reg_address) override {
 | 
			
		||||
		return read(reg_address);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	I2C& bus;
 | 
			
		||||
	const I2C::address_t bus_address;
 | 
			
		||||
	RegisterMap map { default_after_reset };
 | 
			
		||||
 | 
			
		||||
	enum class LineOutSelect {
 | 
			
		||||
		Speaker,
 | 
			
		||||
		Line,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void configure_digital_interface_i2s();
 | 
			
		||||
	void configure_digital_interface_external_slave();
 | 
			
		||||
	void configure_digital_interface_external_master();
 | 
			
		||||
	void set_digtal_volume_control(const reg_t value);
 | 
			
		||||
	void set_dac_power(const bool enable);
 | 
			
		||||
	void set_headphone_power(const bool enable);
 | 
			
		||||
	void set_speaker_power(const bool enable);
 | 
			
		||||
	void select_line_out(const LineOutSelect value);
 | 
			
		||||
 | 
			
		||||
	reg_t read(const address_t reg_address);
 | 
			
		||||
	void update(const Register reg);
 | 
			
		||||
	void write(const address_t reg_address, const reg_t value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace ak4951 */
 | 
			
		||||
} /* namespace asahi_kasei */
 | 
			
		||||
 | 
			
		||||
#endif/*__AK4951_H__*/
 | 
			
		||||
							
								
								
									
										27
									
								
								Software/portapack-mayhem/firmware/common/aprs_packet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Software/portapack-mayhem/firmware/common/aprs_packet.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "aprs_packet.hpp"
 | 
			
		||||
 | 
			
		||||
namespace aprs {
 | 
			
		||||
 | 
			
		||||
} /* namespace zwave */
 | 
			
		||||
							
								
								
									
										495
									
								
								Software/portapack-mayhem/firmware/common/aprs_packet.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										495
									
								
								Software/portapack-mayhem/firmware/common/aprs_packet.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,495 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __APRS_PACKET_H__
 | 
			
		||||
#define __APRS_PACKET_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cctype>
 | 
			
		||||
 | 
			
		||||
#include "baseband.hpp"
 | 
			
		||||
 | 
			
		||||
namespace aprs {
 | 
			
		||||
 | 
			
		||||
const int APRS_MIN_LENGTH = 18; //14 bytes address, control byte and pid. 2 CRC.
 | 
			
		||||
 | 
			
		||||
struct aprs_pos{
 | 
			
		||||
	float latitude;
 | 
			
		||||
	float longitude;	
 | 
			
		||||
	uint8_t symbol_code;
 | 
			
		||||
	uint8_t  sym_table_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ADDRESS_TYPE {
 | 
			
		||||
	SOURCE,
 | 
			
		||||
	DESTINATION,
 | 
			
		||||
	REPEATER
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class APRSPacket {
 | 
			
		||||
public:
 | 
			
		||||
	void set_timestamp(const Timestamp& value) {
 | 
			
		||||
		timestamp_ = value;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Timestamp timestamp() const {
 | 
			
		||||
		return timestamp_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set(const size_t index, const uint8_t data) {		
 | 
			
		||||
		payload[index] = data;
 | 
			
		||||
 | 
			
		||||
		if(index + 1 > payload_size){
 | 
			
		||||
			payload_size = index + 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t operator[](const size_t index) const {
 | 
			
		||||
		return payload[index];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	uint8_t size() const {
 | 
			
		||||
		return payload_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_valid_checksum(const bool valid) {
 | 
			
		||||
		valid_checksum = valid;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_valid_checksum() const {
 | 
			
		||||
		return valid_checksum;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t get_source(){
 | 
			
		||||
		uint64_t source = 0x0;
 | 
			
		||||
 | 
			
		||||
		for(uint8_t i = SOURCE_START; i < SOURCE_START + ADDRESS_SIZE; i++){
 | 
			
		||||
			source |= ( ((uint64_t)payload[i]) << ((i - SOURCE_START) * 8));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return source;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string get_source_formatted(){
 | 
			
		||||
		parse_address(SOURCE_START, SOURCE);
 | 
			
		||||
		return std::string(address_buffer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string get_destination_formatted(){
 | 
			
		||||
		parse_address(DESTINATION_START, DESTINATION);
 | 
			
		||||
		return std::string(address_buffer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string get_digipeaters_formatted(){
 | 
			
		||||
		uint8_t position = DIGIPEATER_START;
 | 
			
		||||
		bool has_more = parse_address(SOURCE_START, REPEATER);
 | 
			
		||||
 | 
			
		||||
		std::string repeaters = "";
 | 
			
		||||
		while(has_more){			
 | 
			
		||||
			has_more = parse_address(position, REPEATER);	
 | 
			
		||||
			repeaters += std::string(address_buffer);
 | 
			
		||||
 | 
			
		||||
			position += ADDRESS_SIZE;
 | 
			
		||||
 | 
			
		||||
			if(has_more){			
 | 
			
		||||
				repeaters += ">";
 | 
			
		||||
			}		
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return repeaters;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t get_number_of_digipeaters(){
 | 
			
		||||
		uint8_t position = DIGIPEATER_START;		
 | 
			
		||||
		bool has_more = parse_address(SOURCE_START, REPEATER);
 | 
			
		||||
		uint8_t repeaters = 0;
 | 
			
		||||
		while(has_more){			
 | 
			
		||||
			has_more = parse_address(position, REPEATER);	
 | 
			
		||||
			position += ADDRESS_SIZE;
 | 
			
		||||
			repeaters++;	
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return repeaters;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t get_information_start_index(){
 | 
			
		||||
		return DIGIPEATER_START + (get_number_of_digipeaters() * ADDRESS_SIZE) + 2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string get_information_text_formatted(){
 | 
			
		||||
		std::string information_text = "";
 | 
			
		||||
		for(uint8_t i = get_information_start_index(); i < payload_size - 2; i++){
 | 
			
		||||
			information_text += payload[i];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return information_text;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string get_stream_text(){
 | 
			
		||||
		std::string stream = get_source_formatted() + ">" + get_destination_formatted() + ";" + get_digipeaters_formatted() + ";" + get_information_text_formatted();
 | 
			
		||||
 | 
			
		||||
		return stream;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char get_data_type_identifier(){
 | 
			
		||||
		char ident = '\0';
 | 
			
		||||
		for(uint8_t i = get_information_start_index(); i < payload_size - 2; i++){
 | 
			
		||||
			ident = payload[i];
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		return ident;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool has_position(){		
 | 
			
		||||
		char ident = get_data_type_identifier();
 | 
			
		||||
 | 
			
		||||
		return 
 | 
			
		||||
			ident == '!' || 
 | 
			
		||||
			ident == '=' || 
 | 
			
		||||
			ident == '/' || 
 | 
			
		||||
			ident == '@' || 
 | 
			
		||||
			ident == ';' || 
 | 
			
		||||
			ident == '`' ||
 | 
			
		||||
			ident == '\''||
 | 
			
		||||
			ident == 0x1d||
 | 
			
		||||
			ident == 0x1c;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	aprs_pos get_position(){
 | 
			
		||||
		aprs::aprs_pos pos;
 | 
			
		||||
 | 
			
		||||
		char ident = get_data_type_identifier();
 | 
			
		||||
		std::string info_text = get_information_text_formatted();
 | 
			
		||||
 | 
			
		||||
		std::string lat_str, lng_str;
 | 
			
		||||
		char first;
 | 
			
		||||
		//bool supports_compression = true;
 | 
			
		||||
		bool is_mic_e_format = false;
 | 
			
		||||
		std::string::size_type start;
 | 
			
		||||
 | 
			
		||||
		switch(ident){
 | 
			
		||||
			case '/':
 | 
			
		||||
			case '@':
 | 
			
		||||
				start = 8;
 | 
			
		||||
				break;
 | 
			
		||||
			case '=':
 | 
			
		||||
			case '!':
 | 
			
		||||
				start = 1;
 | 
			
		||||
				break;
 | 
			
		||||
			case ';':			
 | 
			
		||||
				start = 18;
 | 
			
		||||
				//supports_compression = false;
 | 
			
		||||
				break;
 | 
			
		||||
			case '`':
 | 
			
		||||
			case '\'':
 | 
			
		||||
			case 0x1c:
 | 
			
		||||
			case 0x1d:
 | 
			
		||||
				is_mic_e_format = true;
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				return pos;
 | 
			
		||||
		}		
 | 
			
		||||
		if(is_mic_e_format){
 | 
			
		||||
			parse_mic_e_format(pos);
 | 
			
		||||
		}
 | 
			
		||||
		else {			
 | 
			
		||||
			if(start < info_text.size()){
 | 
			
		||||
				first = info_text.at(start);
 | 
			
		||||
 | 
			
		||||
				if(std::isdigit(first)){
 | 
			
		||||
					if(start + 18 < info_text.size()){
 | 
			
		||||
						lat_str = info_text.substr(start, 8);
 | 
			
		||||
						pos.sym_table_id = info_text.at(start + 8);
 | 
			
		||||
						lng_str = info_text.substr(start + 9, 9);
 | 
			
		||||
						pos.symbol_code = info_text.at(start + 18);
 | 
			
		||||
 | 
			
		||||
						pos.latitude = parse_lat_str(lat_str);
 | 
			
		||||
						pos.longitude = parse_lng_str(lng_str);
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					if(start + 9 < info_text.size()){
 | 
			
		||||
						pos.sym_table_id = info_text.at(start);
 | 
			
		||||
						lat_str = info_text.substr(start + 1, 4);
 | 
			
		||||
						lng_str = info_text.substr(start + 5, 4);
 | 
			
		||||
						pos.symbol_code = info_text.at(start + 9);
 | 
			
		||||
 | 
			
		||||
						pos.latitude = parse_lat_str_cmp(lat_str);
 | 
			
		||||
						pos.longitude = parse_lng_str_cmp(lng_str);	
 | 
			
		||||
					}		
 | 
			
		||||
				}
 | 
			
		||||
			}			
 | 
			
		||||
		}		
 | 
			
		||||
 | 
			
		||||
		return pos;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void clear() {
 | 
			
		||||
		payload_size = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const uint8_t DIGIPEATER_START = 14;
 | 
			
		||||
	const uint8_t SOURCE_START = 7;
 | 
			
		||||
	const uint8_t DESTINATION_START = 0;
 | 
			
		||||
	const uint8_t ADDRESS_SIZE = 7;
 | 
			
		||||
 | 
			
		||||
	bool valid_checksum = false;
 | 
			
		||||
	uint8_t payload[256];
 | 
			
		||||
	char address_buffer[15];
 | 
			
		||||
	uint8_t payload_size = 0 ;
 | 
			
		||||
	Timestamp timestamp_ { };
 | 
			
		||||
 | 
			
		||||
	float parse_lat_str_cmp(const std::string& lat_str){
 | 
			
		||||
		return 90.0 - ( (lat_str.at(0) - 33) * (91*91*91) + (lat_str.at(1) - 33) * (91*91) + (lat_str.at(2) - 33) * 91 + (lat_str.at(3)) ) / 380926.0;		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float parse_lng_str_cmp(const std::string& lng_str){
 | 
			
		||||
		return -180.0 + ( (lng_str.at(0) - 33) * (91*91*91) + (lng_str.at(1) - 33) * (91*91) + (lng_str.at(2) - 33) * 91 + (lng_str.at(3)) ) / 190463.0;		
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	uint8_t parse_digits(const std::string& str){
 | 
			
		||||
		if(str.at(0) == ' '){
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		uint8_t end = str.find_last_not_of(' ') + 1;
 | 
			
		||||
		std::string sub = str.substr(0, end);
 | 
			
		||||
 | 
			
		||||
		if(!is_digits(sub)){
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			return std::stoi(sub);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_digits(const std::string& str){
 | 
			
		||||
		return str.find_last_not_of("0123456789") == std::string::npos;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float parse_lat_str(const std::string& lat_str){
 | 
			
		||||
		float lat = 0.0;
 | 
			
		||||
 | 
			
		||||
		std::string str_lat_deg = lat_str.substr(0, 2);
 | 
			
		||||
		std::string str_lat_min = lat_str.substr(2, 2);
 | 
			
		||||
		std::string str_lat_hund = lat_str.substr(5, 2);
 | 
			
		||||
		std::string dir = lat_str.substr(7, 1);
 | 
			
		||||
 | 
			
		||||
		uint8_t lat_deg = parse_digits(str_lat_deg);
 | 
			
		||||
		uint8_t lat_min = parse_digits(str_lat_min);
 | 
			
		||||
		uint8_t lat_hund = parse_digits(str_lat_hund);
 | 
			
		||||
 | 
			
		||||
		lat += lat_deg;
 | 
			
		||||
		lat += (lat_min + (lat_hund/ 100.0))/60.0;
 | 
			
		||||
 | 
			
		||||
		if(dir.c_str()[0] == 'S'){
 | 
			
		||||
			lat = -lat;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return lat;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float parse_lng_str(std::string& lng_str){
 | 
			
		||||
		float lng = 0.0;
 | 
			
		||||
 | 
			
		||||
		std::string str_lng_deg = lng_str.substr(0, 3);
 | 
			
		||||
		std::string str_lng_min = lng_str.substr(3, 2);
 | 
			
		||||
		std::string str_lng_hund = lng_str.substr(6, 2);
 | 
			
		||||
		std::string dir = lng_str.substr(8, 1);
 | 
			
		||||
 | 
			
		||||
		uint8_t lng_deg = parse_digits(str_lng_deg);
 | 
			
		||||
		uint8_t lng_min = parse_digits(str_lng_min);
 | 
			
		||||
		uint8_t lng_hund = parse_digits(str_lng_hund);
 | 
			
		||||
 | 
			
		||||
		lng += lng_deg;
 | 
			
		||||
		lng += (lng_min + (lng_hund/ 100.0))/60.0;
 | 
			
		||||
 | 
			
		||||
		if(dir.c_str()[0] == 'W'){
 | 
			
		||||
			lng = -lng;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return lng;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void parse_mic_e_format(aprs::aprs_pos& pos){
 | 
			
		||||
		std::string lat_str = "";
 | 
			
		||||
		std::string lng_str = "";
 | 
			
		||||
 | 
			
		||||
		bool is_north = false;
 | 
			
		||||
		bool is_west = false;
 | 
			
		||||
		uint8_t lng_offset = 0;
 | 
			
		||||
		for(uint8_t i = DESTINATION_START; i < DESTINATION_START + ADDRESS_SIZE - 1; i++){
 | 
			
		||||
			uint8_t ascii = payload[i] >> 1;
 | 
			
		||||
 | 
			
		||||
			lat_str += get_mic_e_lat_digit(ascii);
 | 
			
		||||
 | 
			
		||||
			if(i - DESTINATION_START == 3){
 | 
			
		||||
				lat_str += ".";
 | 
			
		||||
			}
 | 
			
		||||
			if(i - DESTINATION_START == 3){
 | 
			
		||||
				is_north = is_mic_e_lat_N(ascii);
 | 
			
		||||
			}
 | 
			
		||||
			if(i - DESTINATION_START == 4){
 | 
			
		||||
				lng_offset = get_mic_e_lng_offset(ascii);
 | 
			
		||||
			}
 | 
			
		||||
			if(i - DESTINATION_START == 5){
 | 
			
		||||
				is_west = is_mic_e_lng_W(ascii);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if(is_north){
 | 
			
		||||
			lat_str += "N";
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			lat_str += "S";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pos.latitude = parse_lat_str(lat_str);	
 | 
			
		||||
 | 
			
		||||
		float lng = 0.0;
 | 
			
		||||
		uint8_t information_start = get_information_start_index() + 1;
 | 
			
		||||
		for(uint8_t i = information_start; i < information_start + 3 && i < payload_size - 2; i++){
 | 
			
		||||
			uint8_t ascii = payload[i];
 | 
			
		||||
			
 | 
			
		||||
			if(i - information_start == 0){ //deg
 | 
			
		||||
				ascii -=28;
 | 
			
		||||
				ascii += lng_offset;
 | 
			
		||||
 | 
			
		||||
				if(ascii >= 180 && ascii <= 189){
 | 
			
		||||
					ascii -= 80;
 | 
			
		||||
				}
 | 
			
		||||
				else if (ascii >= 190 && ascii <= 199){
 | 
			
		||||
					ascii -= 190;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				lng += ascii;
 | 
			
		||||
			}	
 | 
			
		||||
			else if(i - information_start == 1){ //min
 | 
			
		||||
				ascii -= 28;
 | 
			
		||||
				if(ascii >= 60){
 | 
			
		||||
					ascii -= 60;
 | 
			
		||||
				}
 | 
			
		||||
				lng += ascii/60.0;
 | 
			
		||||
			}	
 | 
			
		||||
			else if(i - information_start == 2){ //hundredth minutes
 | 
			
		||||
				ascii -= 28;
 | 
			
		||||
 | 
			
		||||
				lng += (ascii/100.0)/60.0;
 | 
			
		||||
			}	
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if(is_west){
 | 
			
		||||
			lng = -lng;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pos.longitude = lng;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t get_mic_e_lat_digit(uint8_t ascii){
 | 
			
		||||
		if(ascii >= '0' && ascii <= '9'){
 | 
			
		||||
			return ascii;
 | 
			
		||||
		}
 | 
			
		||||
		if(ascii >= 'A' && ascii <= 'J'){
 | 
			
		||||
			return ascii - 17;
 | 
			
		||||
		}
 | 
			
		||||
		if(ascii >= 'P' && ascii <='Y'){
 | 
			
		||||
			return ascii - 32;
 | 
			
		||||
		}
 | 
			
		||||
		if(ascii == 'K' || ascii == 'L' || ascii == 'Z'){
 | 
			
		||||
			return ' ';
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return '\0';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_mic_e_lat_N(uint8_t ascii){
 | 
			
		||||
		if(ascii >= 'P' && ascii <='Z'){
 | 
			
		||||
			return true;
 | 
			
		||||
		}		
 | 
			
		||||
		return false; //not technical definition, but the other case is invalid
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_mic_e_lng_W(uint8_t ascii){
 | 
			
		||||
		if(ascii >= 'P' && ascii <='Z'){
 | 
			
		||||
			return true;
 | 
			
		||||
		}		
 | 
			
		||||
		return false; //not technical definition, but the other case is invalid
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t get_mic_e_lng_offset(uint8_t ascii){
 | 
			
		||||
		if(ascii >= 'P' && ascii <='Z'){
 | 
			
		||||
			return 100;
 | 
			
		||||
		}		
 | 
			
		||||
		return 0; //not technical definition, but the other case is invalid
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool parse_address(uint8_t start, ADDRESS_TYPE address_type){
 | 
			
		||||
		uint8_t byte = 0;
 | 
			
		||||
		uint8_t has_more = false;
 | 
			
		||||
		uint8_t ssid = 0;
 | 
			
		||||
		uint8_t buffer_index = 0;
 | 
			
		||||
 | 
			
		||||
		for(uint8_t i = start; i < start + ADDRESS_SIZE && i < payload_size - 2; i++){
 | 
			
		||||
			byte = payload[i];
 | 
			
		||||
 | 
			
		||||
			if(i - start == 6){
 | 
			
		||||
				 has_more = (byte & 0x1) == 0;
 | 
			
		||||
				 ssid = (byte >> 1) & 0x0F;
 | 
			
		||||
 | 
			
		||||
				 if(ssid != 0 || address_type == REPEATER){
 | 
			
		||||
				 	address_buffer[buffer_index++] = '-';				 	
 | 
			
		||||
 | 
			
		||||
				 	if(ssid < 10){
 | 
			
		||||
				 		address_buffer[buffer_index++] = '0' + ssid;				 		
 | 
			
		||||
				 		address_buffer[buffer_index++] = '\0';
 | 
			
		||||
				 	}
 | 
			
		||||
				 	else {
 | 
			
		||||
				 		address_buffer[buffer_index++] = '1';
 | 
			
		||||
				 		address_buffer[buffer_index++] = '0' + ssid - 10;
 | 
			
		||||
				 		address_buffer[buffer_index++] = '\0';
 | 
			
		||||
				 	}
 | 
			
		||||
				 }
 | 
			
		||||
				 else {
 | 
			
		||||
					 address_buffer[buffer_index++] = '\0';
 | 
			
		||||
				 }
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				byte >>= 1;
 | 
			
		||||
 | 
			
		||||
				if(byte != ' '){
 | 
			
		||||
					address_buffer[buffer_index++] = byte;		
 | 
			
		||||
				}			
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return has_more;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace aprs */
 | 
			
		||||
 | 
			
		||||
#endif/*__APRS_PACKET_H__*/
 | 
			
		||||
							
								
								
									
										100
									
								
								Software/portapack-mayhem/firmware/common/backlight.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								Software/portapack-mayhem/firmware/common/backlight.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "backlight.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_io.hpp"
 | 
			
		||||
 | 
			
		||||
namespace portapack {
 | 
			
		||||
 | 
			
		||||
void BacklightOnOff::on() {
 | 
			
		||||
	if( !is_on() ) {
 | 
			
		||||
		io.lcd_backlight(true);
 | 
			
		||||
		on_ = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BacklightOnOff::off() {
 | 
			
		||||
	if( is_on() ) {
 | 
			
		||||
		io.lcd_backlight(false);
 | 
			
		||||
		on_ = false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BacklightCAT4004::set_level(const value_t value) {		
 | 
			
		||||
	auto target = value;
 | 
			
		||||
 | 
			
		||||
	// Clip target value to valid range.
 | 
			
		||||
	if( target < 0 ) {
 | 
			
		||||
		target = 0;
 | 
			
		||||
	}
 | 
			
		||||
	if( target > maximum_level ) {
 | 
			
		||||
		target = maximum_level;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if( is_on() ) {
 | 
			
		||||
		pulses(target);
 | 
			
		||||
	} else {
 | 
			
		||||
		level_ = target;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BacklightCAT4004::on() {
 | 
			
		||||
	if( !is_on() ) {
 | 
			
		||||
		io.lcd_backlight(true);
 | 
			
		||||
		halPolledDelay(ticks_setup);
 | 
			
		||||
		on_ = true;
 | 
			
		||||
 | 
			
		||||
		// Just enabled driver, initial value is maximum.
 | 
			
		||||
		const auto target_level = level();
 | 
			
		||||
		level_ = maximum_level;
 | 
			
		||||
 | 
			
		||||
		pulses(target_level);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BacklightCAT4004::off() {
 | 
			
		||||
	if( is_on() ) {
 | 
			
		||||
		io.lcd_backlight(false);
 | 
			
		||||
		chThdSleepMilliseconds(ms_pwrdwn);
 | 
			
		||||
		on_ = false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BacklightCAT4004::pulses(value_t target) {
 | 
			
		||||
	while(level() != target) {
 | 
			
		||||
		pulse();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BacklightCAT4004::pulse() {
 | 
			
		||||
	io.lcd_backlight(false);
 | 
			
		||||
	halPolledDelay(ticks_lo);
 | 
			
		||||
	io.lcd_backlight(true);
 | 
			
		||||
	halPolledDelay(ticks_hi);
 | 
			
		||||
 | 
			
		||||
	level_ -= 1;
 | 
			
		||||
	if( level_ < 0 ) {
 | 
			
		||||
		level_ = levels() - 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace portapack */
 | 
			
		||||
							
								
								
									
										120
									
								
								Software/portapack-mayhem/firmware/common/backlight.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								Software/portapack-mayhem/firmware/common/backlight.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
namespace portapack {
 | 
			
		||||
 | 
			
		||||
class Backlight {
 | 
			
		||||
public:
 | 
			
		||||
	using value_t = int_fast8_t;
 | 
			
		||||
 | 
			
		||||
	virtual ~Backlight() = default;
 | 
			
		||||
 | 
			
		||||
	virtual value_t levels() const = 0;
 | 
			
		||||
 | 
			
		||||
	virtual void set_level(const value_t value) = 0;
 | 
			
		||||
	virtual value_t level() const = 0;
 | 
			
		||||
 | 
			
		||||
	virtual void increase() = 0;
 | 
			
		||||
	virtual void decrease() = 0;
 | 
			
		||||
 | 
			
		||||
	virtual void on() = 0;
 | 
			
		||||
	virtual void off() = 0;
 | 
			
		||||
 | 
			
		||||
	virtual bool is_on() const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BacklightBase : public Backlight {
 | 
			
		||||
public:
 | 
			
		||||
	void increase() override {
 | 
			
		||||
		set_level(level() + 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void decrease() override {
 | 
			
		||||
		set_level(level() - 1);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BacklightOnOff : public BacklightBase {
 | 
			
		||||
public:
 | 
			
		||||
	value_t levels() const override {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_level(const value_t) override {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	value_t level() const override {
 | 
			
		||||
		return levels() - 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void on() override;
 | 
			
		||||
	void off() override;
 | 
			
		||||
 | 
			
		||||
	bool is_on() const override {
 | 
			
		||||
		return on_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr value_t maximum_level = 1;
 | 
			
		||||
 | 
			
		||||
	bool on_ { false };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BacklightCAT4004 : public BacklightBase {
 | 
			
		||||
public:
 | 
			
		||||
	value_t levels() const override {
 | 
			
		||||
		return maximum_level + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_level(const value_t value) override;
 | 
			
		||||
 | 
			
		||||
	value_t level() const override {
 | 
			
		||||
		return level_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void on() override;
 | 
			
		||||
	void off() override;
 | 
			
		||||
 | 
			
		||||
	bool is_on() const override {
 | 
			
		||||
		return on_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr value_t initial_brightness = 25;
 | 
			
		||||
	static constexpr value_t maximum_level = 31;
 | 
			
		||||
 | 
			
		||||
	static constexpr uint32_t ticks_setup  = 204e6 * 10e-6;
 | 
			
		||||
	static constexpr uint32_t ms_pwrdwn    = 5;
 | 
			
		||||
	static constexpr uint32_t ticks_lo     = 204e6 * 1e-6;
 | 
			
		||||
	static constexpr uint32_t ticks_hi     = 204e6 * 1e-6;
 | 
			
		||||
 | 
			
		||||
	value_t level_ { initial_brightness };
 | 
			
		||||
	bool on_ { false };
 | 
			
		||||
 | 
			
		||||
	void pulses(value_t target);
 | 
			
		||||
	void pulse();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace portapack */
 | 
			
		||||
							
								
								
									
										40
									
								
								Software/portapack-mayhem/firmware/common/baseband.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Software/portapack-mayhem/firmware/common/baseband.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_H__
 | 
			
		||||
#define __BASEBAND_H__
 | 
			
		||||
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
#include "buffer.hpp"
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
 | 
			
		||||
using sample_t = complex8_t;
 | 
			
		||||
using buffer_t = buffer_t<sample_t>;
 | 
			
		||||
 | 
			
		||||
enum class Direction {
 | 
			
		||||
	Receive = 0,
 | 
			
		||||
	Transmit = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace baseband */
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_H__*/
 | 
			
		||||
							
								
								
									
										38
									
								
								Software/portapack-mayhem/firmware/common/baseband_cpld.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Software/portapack-mayhem/firmware/common/baseband_cpld.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "baseband_cpld.hpp"
 | 
			
		||||
 | 
			
		||||
#include "hackrf_gpio.hpp"
 | 
			
		||||
using namespace hackrf::one;
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
 | 
			
		||||
void CPLD::init() {
 | 
			
		||||
	set_invert(false);
 | 
			
		||||
	gpio_baseband_invert.output();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::set_invert(const bool invert) {
 | 
			
		||||
	gpio_baseband_invert.write(invert);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								Software/portapack-mayhem/firmware/common/baseband_cpld.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Software/portapack-mayhem/firmware/common/baseband_cpld.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_CPLD_H__
 | 
			
		||||
#define __BASEBAND_CPLD_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
 | 
			
		||||
class CPLD {
 | 
			
		||||
public:
 | 
			
		||||
	void init();
 | 
			
		||||
 | 
			
		||||
	void set_invert(const bool invert);
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_CPLD_H__*/
 | 
			
		||||
@@ -0,0 +1,72 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_PACKET_H__
 | 
			
		||||
#define __BASEBAND_PACKET_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
 | 
			
		||||
class Packet {
 | 
			
		||||
public:
 | 
			
		||||
	void set_timestamp(const Timestamp& value) {
 | 
			
		||||
		timestamp_ = value;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Timestamp timestamp() const {
 | 
			
		||||
		return timestamp_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void add(const bool symbol) {
 | 
			
		||||
		if( count < capacity() ) {
 | 
			
		||||
			data[count++] = symbol;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint_fast8_t operator[](const size_t index) const {
 | 
			
		||||
		return (index < size()) ? data[index] : 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t size() const {
 | 
			
		||||
		return count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t capacity() const {
 | 
			
		||||
		return data.size();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void clear() {
 | 
			
		||||
		count = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::bitset<2560> data { };
 | 
			
		||||
	Timestamp timestamp_ { };
 | 
			
		||||
	size_t count { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace baseband */
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_PACKET_H__*/
 | 
			
		||||
							
								
								
									
										392
									
								
								Software/portapack-mayhem/firmware/common/baseband_sgpio.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								Software/portapack-mayhem/firmware/common/baseband_sgpio.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,392 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "baseband_sgpio.hpp"
 | 
			
		||||
 | 
			
		||||
#include "baseband.hpp"
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
struct PinConfig {
 | 
			
		||||
	P_OUT_CFG p_out_cfg;
 | 
			
		||||
	P_OE_CFG p_oe_cfg { P_OE_CFG::GPIO_OE };
 | 
			
		||||
 | 
			
		||||
	constexpr SGPIOPinConfig(
 | 
			
		||||
		P_OUT_CFG p_out_cfg
 | 
			
		||||
	) :
 | 
			
		||||
		p_out_cfg(p_out_cfg)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static constexpr bool slice_mode_multislice = false;
 | 
			
		||||
 | 
			
		||||
static constexpr P_OUT_CFG output_multiplexing_mode =
 | 
			
		||||
	slice_mode_multislice ? P_OUT_CFG::DOUT_DOUTM8C : P_OUT_CFG::DOUT_DOUTM8A;
 | 
			
		||||
 | 
			
		||||
static constexpr std::array<PinConfig, 16> pin_config { {
 | 
			
		||||
	[PIN_D0]		= { output_multiplexing_mode, SLICE_A },
 | 
			
		||||
	[PIN_D1]		= { output_multiplexing_mode, SLICE_I },
 | 
			
		||||
	[PIN_D2]		= { output_multiplexing_mode, },
 | 
			
		||||
	[PIN_D3]		= { output_multiplexing_mode, },
 | 
			
		||||
	[PIN_D4]		= { output_multiplexing_mode, },
 | 
			
		||||
	[PIN_D5]		= { output_multiplexing_mode, },
 | 
			
		||||
	[PIN_D6]		= { output_multiplexing_mode, },
 | 
			
		||||
	[PIN_D7]		= { output_multiplexing_mode, },
 | 
			
		||||
	[PIN_CLKIN]		= { P_OUT_CFG::DOUT_DOUTM1, },
 | 
			
		||||
	[PIN_CAPTURE]	= { P_OUT_CFG::DOUT_DOUTM1, },
 | 
			
		||||
	[PIN_DISABLE]	= { P_OUT_CFG::GPIO_OUT, },
 | 
			
		||||
	[PIN_DIRECTION]	= { P_OUT_CFG::GPIO_OUT, },
 | 
			
		||||
	[PIN_INVERT]	= { P_OUT_CFG::GPIO_OUT, },
 | 
			
		||||
	[PIN_DECIM0]	= { P_OUT_CFG::GPIO_OUT, },
 | 
			
		||||
	[PIN_DECIM1]	= { P_OUT_CFG::DOUT_DOUTM1, },
 | 
			
		||||
	[PIN_DECIM2]	= { P_OUT_CFG::GPIO_OUT, },
 | 
			
		||||
} };
 | 
			
		||||
*/
 | 
			
		||||
/*
 | 
			
		||||
static constexpr std::array<LPC_SGPIO_OUT_MUX_CFG_Type, 16> out_mux_cfg_receive {
 | 
			
		||||
	{ },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static constexpr std::array<LPC_SGPIO_OUT_MUX_CFG_Type, 16> out_mux_cfg_transmit {
 | 
			
		||||
	{ },
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
enum class P_OUT_CFG : uint8_t {
 | 
			
		||||
	DOUT_DOUTM1 = 0x0,
 | 
			
		||||
	DOUT_DOUTM2A = 0x1,
 | 
			
		||||
	DOUT_DOUTM2B = 0x2,
 | 
			
		||||
	DOUT_DOUTM2C = 0x3,
 | 
			
		||||
	GPIO_OUT = 0x4,
 | 
			
		||||
	DOUT_DOUTM4A = 0x5,
 | 
			
		||||
	DOUT_DOUTM4B = 0x6,
 | 
			
		||||
	DOUT_DOUTM4C = 0x7,
 | 
			
		||||
	CLK_OUT = 0x8,
 | 
			
		||||
	DOUT_DOUTM8A = 0x9,
 | 
			
		||||
	DOUT_DOUTM8B = 0xa,
 | 
			
		||||
	DOUT_DOUTM8C = 0xb,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class P_OE_CFG : uint8_t {
 | 
			
		||||
	GPIO_OE = 0x0,
 | 
			
		||||
	DOUT_OEM1 = 0x4,
 | 
			
		||||
	DOUT_OEM2 = 0x5,
 | 
			
		||||
	DOUT_OEM4 = 0x6,
 | 
			
		||||
	DOUT_OEM8 = 0x7,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class CONCAT_ORDER : uint8_t {
 | 
			
		||||
	SELF_LOOP = 0x0,
 | 
			
		||||
	TWO_SLICES = 0x1,
 | 
			
		||||
	FOUR_SLICES = 0x2,
 | 
			
		||||
	EIGHT_SLICES = 0x3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class CONCAT_ENABLE : uint8_t {
 | 
			
		||||
	EXTERNAL_DATA_PIN = 0x0,
 | 
			
		||||
	CONCATENATE_DATA = 0x1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class CLK_CAPTURE_MODE : uint8_t {
 | 
			
		||||
	RISING_CLOCK_EDGE = 0,
 | 
			
		||||
	FALLING_CLOCK_EDGE = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class PARALLEL_MODE : uint8_t {
 | 
			
		||||
	SHIFT_1_BIT_PER_CLOCK = 0x0,
 | 
			
		||||
	SHIFT_2_BITS_PER_CLOCK = 0x1,
 | 
			
		||||
	SHIFT_4_BITS_PER_CLOCK = 0x2,
 | 
			
		||||
	SHIFT_1_BYTE_PER_CLOCK = 0x3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	PIN_D0 = 0,
 | 
			
		||||
	PIN_D1 = 1,
 | 
			
		||||
	PIN_D2 = 2,
 | 
			
		||||
	PIN_D3 = 3,
 | 
			
		||||
	PIN_D4 = 4,
 | 
			
		||||
	PIN_D5 = 5,
 | 
			
		||||
	PIN_D6 = 6,
 | 
			
		||||
	PIN_D7 = 7,
 | 
			
		||||
	PIN_CLKIN = 8,
 | 
			
		||||
	PIN_CAPTURE = 9,
 | 
			
		||||
	PIN_DISABLE = 10,
 | 
			
		||||
	PIN_DIRECTION = 11,
 | 
			
		||||
	PIN_INVERT = 12,
 | 
			
		||||
	PIN_SYNC_EN = 13,
 | 
			
		||||
	PIN_P81 = 14,
 | 
			
		||||
	PIN_P78 = 15,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Slice : uint8_t {
 | 
			
		||||
	A =  0,
 | 
			
		||||
	B =  1,
 | 
			
		||||
	C =  2,
 | 
			
		||||
	D =  3,
 | 
			
		||||
	E =  4,
 | 
			
		||||
	F =  5,
 | 
			
		||||
	G =  6,
 | 
			
		||||
	H =  7,
 | 
			
		||||
	I =  8,
 | 
			
		||||
	J =  9,
 | 
			
		||||
	K = 10,
 | 
			
		||||
	L = 11,
 | 
			
		||||
	M = 12,
 | 
			
		||||
	N = 13,
 | 
			
		||||
	O = 14,
 | 
			
		||||
	P = 15,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr bool slice_mode_multislice = false;
 | 
			
		||||
 | 
			
		||||
constexpr uint8_t pos_count_multi_slice = 0x1f;
 | 
			
		||||
constexpr uint8_t pos_count_single_slice = 0x03;
 | 
			
		||||
 | 
			
		||||
constexpr Slice slice_order[] {
 | 
			
		||||
	Slice::A,
 | 
			
		||||
	Slice::I,
 | 
			
		||||
	Slice::E,
 | 
			
		||||
	Slice::J,
 | 
			
		||||
	Slice::C,
 | 
			
		||||
	Slice::K,
 | 
			
		||||
	Slice::F,
 | 
			
		||||
	Slice::L,
 | 
			
		||||
	Slice::B,
 | 
			
		||||
	Slice::M,
 | 
			
		||||
	Slice::G,
 | 
			
		||||
	Slice::N,
 | 
			
		||||
	Slice::D,
 | 
			
		||||
	Slice::O,
 | 
			
		||||
	Slice::H,
 | 
			
		||||
	Slice::P,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t gpio_outreg(const Direction direction) {
 | 
			
		||||
	return ((direction == Direction::Transmit) ? (1U << PIN_DIRECTION) : 0U) | (1U << PIN_DISABLE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t gpio_oenreg(const Direction direction) {
 | 
			
		||||
	return
 | 
			
		||||
		  (0U << PIN_P78)
 | 
			
		||||
		| (0U << PIN_P81)
 | 
			
		||||
		| (0U << PIN_SYNC_EN)
 | 
			
		||||
		| (0U << PIN_INVERT)
 | 
			
		||||
		| (1U << PIN_DIRECTION)
 | 
			
		||||
		| (1U << PIN_DISABLE)
 | 
			
		||||
		| (0U << PIN_CAPTURE)
 | 
			
		||||
		| (0U << PIN_CLKIN)
 | 
			
		||||
		| ((direction == Direction::Transmit) ? 0xffU : 0x00U)
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t out_mux_cfg(const P_OUT_CFG out, const P_OE_CFG oe) {
 | 
			
		||||
	return
 | 
			
		||||
		  (toUType(out) << 0)
 | 
			
		||||
		| (toUType(oe) << 4)
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t data_sgpio_mux_cfg(
 | 
			
		||||
	const CONCAT_ENABLE concat_enable,
 | 
			
		||||
	const CONCAT_ORDER concat_order
 | 
			
		||||
) {
 | 
			
		||||
	return
 | 
			
		||||
		  (1U << 0)
 | 
			
		||||
		| (0U << 1)
 | 
			
		||||
		| (0U << 3)
 | 
			
		||||
		| (3U << 5)
 | 
			
		||||
		| (1U << 7)
 | 
			
		||||
		| (0U << 9)
 | 
			
		||||
		| (toUType(concat_enable) << 11)
 | 
			
		||||
		| (toUType(concat_order) << 12)
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t data_slice_mux_cfg(
 | 
			
		||||
	const PARALLEL_MODE parallel_mode,
 | 
			
		||||
	const CLK_CAPTURE_MODE clk_capture_mode
 | 
			
		||||
) {
 | 
			
		||||
	return
 | 
			
		||||
		  (0U << 0)
 | 
			
		||||
		| (toUType(clk_capture_mode) << 1)
 | 
			
		||||
		| (1U << 2)
 | 
			
		||||
		| (0U << 3)
 | 
			
		||||
		| (0U << 4)
 | 
			
		||||
		| (toUType(parallel_mode) << 6)
 | 
			
		||||
		| (0U << 8)
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t pos(
 | 
			
		||||
	const uint32_t pos,
 | 
			
		||||
	const uint32_t pos_reset
 | 
			
		||||
) {
 | 
			
		||||
	return
 | 
			
		||||
		  (pos << 0)
 | 
			
		||||
		| (pos_reset << 8)
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
constexpr uint32_t data_pos(
 | 
			
		||||
	const bool multi_slice
 | 
			
		||||
) {
 | 
			
		||||
	return pos(
 | 
			
		||||
		(multi_slice ? pos_count_multi_slice : pos_count_single_slice),
 | 
			
		||||
		(multi_slice ? pos_count_multi_slice : pos_count_single_slice)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr CONCAT_ENABLE data_concat_enable(
 | 
			
		||||
	const bool input_slice,
 | 
			
		||||
	const bool single_slice
 | 
			
		||||
) {
 | 
			
		||||
	return (input_slice || single_slice)
 | 
			
		||||
		? CONCAT_ENABLE::EXTERNAL_DATA_PIN
 | 
			
		||||
		: CONCAT_ENABLE::CONCATENATE_DATA
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr CONCAT_ORDER data_concat_order(
 | 
			
		||||
	const bool input_slice,
 | 
			
		||||
	const bool single_slice
 | 
			
		||||
) {
 | 
			
		||||
	return (input_slice || single_slice)
 | 
			
		||||
		? CONCAT_ORDER::SELF_LOOP
 | 
			
		||||
		: CONCAT_ORDER::EIGHT_SLICES
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr CLK_CAPTURE_MODE data_clk_capture_mode(
 | 
			
		||||
	const Direction direction
 | 
			
		||||
) {
 | 
			
		||||
	return (direction == Direction::Transmit)
 | 
			
		||||
		? CLK_CAPTURE_MODE::RISING_CLOCK_EDGE
 | 
			
		||||
		: CLK_CAPTURE_MODE::RISING_CLOCK_EDGE
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr P_OUT_CFG data_p_out_cfg(
 | 
			
		||||
	const bool multi_slice
 | 
			
		||||
) {
 | 
			
		||||
	return (multi_slice)
 | 
			
		||||
		? P_OUT_CFG::DOUT_DOUTM8C
 | 
			
		||||
		: P_OUT_CFG::DOUT_DOUTM8A
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const sgpio_resources_t sgpio_resources = {
 | 
			
		||||
	.base = { .clk = &LPC_CGU->BASE_PERIPH_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 6) },
 | 
			
		||||
	.branch = { .cfg = &LPC_CCU1->CLK_PERIPH_SGPIO_CFG, .stat = &LPC_CCU1->CLK_PERIPH_SGPIO_STAT },
 | 
			
		||||
	.reset = { .output_index = 57 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void SGPIO::init() {
 | 
			
		||||
	base_clock_enable(&sgpio_resources.base);
 | 
			
		||||
	branch_clock_enable(&sgpio_resources.branch);
 | 
			
		||||
	peripheral_reset(&sgpio_resources.reset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SGPIO::configure(const Direction direction) {
 | 
			
		||||
	disable_all_slice_counters();
 | 
			
		||||
 | 
			
		||||
	// Set data pins as input, temporarily.
 | 
			
		||||
	LPC_SGPIO->GPIO_OENREG = gpio_oenreg(Direction::Receive);
 | 
			
		||||
 | 
			
		||||
	// Now that data pins are inputs, safe to change CPLD direction.
 | 
			
		||||
	LPC_SGPIO->GPIO_OUTREG = gpio_outreg(direction);
 | 
			
		||||
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[ 8] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1,	P_OE_CFG::GPIO_OE);
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[ 9] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1,	P_OE_CFG::GPIO_OE);
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[10] = out_mux_cfg(P_OUT_CFG::GPIO_OUT,		P_OE_CFG::GPIO_OE);
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[11] = out_mux_cfg(P_OUT_CFG::GPIO_OUT,		P_OE_CFG::GPIO_OE);
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[12] = out_mux_cfg(P_OUT_CFG::GPIO_OUT,		P_OE_CFG::GPIO_OE);
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[13] = out_mux_cfg(P_OUT_CFG::GPIO_OUT,		P_OE_CFG::GPIO_OE);
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[14] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1,	P_OE_CFG::GPIO_OE);
 | 
			
		||||
	LPC_SGPIO->OUT_MUX_CFG[15] = out_mux_cfg(P_OUT_CFG::GPIO_OUT,		P_OE_CFG::GPIO_OE);
 | 
			
		||||
 | 
			
		||||
	const auto data_out_mux_cfg = out_mux_cfg(data_p_out_cfg(slice_mode_multislice), P_OE_CFG::GPIO_OE);
 | 
			
		||||
	for(size_t i=0; i<8; i++) {
 | 
			
		||||
		LPC_SGPIO->OUT_MUX_CFG[i] = data_out_mux_cfg;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Now that output enable sources are set, enable data bus in correct direction.
 | 
			
		||||
	LPC_SGPIO->GPIO_OENREG = gpio_oenreg(direction);
 | 
			
		||||
 | 
			
		||||
	const auto slice_gpdma = Slice::H;
 | 
			
		||||
 | 
			
		||||
	const size_t slice_count = slice_mode_multislice ? 8 : 1;
 | 
			
		||||
	const auto clk_capture_mode = data_clk_capture_mode(direction);
 | 
			
		||||
	const auto single_slice = !slice_mode_multislice;
 | 
			
		||||
 | 
			
		||||
	uint32_t slice_enable_mask = 0;
 | 
			
		||||
	for(size_t i=0; i<slice_count; i++) {
 | 
			
		||||
		const auto slice = slice_order[i];
 | 
			
		||||
		const auto slice_index = toUType(slice);
 | 
			
		||||
		const auto input_slice = (i == 0) && (direction != Direction::Transmit);
 | 
			
		||||
		const auto concat_order = data_concat_order(input_slice, single_slice);
 | 
			
		||||
		const auto concat_enable = data_concat_enable(input_slice, single_slice);
 | 
			
		||||
 | 
			
		||||
		LPC_SGPIO->SGPIO_MUX_CFG[slice_index] = data_sgpio_mux_cfg(
 | 
			
		||||
			concat_enable,
 | 
			
		||||
			concat_order
 | 
			
		||||
		);
 | 
			
		||||
		LPC_SGPIO->SLICE_MUX_CFG[slice_index] = data_slice_mux_cfg(
 | 
			
		||||
			PARALLEL_MODE::SHIFT_1_BYTE_PER_CLOCK,
 | 
			
		||||
			clk_capture_mode
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		LPC_SGPIO->PRESET[slice_index] = 0;
 | 
			
		||||
		LPC_SGPIO->COUNT[slice_index] = 0;
 | 
			
		||||
		LPC_SGPIO->POS[slice_index] = data_pos(slice_mode_multislice);
 | 
			
		||||
		LPC_SGPIO->REG[slice_index] = 0;
 | 
			
		||||
		LPC_SGPIO->REG_SS[slice_index] = 0;
 | 
			
		||||
 | 
			
		||||
		slice_enable_mask |= (1U << slice_index);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if( !slice_mode_multislice ) {
 | 
			
		||||
		const auto slice_index = toUType(slice_gpdma);
 | 
			
		||||
 | 
			
		||||
		LPC_SGPIO->SGPIO_MUX_CFG[slice_index] = data_sgpio_mux_cfg(
 | 
			
		||||
			CONCAT_ENABLE::CONCATENATE_DATA,
 | 
			
		||||
			CONCAT_ORDER::SELF_LOOP
 | 
			
		||||
		);
 | 
			
		||||
		LPC_SGPIO->SLICE_MUX_CFG[slice_index] = data_slice_mux_cfg(
 | 
			
		||||
			PARALLEL_MODE::SHIFT_1_BIT_PER_CLOCK,
 | 
			
		||||
			clk_capture_mode
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		LPC_SGPIO->PRESET[slice_index] = 0;
 | 
			
		||||
		LPC_SGPIO->COUNT[slice_index] = 0;
 | 
			
		||||
		LPC_SGPIO->POS[slice_index] = pos(0x1f, 0x1f);
 | 
			
		||||
		LPC_SGPIO->REG[slice_index] = 0x11111111;
 | 
			
		||||
		LPC_SGPIO->REG_SS[slice_index] = 0x11111111;
 | 
			
		||||
 | 
			
		||||
		slice_enable_mask |= (1 << slice_index);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set_slice_counter_enables(slice_enable_mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace baseband */
 | 
			
		||||
							
								
								
									
										66
									
								
								Software/portapack-mayhem/firmware/common/baseband_sgpio.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								Software/portapack-mayhem/firmware/common/baseband_sgpio.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_GPIO_H__
 | 
			
		||||
#define __BASEBAND_GPIO_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "baseband.hpp"
 | 
			
		||||
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
 | 
			
		||||
class SGPIO {
 | 
			
		||||
public:
 | 
			
		||||
	void init();
 | 
			
		||||
 | 
			
		||||
	void configure(const Direction direction);
 | 
			
		||||
 | 
			
		||||
	void streaming_enable() {
 | 
			
		||||
		/* TODO: Any reason not to control from general GPIO facility? */
 | 
			
		||||
		LPC_SGPIO->GPIO_OUTREG &= ~(1U << 10);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void streaming_disable() {
 | 
			
		||||
		/* TODO: Any reason not to control from general GPIO facility? */
 | 
			
		||||
		LPC_SGPIO->GPIO_OUTREG |= (1U << 10);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool streaming_is_enabled() const {
 | 
			
		||||
		/* TODO: Any reason not to control from general GPIO facility? */
 | 
			
		||||
		return (LPC_SGPIO->GPIO_OUTREG >> 10) & 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void disable_all_slice_counters() {
 | 
			
		||||
		set_slice_counter_enables(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_slice_counter_enables(const uint16_t enable_mask) {
 | 
			
		||||
		LPC_SGPIO->CTRL_ENABLE = enable_mask;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_GPIO_H__*/
 | 
			
		||||
							
								
								
									
										364
									
								
								Software/portapack-mayhem/firmware/common/bch_code.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										364
									
								
								Software/portapack-mayhem/firmware/common/bch_code.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,364 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Craig Shelley (craig@microtron.org.uk)
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * BCH Encoder/Decoder - Adapted from GNURadio
 | 
			
		||||
 * 
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
 | 
			
		||||
#include "bch_code.hpp"
 | 
			
		||||
 | 
			
		||||
void BCHCode::generate_gf() {
 | 
			
		||||
	/*
 | 
			
		||||
	* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
 | 
			
		||||
	* lookup tables:  index->polynomial form   alpha_to[] contains j=alpha**i;
 | 
			
		||||
	* polynomial form -> index form  index_of[j=alpha**i] = i alpha=2 is the
 | 
			
		||||
	* primitive element of GF(2**m) 
 | 
			
		||||
	*/
 | 
			
		||||
	
 | 
			
		||||
	int i, mask;
 | 
			
		||||
	mask = 1;
 | 
			
		||||
	alpha_to[m] = 0;
 | 
			
		||||
	
 | 
			
		||||
	for (i = 0; i < m; i++) 
 | 
			
		||||
	{
 | 
			
		||||
		alpha_to[i] = mask;
 | 
			
		||||
		
 | 
			
		||||
		index_of[alpha_to[i]] = i;
 | 
			
		||||
		
 | 
			
		||||
		if (p[i] != 0)
 | 
			
		||||
			alpha_to[m] ^= mask;
 | 
			
		||||
		
 | 
			
		||||
		mask <<= 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	index_of[alpha_to[m]] = m;
 | 
			
		||||
	
 | 
			
		||||
	mask >>= 1;
 | 
			
		||||
	
 | 
			
		||||
	for (i = m + 1; i < n; i++) 
 | 
			
		||||
	{
 | 
			
		||||
		if (alpha_to[i - 1] >= mask)
 | 
			
		||||
		  alpha_to[i] = alpha_to[m] ^ ((alpha_to[i - 1] ^ mask) << 1);
 | 
			
		||||
		else
 | 
			
		||||
		  alpha_to[i] = alpha_to[i - 1] << 1;
 | 
			
		||||
	
 | 
			
		||||
		index_of[alpha_to[i]] = i;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	index_of[0] = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void BCHCode::gen_poly() {
 | 
			
		||||
	/* 
 | 
			
		||||
	* Compute generator polynomial of BCH code of length = 31, redundancy = 10
 | 
			
		||||
	* (OK, this is not very efficient, but we only do it once, right? :)
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	int ii, jj, ll, kaux;
 | 
			
		||||
	int test, aux, nocycles, root, noterms, rdncy;
 | 
			
		||||
	int cycle[15][6], size[15], min[11], zeros[11];
 | 
			
		||||
	
 | 
			
		||||
	// Generate cycle sets modulo 31 
 | 
			
		||||
	cycle[0][0] = 0; size[0] = 1;
 | 
			
		||||
	cycle[1][0] = 1; size[1] = 1;
 | 
			
		||||
	jj = 1;			// cycle set index 
 | 
			
		||||
	
 | 
			
		||||
	do 
 | 
			
		||||
	{
 | 
			
		||||
		// Generate the jj-th cycle set 
 | 
			
		||||
		ii = 0;
 | 
			
		||||
		do 
 | 
			
		||||
		{
 | 
			
		||||
			ii++;
 | 
			
		||||
			cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % n;
 | 
			
		||||
			size[jj]++;
 | 
			
		||||
			aux = (cycle[jj][ii] * 2) % n;
 | 
			
		||||
 | 
			
		||||
		} while (aux != cycle[jj][0]);
 | 
			
		||||
		
 | 
			
		||||
		// Next cycle set representative 
 | 
			
		||||
		ll = 0;
 | 
			
		||||
		do 
 | 
			
		||||
		{
 | 
			
		||||
			ll++;
 | 
			
		||||
			test = 0;
 | 
			
		||||
			for (ii = 1; ((ii <= jj) && (!test)); ii++)	
 | 
			
		||||
			// Examine previous cycle sets 
 | 
			
		||||
			  for (kaux = 0; ((kaux < size[ii]) && (!test)); kaux++)
 | 
			
		||||
					if (ll == cycle[ii][kaux])
 | 
			
		||||
						test = 1;
 | 
			
		||||
		} 
 | 
			
		||||
		while ((test) && (ll < (n - 1)));
 | 
			
		||||
		
 | 
			
		||||
		if (!(test)) 
 | 
			
		||||
		{
 | 
			
		||||
			jj++;	// next cycle set index 
 | 
			
		||||
			cycle[jj][0] = ll;
 | 
			
		||||
			size[jj] = 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} while (ll < (n - 1));
 | 
			
		||||
	
 | 
			
		||||
	nocycles = jj;		// number of cycle sets modulo n 
 | 
			
		||||
	// Search for roots 1, 2, ..., d-1 in cycle sets 
 | 
			
		||||
	
 | 
			
		||||
	kaux = 0;
 | 
			
		||||
	rdncy = 0;
 | 
			
		||||
	
 | 
			
		||||
	for (ii = 1; ii <= nocycles; ii++) 
 | 
			
		||||
	{
 | 
			
		||||
		min[kaux] = 0;
 | 
			
		||||
		
 | 
			
		||||
		for (jj = 0; jj < size[ii]; jj++)
 | 
			
		||||
			for (root = 1; root < d; root++)
 | 
			
		||||
				if (root == cycle[ii][jj])
 | 
			
		||||
					min[kaux] = ii;
 | 
			
		||||
		
 | 
			
		||||
		if (min[kaux]) 
 | 
			
		||||
		{
 | 
			
		||||
			rdncy += size[min[kaux]];
 | 
			
		||||
			kaux++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	noterms = kaux;
 | 
			
		||||
	kaux = 1;
 | 
			
		||||
	
 | 
			
		||||
	for (ii = 0; ii < noterms; ii++)
 | 
			
		||||
		for (jj = 0; jj < size[min[ii]]; jj++) 
 | 
			
		||||
		{
 | 
			
		||||
			zeros[kaux] = cycle[min[ii]][jj];
 | 
			
		||||
			kaux++;
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
	// Compute generator polynomial 
 | 
			
		||||
	g[0] = alpha_to[zeros[1]];
 | 
			
		||||
	g[1] = 1;		// g(x) = (X + zeros[1]) initially 
 | 
			
		||||
	
 | 
			
		||||
	for (ii = 2; ii <= rdncy; ii++) 
 | 
			
		||||
	{
 | 
			
		||||
	  g[ii] = 1;
 | 
			
		||||
	  for (jj = ii - 1; jj > 0; jj--)
 | 
			
		||||
	    if (g[jj] != 0)
 | 
			
		||||
	      g[jj] = g[jj - 1] ^ alpha_to[(index_of[g[jj]] + zeros[ii]) % n];
 | 
			
		||||
	    else
 | 
			
		||||
	      g[jj] = g[jj - 1];
 | 
			
		||||
	  
 | 
			
		||||
		g[0] = alpha_to[(index_of[g[0]] + zeros[ii]) % n];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int * BCHCode::encode(int data[]) {
 | 
			
		||||
	// Calculate redundant bits bb[]
 | 
			
		||||
 | 
			
		||||
	int    h, i, j=0, start=0, end=(n-k);	// 10
 | 
			
		||||
	int Mr[31];
 | 
			
		||||
	
 | 
			
		||||
	if (!valid) return nullptr;
 | 
			
		||||
	
 | 
			
		||||
	for (i = 0; i < n; i++) {
 | 
			
		||||
		Mr[i] = 0;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	for (h = 0; h < k; ++h)
 | 
			
		||||
		Mr[h] = data[h];
 | 
			
		||||
	
 | 
			
		||||
	while (end < n)
 | 
			
		||||
	{
 | 
			
		||||
		for (i=end; i>start-2; --i)
 | 
			
		||||
		{
 | 
			
		||||
			if (Mr[start] != 0)
 | 
			
		||||
			{
 | 
			
		||||
				Mr[i]^=g[j];
 | 
			
		||||
				++j;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				++start;
 | 
			
		||||
				j = 0;
 | 
			
		||||
				end = start+(n-k);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	j = 0;
 | 
			
		||||
	for (i = start; i<end; ++i) {
 | 
			
		||||
		bb[j]=Mr[i];
 | 
			
		||||
		++j;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return bb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int BCHCode::decode(int recd[]) {
 | 
			
		||||
	// We do not need the Berlekamp algorithm to decode.
 | 
			
		||||
	// We solve before hand two equations in two variables.
 | 
			
		||||
 | 
			
		||||
	int i, j, q;
 | 
			
		||||
	int elp[3], s[5], s3;
 | 
			
		||||
	int count = 0, syn_error = 0;
 | 
			
		||||
	int loc[3], reg[3];
 | 
			
		||||
	int	aux;
 | 
			
		||||
	int retval=0;
 | 
			
		||||
	
 | 
			
		||||
	if (!valid) return 0;
 | 
			
		||||
	
 | 
			
		||||
	for (i = 1; i <= 4; i++) {
 | 
			
		||||
		s[i] = 0;
 | 
			
		||||
		for (j = 0; j < n; j++) {
 | 
			
		||||
			if (recd[j] != 0) {
 | 
			
		||||
				s[i] ^= alpha_to[(i * j) % n];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (s[i] != 0) {
 | 
			
		||||
			syn_error = 1;		// set flag if non-zero syndrome
 | 
			
		||||
		}
 | 
			
		||||
		/* NOTE: If only error detection is needed,
 | 
			
		||||
		 * then exit the program here...
 | 
			
		||||
		 */
 | 
			
		||||
		// Convert syndrome from polynomial form to index form
 | 
			
		||||
		s[i] = index_of[s[i]];
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	if (syn_error) {			// If there are errors, try to correct them
 | 
			
		||||
		if (s[1] != -1) {
 | 
			
		||||
			s3 = (s[1] * 3) % n;
 | 
			
		||||
			if ( s[3] == s3 ) { 	// Was it a single error ?
 | 
			
		||||
				//printf("One error at %d\n", s[1]);
 | 
			
		||||
				recd[s[1]] ^= 1; 	// Yes: Correct it
 | 
			
		||||
			} else {
 | 
			
		||||
				/* Assume two errors occurred and solve
 | 
			
		||||
				 * for the coefficients of sigma(x), the
 | 
			
		||||
				 * error locator polynomial
 | 
			
		||||
				 */
 | 
			
		||||
				if (s[3] != -1) {
 | 
			
		||||
					aux = alpha_to[s3] ^ alpha_to[s[3]];
 | 
			
		||||
				} else {
 | 
			
		||||
					aux = alpha_to[s3];
 | 
			
		||||
				}
 | 
			
		||||
				elp[0] = 0;
 | 
			
		||||
				elp[1] = (s[2] - index_of[aux] + n) % n;
 | 
			
		||||
				elp[2] = (s[1] - index_of[aux] + n) % n;
 | 
			
		||||
				//printf("sigma(x) = ");
 | 
			
		||||
				//for (i = 0; i <= 2; i++) {
 | 
			
		||||
				//	printf("%3d ", elp[i]);
 | 
			
		||||
				//}
 | 
			
		||||
				//printf("\n");
 | 
			
		||||
				//printf("Roots: ");
 | 
			
		||||
				
 | 
			
		||||
				// Find roots of the error location polynomial
 | 
			
		||||
				for (i = 1; i <= 2; i++) {
 | 
			
		||||
					reg[i] = elp[i];
 | 
			
		||||
				}
 | 
			
		||||
				count = 0;
 | 
			
		||||
				for (i = 1; i <= n; i++) { // Chien search
 | 
			
		||||
					q = 1;
 | 
			
		||||
					for (j = 1; j <= 2; j++) {
 | 
			
		||||
						if (reg[j] != -1) {
 | 
			
		||||
							reg[j] = (reg[j] + j) % n;
 | 
			
		||||
							q ^= alpha_to[reg[j]];
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if (!q) {	// store error location number indices
 | 
			
		||||
						loc[count] = i % n;
 | 
			
		||||
						count++;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if (count == 2)	{
 | 
			
		||||
					// no. roots = degree of elp hence 2 errors
 | 
			
		||||
					for (i = 0; i < 2; i++)
 | 
			
		||||
						recd[loc[i]] ^= 1;
 | 
			
		||||
				} else {	// Cannot solve: Error detection
 | 
			
		||||
					retval=1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else if (s[2] != -1) {	// Error detection
 | 
			
		||||
			retval=1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Example usage BCH(31,21,5)
 | 
			
		||||
 *
 | 
			
		||||
 * p[] = coefficients of primitive polynomial used to generate GF(2**5)
 | 
			
		||||
 * m = order of the field GF(2**5) = 5
 | 
			
		||||
 * n = 2**5 - 1 = 31
 | 
			
		||||
 * t = 2 = error correcting capability
 | 
			
		||||
 * d = 2*t + 1 = 5 = designed minimum distance
 | 
			
		||||
 * k = n - deg(g(x)) = 21 = dimension
 | 
			
		||||
 * g[] = coefficients of generator polynomial, g(x) [n - k + 1]=[11]
 | 
			
		||||
 * alpha_to [] = log table of GF(2**5)
 | 
			
		||||
 * index_of[] = antilog table of GF(2**5)
 | 
			
		||||
 * data[] = coefficients of data polynomial, i(x)
 | 
			
		||||
 * bb[] = coefficients of redundancy polynomial ( x**(10) i(x) ) modulo g(x)
 | 
			
		||||
 */
 | 
			
		||||
BCHCode::BCHCode(
 | 
			
		||||
	std::vector<int> p_init, int m, int n, int k, int t
 | 
			
		||||
) : m { m },
 | 
			
		||||
	n { n },
 | 
			
		||||
	k { k },
 | 
			
		||||
	t { t } {
 | 
			
		||||
	size_t i;
 | 
			
		||||
	
 | 
			
		||||
	d = 5;
 | 
			
		||||
	
 | 
			
		||||
	alpha_to = (int *)chHeapAlloc(NULL, sizeof(int) * (n + 1));
 | 
			
		||||
	index_of = (int *)chHeapAlloc(0, sizeof(int) * (n + 1));
 | 
			
		||||
	p = (int *)chHeapAlloc(0, sizeof(int) * (m + 1));
 | 
			
		||||
	g = (int *)chHeapAlloc(0, sizeof(int) * (n - k + 1));
 | 
			
		||||
	bb = (int *)chHeapAlloc(0, sizeof(int) * (n - k + 1));
 | 
			
		||||
	
 | 
			
		||||
	if (alpha_to == NULL ||
 | 
			
		||||
		index_of == NULL ||
 | 
			
		||||
		p == NULL ||
 | 
			
		||||
		g == NULL ||
 | 
			
		||||
		bb == NULL)
 | 
			
		||||
		valid = false;
 | 
			
		||||
	else
 | 
			
		||||
		valid = true;
 | 
			
		||||
	
 | 
			
		||||
	if (valid) {
 | 
			
		||||
		for (i = 0; i < (size_t)(m + 1); i++) {
 | 
			
		||||
			p[i] = p_init[i];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		generate_gf();			/* generate the Galois Field GF(2**m) */
 | 
			
		||||
		gen_poly();				/* Compute the generator polynomial of BCH code */
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BCHCode::~BCHCode() {
 | 
			
		||||
	if (alpha_to != NULL) chHeapFree(alpha_to);
 | 
			
		||||
	if (index_of != NULL) chHeapFree(index_of);
 | 
			
		||||
	if (p != NULL) chHeapFree(p);
 | 
			
		||||
	if (g != NULL) chHeapFree(g);
 | 
			
		||||
	if (bb != NULL) chHeapFree(bb);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								Software/portapack-mayhem/firmware/common/bch_code.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Software/portapack-mayhem/firmware/common/bch_code.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Craig Shelley (craig@microtron.org.uk)
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * BCH Encoder/Decoder - Adapted from GNURadio
 | 
			
		||||
 * 
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BCHCODE_H__
 | 
			
		||||
#define __BCHCODE_H__
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
class BCHCode {
 | 
			
		||||
public:
 | 
			
		||||
	BCHCode(std::vector<int> p_init, int m, int n, int k, int t);
 | 
			
		||||
	~BCHCode();
 | 
			
		||||
	
 | 
			
		||||
	BCHCode(const BCHCode&) = delete;
 | 
			
		||||
	BCHCode(BCHCode&&) = delete;
 | 
			
		||||
	BCHCode& operator=(const BCHCode&) = delete;
 | 
			
		||||
	BCHCode& operator=(BCHCode&&) = delete;
 | 
			
		||||
 | 
			
		||||
	int * encode(int data[]);
 | 
			
		||||
	int decode(int recd[]);
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	void gen_poly();
 | 
			
		||||
	void generate_gf();
 | 
			
		||||
	
 | 
			
		||||
	bool valid { false };
 | 
			
		||||
 | 
			
		||||
	int d { };
 | 
			
		||||
	int * p { };			// coefficients of primitive polynomial used to generate GF(2**5)
 | 
			
		||||
	int m { };				// order of the field GF(2**5) = 5
 | 
			
		||||
	int n { };				// 2**5 - 1 = 31
 | 
			
		||||
	int k { };				// n - deg(g(x)) = 21 = dimension
 | 
			
		||||
	int t { };				// 2 = error correcting capability
 | 
			
		||||
	int * alpha_to { };		// log table of GF(2**5)
 | 
			
		||||
	int * index_of { };		// antilog table of GF(2**5)
 | 
			
		||||
	int * g { };			// coefficients of generator polynomial, g(x) [n - k + 1]=[11]
 | 
			
		||||
	int * bb { };			// coefficients of redundancy polynomial ( x**(10) i(x) ) modulo g(x)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__BCHCODE_H__*/
 | 
			
		||||
							
								
								
									
										73
									
								
								Software/portapack-mayhem/firmware/common/bit_pattern.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								Software/portapack-mayhem/firmware/common/bit_pattern.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BIT_PATTERN_H__
 | 
			
		||||
#define __BIT_PATTERN_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
class BitHistory {
 | 
			
		||||
public:
 | 
			
		||||
	void add(const uint_fast8_t bit) {
 | 
			
		||||
		history = (history << 1) | (bit & 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t value() const {
 | 
			
		||||
		return history;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint64_t history { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BitPattern {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr BitPattern(
 | 
			
		||||
	) : code_ { 0 },
 | 
			
		||||
		mask_ { 0 },
 | 
			
		||||
		maximum_hanning_distance_ { 0 }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	constexpr BitPattern(
 | 
			
		||||
		const uint64_t code,
 | 
			
		||||
		const size_t code_length,
 | 
			
		||||
		const size_t maximum_hanning_distance = 0
 | 
			
		||||
	) : code_ { code },
 | 
			
		||||
		mask_ { (1ULL << code_length) - 1ULL },
 | 
			
		||||
		maximum_hanning_distance_ { maximum_hanning_distance }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator()(const BitHistory& history, const size_t) const {
 | 
			
		||||
		const auto delta_bits = (history.value() ^ code_) & mask_;
 | 
			
		||||
		const size_t count = __builtin_popcountll(delta_bits);
 | 
			
		||||
		return (count <= maximum_hanning_distance_);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint64_t code_;
 | 
			
		||||
	uint64_t mask_;
 | 
			
		||||
	size_t maximum_hanning_distance_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__BIT_PATTERN_H__*/
 | 
			
		||||
							
								
								
									
										53
									
								
								Software/portapack-mayhem/firmware/common/bmp.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Software/portapack-mayhem/firmware/common/bmp.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
struct bmp_header_t {
 | 
			
		||||
	uint16_t signature;
 | 
			
		||||
	uint32_t size;
 | 
			
		||||
	uint16_t reserved_1;
 | 
			
		||||
	uint16_t reserved_2;
 | 
			
		||||
	uint32_t image_data;
 | 
			
		||||
	uint32_t BIH_size;
 | 
			
		||||
	uint32_t width;
 | 
			
		||||
	uint32_t height;
 | 
			
		||||
	uint16_t planes;
 | 
			
		||||
	uint16_t bpp;
 | 
			
		||||
	uint32_t compression;
 | 
			
		||||
	uint32_t data_size;
 | 
			
		||||
	uint32_t h_res;
 | 
			
		||||
	uint32_t v_res;
 | 
			
		||||
	uint32_t colors_count;
 | 
			
		||||
	uint32_t icolors_count;
 | 
			
		||||
};
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
struct bmp_palette_t {
 | 
			
		||||
	struct color_t {
 | 
			
		||||
		uint8_t B;
 | 
			
		||||
		uint8_t G;
 | 
			
		||||
		uint8_t R;
 | 
			
		||||
		uint8_t A;
 | 
			
		||||
	} color[16];
 | 
			
		||||
};
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
							
								
								
									
										36
									
								
								Software/portapack-mayhem/firmware/common/buffer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Software/portapack-mayhem/firmware/common/buffer.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "buffer.hpp"
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
#include "lpc43xx_m4.h"
 | 
			
		||||
 | 
			
		||||
Timestamp Timestamp::now() {
 | 
			
		||||
	// Code stolen from LPC43xx rtc_lld.c
 | 
			
		||||
	Timestamp timestamp;
 | 
			
		||||
    do {
 | 
			
		||||
		timestamp.tv_time = LPC_RTC->CTIME0;
 | 
			
		||||
		timestamp.tv_date = LPC_RTC->CTIME1;
 | 
			
		||||
    } while( (timestamp.tv_time != LPC_RTC->CTIME0) || (timestamp.tv_date != LPC_RTC->CTIME1) );
 | 
			
		||||
    return timestamp;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										91
									
								
								Software/portapack-mayhem/firmware/common/buffer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								Software/portapack-mayhem/firmware/common/buffer.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BUFFER_H__
 | 
			
		||||
#define __BUFFER_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
/* LPC43xx RTC structure. Avoiding using the ChibiOS-defined structure because
 | 
			
		||||
 * it pulls in all sorts of dependencies and initialization and other stuff that
 | 
			
		||||
 * the M0 needs to remain in control of.
 | 
			
		||||
 *
 | 
			
		||||
 * But yes, this is a hack, and something better is needed. It's too tangled of
 | 
			
		||||
 * a knot to tackle at the moment, though...
 | 
			
		||||
 */
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
struct Timestamp {
 | 
			
		||||
	uint32_t tv_date { 0 };
 | 
			
		||||
	uint32_t tv_time { 0 };
 | 
			
		||||
 | 
			
		||||
	static Timestamp now();
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M0)
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
 | 
			
		||||
using Timestamp = lpc43xx::rtc::RTC;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct buffer_t {
 | 
			
		||||
	T* const p;
 | 
			
		||||
	const size_t count;
 | 
			
		||||
	const uint32_t sampling_rate;
 | 
			
		||||
	const Timestamp timestamp;
 | 
			
		||||
 | 
			
		||||
	constexpr buffer_t(
 | 
			
		||||
	) : p { nullptr },
 | 
			
		||||
		count { 0 },
 | 
			
		||||
		sampling_rate { 0 },
 | 
			
		||||
		timestamp { }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr buffer_t(
 | 
			
		||||
		const buffer_t<T>& other
 | 
			
		||||
	) : p { other.p },
 | 
			
		||||
		count { other.count },
 | 
			
		||||
		sampling_rate { other.sampling_rate },
 | 
			
		||||
		timestamp { other.timestamp }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr buffer_t(
 | 
			
		||||
		T* const p,
 | 
			
		||||
		const size_t count,
 | 
			
		||||
		const uint32_t sampling_rate = 0,
 | 
			
		||||
		const Timestamp timestamp = { }
 | 
			
		||||
	) : p { p },
 | 
			
		||||
		count { count },
 | 
			
		||||
		sampling_rate { sampling_rate },
 | 
			
		||||
		timestamp { timestamp }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	operator bool() const {
 | 
			
		||||
		return (p != nullptr);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__BUFFER_H__*/
 | 
			
		||||
@@ -0,0 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "buffer_exchange.hpp"
 | 
			
		||||
 | 
			
		||||
BufferExchange* BufferExchange::obj { nullptr };
 | 
			
		||||
 | 
			
		||||
BufferExchange::BufferExchange(
 | 
			
		||||
	CaptureConfig* const config
 | 
			
		||||
)	// : config_capture { config }
 | 
			
		||||
{
 | 
			
		||||
	obj = this;
 | 
			
		||||
	// In capture mode, baseband wants empty buffers, app waits for full buffers
 | 
			
		||||
	fifo_buffers_for_baseband = config->fifo_buffers_empty;
 | 
			
		||||
	fifo_buffers_for_application = config->fifo_buffers_full;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BufferExchange::BufferExchange(
 | 
			
		||||
	ReplayConfig* const config
 | 
			
		||||
)	// : config_replay { config }
 | 
			
		||||
{
 | 
			
		||||
	obj = this;
 | 
			
		||||
	// In replay mode, baseband wants full buffers, app waits for empty buffers
 | 
			
		||||
	fifo_buffers_for_baseband = config->fifo_buffers_full;
 | 
			
		||||
	fifo_buffers_for_application = config->fifo_buffers_empty;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BufferExchange::~BufferExchange() {
 | 
			
		||||
	obj = nullptr;
 | 
			
		||||
	fifo_buffers_for_baseband = nullptr;
 | 
			
		||||
	fifo_buffers_for_application = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StreamBuffer* BufferExchange::get(FIFO<StreamBuffer*>* fifo) {
 | 
			
		||||
	while(true) {
 | 
			
		||||
		StreamBuffer* p { nullptr };
 | 
			
		||||
		fifo->out(p);
 | 
			
		||||
		
 | 
			
		||||
		if( p ) {
 | 
			
		||||
			return p;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Put thread to sleep, woken up by M4 IRQ
 | 
			
		||||
		chSysLock();
 | 
			
		||||
		thread = chThdSelf();
 | 
			
		||||
		chSchGoSleepS(THD_STATE_SUSPENDED);
 | 
			
		||||
		chSysUnlock();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StreamBuffer* BufferExchange::get_prefill(FIFO<StreamBuffer*>* fifo) {
 | 
			
		||||
	StreamBuffer* p { nullptr };
 | 
			
		||||
	fifo->out(p);
 | 
			
		||||
	
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										112
									
								
								Software/portapack-mayhem/firmware/common/buffer_exchange.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								Software/portapack-mayhem/firmware/common/buffer_exchange.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
#include "fifo.hpp"
 | 
			
		||||
#include "io.hpp"
 | 
			
		||||
 | 
			
		||||
class BufferExchange {
 | 
			
		||||
public:
 | 
			
		||||
	BufferExchange(CaptureConfig* const config);
 | 
			
		||||
	BufferExchange(ReplayConfig* const config);
 | 
			
		||||
	~BufferExchange();
 | 
			
		||||
 | 
			
		||||
	BufferExchange(const BufferExchange&) = delete;
 | 
			
		||||
	BufferExchange(BufferExchange&&) = delete;
 | 
			
		||||
	BufferExchange& operator=(const BufferExchange&) = delete;
 | 
			
		||||
	BufferExchange& operator=(BufferExchange&&) = delete;
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M0)
 | 
			
		||||
	bool empty() const {
 | 
			
		||||
		return fifo_buffers_for_application->is_empty();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	StreamBuffer* get() {
 | 
			
		||||
		return get(fifo_buffers_for_application);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	StreamBuffer* get_prefill() {
 | 
			
		||||
		return get_prefill(fifo_buffers_for_application);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool put(StreamBuffer* const p) {
 | 
			
		||||
		return fifo_buffers_for_baseband->in(p);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	bool put_app(StreamBuffer* const p) {
 | 
			
		||||
		return fifo_buffers_for_application->in(p);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
	bool empty() const {
 | 
			
		||||
		return fifo_buffers_for_baseband->is_empty();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	StreamBuffer* get() {
 | 
			
		||||
		return get(fifo_buffers_for_baseband);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool put(StreamBuffer* const p) {
 | 
			
		||||
		return fifo_buffers_for_application->in(p);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	static void handle_isr() {
 | 
			
		||||
		if( obj ) {
 | 
			
		||||
			obj->check_fifo_isr();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	//CaptureConfig* const config_capture;
 | 
			
		||||
	//ReplayConfig* const config_replay;
 | 
			
		||||
	FIFO<StreamBuffer*>* fifo_buffers_for_baseband { nullptr };
 | 
			
		||||
	FIFO<StreamBuffer*>* fifo_buffers_for_application { nullptr };
 | 
			
		||||
	Thread* thread { nullptr };
 | 
			
		||||
	static BufferExchange* obj;
 | 
			
		||||
	
 | 
			
		||||
	enum {
 | 
			
		||||
		CAPTURE,
 | 
			
		||||
		REPLAY
 | 
			
		||||
	} direction { };
 | 
			
		||||
 | 
			
		||||
	void check_fifo_isr() {
 | 
			
		||||
		if (!empty())
 | 
			
		||||
			wakeup_isr();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void wakeup_isr() {
 | 
			
		||||
		auto thread_tmp = thread;
 | 
			
		||||
		if( thread_tmp ) {
 | 
			
		||||
			thread = nullptr;
 | 
			
		||||
			chSchReadyI(thread_tmp);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	StreamBuffer* get(FIFO<StreamBuffer*>* fifo);
 | 
			
		||||
	
 | 
			
		||||
	StreamBuffer* get_prefill(FIFO<StreamBuffer*>* fifo);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										68
									
								
								Software/portapack-mayhem/firmware/common/chibios_cpp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Software/portapack-mayhem/firmware/common/chibios_cpp.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "chibios_cpp.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
 | 
			
		||||
void* operator new(size_t size) {
 | 
			
		||||
	return chHeapAlloc(0x0, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* operator new[](size_t size) {
 | 
			
		||||
	return chHeapAlloc(0x0, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void operator delete(void* p) noexcept {
 | 
			
		||||
	chHeapFree(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void operator delete[](void* p) noexcept {
 | 
			
		||||
	chHeapFree(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void operator delete(void* ptr, std::size_t) noexcept {
 | 
			
		||||
	::operator delete(ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void operator delete[](void* ptr, std::size_t) noexcept {
 | 
			
		||||
	::operator delete(ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern uint8_t __heap_base__[];
 | 
			
		||||
extern uint8_t __heap_end__[];
 | 
			
		||||
 | 
			
		||||
namespace chibios {
 | 
			
		||||
 | 
			
		||||
size_t heap_size() {
 | 
			
		||||
	return __heap_end__ - __heap_base__;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t heap_used() {
 | 
			
		||||
	const auto core_free = chCoreStatus();
 | 
			
		||||
	size_t heap_free = 0;
 | 
			
		||||
	chHeapStatus(NULL, &heap_free);
 | 
			
		||||
	return heap_size() - (core_free + heap_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace chibios */
 | 
			
		||||
							
								
								
									
										43
									
								
								Software/portapack-mayhem/firmware/common/chibios_cpp.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								Software/portapack-mayhem/firmware/common/chibios_cpp.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CHIBIOS_CPP_H__
 | 
			
		||||
#define __CHIBIOS_CPP_H__
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
/* Override new/delete to use Chibi/OS heap functions */
 | 
			
		||||
/* NOTE: Do not inline these, it doesn't work. ;-) */
 | 
			
		||||
void* operator new(size_t size);
 | 
			
		||||
void* operator new[](size_t size);
 | 
			
		||||
void operator delete(void* p);
 | 
			
		||||
void operator delete[](void* p);
 | 
			
		||||
void operator delete(void* ptr, std::size_t);
 | 
			
		||||
void operator delete[](void* ptr, std::size_t);
 | 
			
		||||
 | 
			
		||||
namespace chibios {
 | 
			
		||||
 | 
			
		||||
size_t heap_size();
 | 
			
		||||
size_t heap_used();
 | 
			
		||||
 | 
			
		||||
} /* namespace chibios */
 | 
			
		||||
 | 
			
		||||
#endif/*__CHIBIOS_CPP_H__*/
 | 
			
		||||
							
								
								
									
										139
									
								
								Software/portapack-mayhem/firmware/common/complex.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								Software/portapack-mayhem/firmware/common/complex.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __COMPLEX_H__
 | 
			
		||||
#define __COMPLEX_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <complex>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
constexpr float pi { 3.141592653589793238462643383279502884f };
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
 | 
			
		||||
template<> struct complex<int8_t> {
 | 
			
		||||
public:
 | 
			
		||||
	typedef int8_t value_type;
 | 
			
		||||
	typedef uint16_t rep_type;
 | 
			
		||||
 | 
			
		||||
	// constexpr complex(
 | 
			
		||||
	// 	rep_type r
 | 
			
		||||
	// ) : _rep { r }
 | 
			
		||||
	// {
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	constexpr complex(
 | 
			
		||||
		int8_t re = 0,
 | 
			
		||||
		int8_t im = 0
 | 
			
		||||
	) : _v { re, im }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// constexpr complex(
 | 
			
		||||
	// 	const complex& o
 | 
			
		||||
	// ) : _rep { o._rep }
 | 
			
		||||
	// {
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	constexpr int8_t real() const { return _v[0]; }
 | 
			
		||||
	constexpr int8_t imag() const { return _v[1]; }
 | 
			
		||||
 | 
			
		||||
	void real(int8_t v) { _v[0] = v; }
 | 
			
		||||
	void imag(int8_t v) { _v[1] = v; }
 | 
			
		||||
 | 
			
		||||
	constexpr uint16_t __rep() const {
 | 
			
		||||
		return _rep;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	union {
 | 
			
		||||
		value_type _v[2];
 | 
			
		||||
		rep_type _rep;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<> struct complex<int16_t> {
 | 
			
		||||
public:
 | 
			
		||||
	typedef int16_t value_type;
 | 
			
		||||
	typedef uint32_t rep_type;
 | 
			
		||||
 | 
			
		||||
	// constexpr complex(
 | 
			
		||||
	// 	rep_type r
 | 
			
		||||
	// ) : _rep { r }
 | 
			
		||||
	// {
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	constexpr complex(
 | 
			
		||||
		int16_t re = 0,
 | 
			
		||||
		int16_t im = 0
 | 
			
		||||
	) : _v { re, im }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// constexpr complex(
 | 
			
		||||
	// 	const complex& o
 | 
			
		||||
	// ) : _rep { o._rep }
 | 
			
		||||
	// {
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	constexpr int16_t real() const { return _v[0]; }
 | 
			
		||||
	constexpr int16_t imag() const { return _v[1]; }
 | 
			
		||||
 | 
			
		||||
	void real(int16_t v) { _v[0] = v; }
 | 
			
		||||
	void imag(int16_t v) { _v[1] = v; }
 | 
			
		||||
 | 
			
		||||
	template<class X>
 | 
			
		||||
	complex<int16_t>& operator+=(const complex<X>& other) {
 | 
			
		||||
		_v[0] += other.real();
 | 
			
		||||
		_v[1] += other.imag();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr uint32_t __rep() const {
 | 
			
		||||
		return _rep;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr operator std::complex<float>() const {
 | 
			
		||||
		return {
 | 
			
		||||
			static_cast<float>(_v[0]),
 | 
			
		||||
			static_cast<float>(_v[1])
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	union {
 | 
			
		||||
		value_type _v[2];
 | 
			
		||||
		rep_type _rep;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace std */
 | 
			
		||||
 | 
			
		||||
using complex8_t  = std::complex<int8_t>;
 | 
			
		||||
using complex16_t = std::complex<int16_t>;
 | 
			
		||||
using complex32_t = std::complex<int32_t>;
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(complex8_t) == 2, "complex8_t size wrong");
 | 
			
		||||
static_assert(sizeof(complex16_t) == 4, "complex16_t size wrong");
 | 
			
		||||
static_assert(sizeof(complex32_t) == 8, "complex32_t size wrong");
 | 
			
		||||
 | 
			
		||||
#endif/*__COMPLEX_H__*/
 | 
			
		||||
							
								
								
									
										274
									
								
								Software/portapack-mayhem/firmware/common/cpld_max5.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								Software/portapack-mayhem/firmware/common/cpld_max5.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,274 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cpld_max5.hpp"
 | 
			
		||||
 | 
			
		||||
#include "jtag.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
namespace cpld {
 | 
			
		||||
namespace max5 {
 | 
			
		||||
 | 
			
		||||
void CPLD::bypass() {
 | 
			
		||||
	shift_ir(instruction_t::BYPASS);
 | 
			
		||||
	jtag.runtest_tck(18003);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::sample() {
 | 
			
		||||
	shift_ir(instruction_t::SAMPLE);
 | 
			
		||||
	jtag.runtest_tck(93);
 | 
			
		||||
	for(size_t i=0; i<80; i++) {
 | 
			
		||||
		jtag.shift_dr(3, 0b111);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::sample(std::bitset<240>& value) {
 | 
			
		||||
	shift_ir(instruction_t::SAMPLE);
 | 
			
		||||
	jtag.runtest_tck(93);
 | 
			
		||||
	shift_dr(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::extest(std::bitset<240>& value) {
 | 
			
		||||
	shift_ir(instruction_t::EXTEST);
 | 
			
		||||
	shift_dr(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::clamp() {
 | 
			
		||||
	shift_ir(instruction_t::CLAMP);
 | 
			
		||||
	jtag.runtest_tck(93);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::enable() {
 | 
			
		||||
	shift_ir(instruction_t::ISC_ENABLE);
 | 
			
		||||
	jtag.runtest_tck(18003);		// 1ms
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::disable() {
 | 
			
		||||
	shift_ir(instruction_t::ISC_DISABLE);
 | 
			
		||||
	jtag.runtest_tck(18003);		// 1ms
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sector erase:
 | 
			
		||||
 * Involves shifting in the instruction to erase the device and applying
 | 
			
		||||
 * an erase pulse or pulses. The erase pulse is automatically generated
 | 
			
		||||
 * internally by waiting in the run, test, or idle state for the
 | 
			
		||||
 * specified erase pulse time of 500 ms for the CFM block and 500 ms for
 | 
			
		||||
 * each sector of the user flash memory (UFM) block.
 | 
			
		||||
 */
 | 
			
		||||
void CPLD::bulk_erase() {
 | 
			
		||||
	erase_sector(0x0011);
 | 
			
		||||
	erase_sector(0x0001);
 | 
			
		||||
	erase_sector(0x0000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPLD::program(
 | 
			
		||||
	const std::array<uint16_t, 3328>& block_0,
 | 
			
		||||
	const std::array<uint16_t, 512>& block_1
 | 
			
		||||
) {
 | 
			
		||||
	bulk_erase();
 | 
			
		||||
 | 
			
		||||
	/* Program:
 | 
			
		||||
	 * involves shifting in the address, data, and program instruction and
 | 
			
		||||
	 * generating the program pulse to program the flash cells. The program
 | 
			
		||||
	 * pulse is automatically generated internally by waiting in the run/test/
 | 
			
		||||
	 * idle state for the specified program pulse time of 75 μs. This process
 | 
			
		||||
	 * is repeated for each address in the CFM and UFM blocks.
 | 
			
		||||
	 */
 | 
			
		||||
	program_block(0x0000, block_0);
 | 
			
		||||
	program_block(0x0001, block_1);
 | 
			
		||||
 | 
			
		||||
	const auto verify_ok = verify(block_0, block_1);
 | 
			
		||||
 | 
			
		||||
	if( verify_ok ) {
 | 
			
		||||
		/* Do "something". Not sure what, but it happens after verify. */
 | 
			
		||||
		/* Starts with a sequence the same as Program: Block 0. */
 | 
			
		||||
		/* Perhaps it is a write to tell the CPLD that the bitstream
 | 
			
		||||
		 * verified OK, and it's OK to load and execute? And despite only
 | 
			
		||||
		 * one bit changing, a write must be a multiple of a particular
 | 
			
		||||
		 * length (64 bits)? */
 | 
			
		||||
		sector_select(0x0000);
 | 
			
		||||
		shift_ir(instruction_t::ISC_PROGRAM);
 | 
			
		||||
		jtag.runtest_tck(93);		// 5 us
 | 
			
		||||
 | 
			
		||||
		/* TODO: Use data from cpld_block_0, with appropriate bit(s) changed */
 | 
			
		||||
		/* Perhaps this is the "ISP_DONE" bit? */
 | 
			
		||||
		jtag.shift_dr(16, block_0[0] & 0xfbff);
 | 
			
		||||
		jtag.runtest_tck(1800);		// 100us
 | 
			
		||||
		jtag.shift_dr(16, block_0[1]);
 | 
			
		||||
		jtag.runtest_tck(1800);		// 100us
 | 
			
		||||
		jtag.shift_dr(16, block_0[2]);
 | 
			
		||||
		jtag.runtest_tck(1800);		// 100us
 | 
			
		||||
		jtag.shift_dr(16, block_0[3]);
 | 
			
		||||
		jtag.runtest_tck(1800);		// 100us
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return verify_ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPLD::verify(
 | 
			
		||||
	const std::array<uint16_t, 3328>& block_0,
 | 
			
		||||
	const std::array<uint16_t, 512>& block_1
 | 
			
		||||
) {
 | 
			
		||||
	/* Verify */
 | 
			
		||||
	const auto block_0_success = verify_block(0x0000, block_0);
 | 
			
		||||
	const auto block_1_success = verify_block(0x0001, block_1);
 | 
			
		||||
	return block_0_success && block_1_success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t CPLD::crc() {
 | 
			
		||||
	crc_t crc { 0x04c11db7, 0xffffffff, 0xffffffff };
 | 
			
		||||
	block_crc(0, 3328, crc);
 | 
			
		||||
	block_crc(1,  512, crc);
 | 
			
		||||
	return crc.checksum();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::sector_select(const uint16_t id) {
 | 
			
		||||
	shift_ir(instruction_t::ISC_ADDRESS_SHIFT);
 | 
			
		||||
	jtag.runtest_tck(93);		// 5us
 | 
			
		||||
	jtag.shift_dr(13, id);		// Sector ID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPLD::idcode_ok() {
 | 
			
		||||
	shift_ir(instruction_t::IDCODE);
 | 
			
		||||
	const auto idcode_read = jtag.shift_dr(idcode_length, 0);
 | 
			
		||||
	return (idcode_read == idcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::array<uint16_t, 5> CPLD::read_silicon_id() {
 | 
			
		||||
	sector_select(0x0089);
 | 
			
		||||
	shift_ir(instruction_t::ISC_READ);
 | 
			
		||||
	jtag.runtest_tck(93);		// 5us
 | 
			
		||||
 | 
			
		||||
	std::array<uint16_t, 5> silicon_id;
 | 
			
		||||
	silicon_id[0] = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
	silicon_id[1] = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
	silicon_id[2] = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
	silicon_id[3] = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
	silicon_id[4] = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
	return silicon_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check ID:
 | 
			
		||||
 * The silicon ID is checked before any Program or Verify process. The
 | 
			
		||||
 * time required to read this silicon ID is relatively small compared to
 | 
			
		||||
 * the overall programming time.
 | 
			
		||||
 */
 | 
			
		||||
bool CPLD::silicon_id_ok() {
 | 
			
		||||
	const auto silicon_id = read_silicon_id();
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		(silicon_id[0] == 0x8232) &&
 | 
			
		||||
		(silicon_id[1] == 0x2aa2) &&
 | 
			
		||||
		(silicon_id[2] == 0x4a82) &&
 | 
			
		||||
		(silicon_id[3] == 0x8c0c) &&
 | 
			
		||||
		(silicon_id[4] == 0x0000)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t CPLD::usercode() {
 | 
			
		||||
	shift_ir(instruction_t::USERCODE);
 | 
			
		||||
	jtag.runtest_tck(93);	// 5us
 | 
			
		||||
	return jtag.shift_dr(32, 0xffffffff);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::erase_sector(const uint16_t id) {
 | 
			
		||||
	sector_select(id);
 | 
			
		||||
	shift_ir(instruction_t::ISC_ERASE);
 | 
			
		||||
	jtag.runtest_tck(9000003);	// 500ms
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::program_block(
 | 
			
		||||
	const uint16_t id,
 | 
			
		||||
	const uint16_t* const data,
 | 
			
		||||
	const size_t count
 | 
			
		||||
) {
 | 
			
		||||
	sector_select(id);
 | 
			
		||||
	shift_ir(instruction_t::ISC_PROGRAM);
 | 
			
		||||
	jtag.runtest_tck(93);		// 5us
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		jtag.shift_dr(16, data[i]);
 | 
			
		||||
		jtag.runtest_tck(1800);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPLD::verify_block(
 | 
			
		||||
	const uint16_t id,
 | 
			
		||||
	const uint16_t* const data,
 | 
			
		||||
	const size_t count
 | 
			
		||||
) {
 | 
			
		||||
	sector_select(id);
 | 
			
		||||
	shift_ir(instruction_t::ISC_READ);
 | 
			
		||||
	jtag.runtest_tck(93);		// 5us
 | 
			
		||||
 | 
			
		||||
	bool success = true;
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const auto from_device = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
		if( from_device != data[i] ) {
 | 
			
		||||
			if( (id == 0) && (i == 0) ) {
 | 
			
		||||
				// Account for bit that indicates bitstream is valid.
 | 
			
		||||
				if( (from_device & 0xfbff) != (data[i] & 0xfbff) ) {
 | 
			
		||||
					success = false;
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				success = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPLD::is_blank_block(const uint16_t id, const size_t count) {
 | 
			
		||||
	sector_select(id);
 | 
			
		||||
	shift_ir(instruction_t::ISC_READ);
 | 
			
		||||
	jtag.runtest_tck(93);		// 5us
 | 
			
		||||
 | 
			
		||||
	bool success = true;
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const auto from_device = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
		if( from_device != 0xffff ) {
 | 
			
		||||
			success = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPLD::block_crc(const uint16_t id, const size_t count, crc_t& crc) {
 | 
			
		||||
	sector_select(id);
 | 
			
		||||
	shift_ir(instruction_t::ISC_READ);
 | 
			
		||||
	jtag.runtest_tck(93);		// 5us
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const uint16_t from_device = jtag.shift_dr(16, 0xffff);
 | 
			
		||||
		crc.process_bytes(&from_device, sizeof(from_device));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPLD::is_blank() {
 | 
			
		||||
	const auto block_0_blank = is_blank_block(0x0000, 3328);
 | 
			
		||||
	const auto block_1_blank = is_blank_block(0x0001, 512);
 | 
			
		||||
	return block_0_blank && block_1_blank;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace max5 */
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
							
								
								
									
										203
									
								
								Software/portapack-mayhem/firmware/common/cpld_max5.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								Software/portapack-mayhem/firmware/common/cpld_max5.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CPLD_MAX5_H__
 | 
			
		||||
#define __CPLD_MAX5_H__
 | 
			
		||||
 | 
			
		||||
#include "jtag.hpp"
 | 
			
		||||
#include "crc.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
namespace cpld {
 | 
			
		||||
namespace max5 {
 | 
			
		||||
 | 
			
		||||
struct Config {
 | 
			
		||||
	const std::array<uint16_t, 3328>& block_0;
 | 
			
		||||
	const std::array<uint16_t,  512>& block_1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CPLD {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr CPLD(
 | 
			
		||||
		jtag::JTAG& jtag
 | 
			
		||||
	) : jtag(jtag)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void bypass();
 | 
			
		||||
	void sample();
 | 
			
		||||
	void sample(std::bitset<240>& value);
 | 
			
		||||
	void extest(std::bitset<240>& value);
 | 
			
		||||
	void clamp();
 | 
			
		||||
 | 
			
		||||
	void reset() {
 | 
			
		||||
		jtag.reset();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void run_test_idle() {
 | 
			
		||||
		jtag.run_test_idle();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool idcode_ok();
 | 
			
		||||
 | 
			
		||||
	void enable();
 | 
			
		||||
 | 
			
		||||
	/* Check ID:
 | 
			
		||||
	 * The silicon ID is checked before any Program or Verify process. The
 | 
			
		||||
	 * time required to read this silicon ID is relatively small compared to
 | 
			
		||||
	 * the overall programming time.
 | 
			
		||||
	 */
 | 
			
		||||
	bool silicon_id_ok();
 | 
			
		||||
 | 
			
		||||
	uint32_t usercode();
 | 
			
		||||
 | 
			
		||||
	void disable();
 | 
			
		||||
 | 
			
		||||
	void bulk_erase();
 | 
			
		||||
 | 
			
		||||
	bool program(
 | 
			
		||||
		const std::array<uint16_t, 3328>& block_0,
 | 
			
		||||
		const std::array<uint16_t, 512>& block_1
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	bool verify(
 | 
			
		||||
		const std::array<uint16_t, 3328>& block_0,
 | 
			
		||||
		const std::array<uint16_t, 512>& block_1
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	bool is_blank();
 | 
			
		||||
 | 
			
		||||
	uint32_t crc();
 | 
			
		||||
 | 
			
		||||
	std::pair<bool, uint8_t> boundary_scan();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	using idcode_t = uint32_t;
 | 
			
		||||
	static constexpr size_t idcode_length = 32;
 | 
			
		||||
	static constexpr idcode_t idcode      = 0b00000010000010100101000011011101;
 | 
			
		||||
	static constexpr idcode_t idcode_mask = 0b11111111111111111111111111111111;
 | 
			
		||||
	
 | 
			
		||||
	static constexpr size_t ir_length = 10;
 | 
			
		||||
 | 
			
		||||
	using ir_t = uint16_t;
 | 
			
		||||
 | 
			
		||||
	enum class instruction_t : ir_t {
 | 
			
		||||
		BYPASS            = 0b1111111111, // 0x3ff
 | 
			
		||||
		EXTEST            = 0b0000001111, // 0x00f
 | 
			
		||||
		SAMPLE            = 0b0000000101, // 0x005
 | 
			
		||||
		IDCODE            = 0b0000000110, // 0x006
 | 
			
		||||
		USERCODE          = 0b0000000111, // 0x007
 | 
			
		||||
		CLAMP             = 0b0000001010, // 0x00a
 | 
			
		||||
		HIGHZ             = 0b0000001011, // 0x00b
 | 
			
		||||
		ISC_ENABLE        = 0b1011001100, // 0x2cc
 | 
			
		||||
		ISC_DISABLE       = 0b1000000001, // 0x201
 | 
			
		||||
		ISC_PROGRAM       = 0b1011110100, // 0x2f4
 | 
			
		||||
		ISC_ERASE         = 0b1011110010, // 0x2f2
 | 
			
		||||
		ISC_ADDRESS_SHIFT = 0b1000000011, // 0x203
 | 
			
		||||
		ISC_READ          = 0b1000000101, // 0x205
 | 
			
		||||
		ISC_NOOP          = 0b1000010000, // 0x210
 | 
			
		||||
 	};
 | 
			
		||||
 | 
			
		||||
	void shift_ir(const instruction_t instruction) {
 | 
			
		||||
		shift_ir(static_cast<ir_t>(instruction));
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void shift_ir(const uint32_t value) {
 | 
			
		||||
		jtag.shift_ir(ir_length, value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void shift_dr(std::bitset<240>& value) {
 | 
			
		||||
		for(size_t i=0; i<value.size(); i++) {
 | 
			
		||||
			value[i] = shift_dr(1, value[i]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t shift_dr(const size_t count, const uint32_t value) {
 | 
			
		||||
		return jtag.shift_dr(count, value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jtag::JTAG& jtag;
 | 
			
		||||
 | 
			
		||||
	std::array<uint16_t, 5> read_silicon_id();
 | 
			
		||||
 | 
			
		||||
	void sector_select(const uint16_t id);
 | 
			
		||||
 | 
			
		||||
	void erase_sector(const uint16_t id);
 | 
			
		||||
 | 
			
		||||
	void program_block(
 | 
			
		||||
		const uint16_t id,
 | 
			
		||||
		const uint16_t* const data,
 | 
			
		||||
		const size_t count
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	template<size_t N>
 | 
			
		||||
	void program_block(
 | 
			
		||||
		const uint16_t id,
 | 
			
		||||
		const std::array<uint16_t, N>& data
 | 
			
		||||
	) {
 | 
			
		||||
		program_block(id, data.data(), data.size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool verify_block(
 | 
			
		||||
		const uint16_t id,
 | 
			
		||||
		const uint16_t* const data,
 | 
			
		||||
		const size_t count
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	template<size_t N>
 | 
			
		||||
	bool verify_block(
 | 
			
		||||
		const uint16_t id,
 | 
			
		||||
		const std::array<uint16_t, N>& data
 | 
			
		||||
	) {
 | 
			
		||||
		return verify_block(id, data.data(), data.size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_blank_block(const uint16_t id, const size_t count);
 | 
			
		||||
 | 
			
		||||
	using crc_t = CRC<32, true, true>;
 | 
			
		||||
	void block_crc(const uint16_t id, const size_t count, crc_t& crc);
 | 
			
		||||
};
 | 
			
		||||
/*
 | 
			
		||||
class ModeISP {
 | 
			
		||||
public:
 | 
			
		||||
	ModeISP(
 | 
			
		||||
		CPLD& cpld
 | 
			
		||||
	) : cpld(cpld)
 | 
			
		||||
	{
 | 
			
		||||
		cpld.enter_isp();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~ModeISP() {
 | 
			
		||||
		cpld.exit_isp();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	CPLD& cpld;
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
} /* namespace max5 */
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
 | 
			
		||||
#endif/*__CPLD_MAX5_H__*/
 | 
			
		||||
							
								
								
									
										134
									
								
								Software/portapack-mayhem/firmware/common/cpld_update.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								Software/portapack-mayhem/firmware/common/cpld_update.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cpld_update.hpp"
 | 
			
		||||
 | 
			
		||||
#include "hackrf_gpio.hpp"
 | 
			
		||||
#include "portapack_hal.hpp"
 | 
			
		||||
 | 
			
		||||
#include "jtag_target_gpio.hpp"
 | 
			
		||||
#include "cpld_max5.hpp"
 | 
			
		||||
#include "cpld_xilinx.hpp"
 | 
			
		||||
#include "portapack_cpld_data.hpp"
 | 
			
		||||
#include "hackrf_cpld_data.hpp"
 | 
			
		||||
 | 
			
		||||
namespace portapack {
 | 
			
		||||
namespace cpld {
 | 
			
		||||
 | 
			
		||||
bool update_if_necessary(
 | 
			
		||||
	const Config config
 | 
			
		||||
) {
 | 
			
		||||
	jtag::GPIOTarget target {
 | 
			
		||||
		portapack::gpio_cpld_tck,
 | 
			
		||||
		portapack::gpio_cpld_tms,
 | 
			
		||||
		portapack::gpio_cpld_tdi,
 | 
			
		||||
		portapack::gpio_cpld_tdo
 | 
			
		||||
	};
 | 
			
		||||
	jtag::JTAG jtag { target };
 | 
			
		||||
	CPLD cpld { jtag };
 | 
			
		||||
 | 
			
		||||
	/* Unknown state */
 | 
			
		||||
	cpld.reset();
 | 
			
		||||
	cpld.run_test_idle();
 | 
			
		||||
 | 
			
		||||
	/* Run-Test/Idle */
 | 
			
		||||
	if( !cpld.idcode_ok() ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cpld.sample();
 | 
			
		||||
	cpld.bypass();
 | 
			
		||||
	cpld.enable();
 | 
			
		||||
 | 
			
		||||
	/* If silicon ID doesn't match, there's a serious problem. Leave CPLD
 | 
			
		||||
	 * in passive state.
 | 
			
		||||
	 */
 | 
			
		||||
	if( !cpld.silicon_id_ok() ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Verify CPLD contents against current bitstream. */
 | 
			
		||||
	auto ok = cpld.verify(config.block_0, config.block_1);
 | 
			
		||||
 | 
			
		||||
	/* CPLD verifies incorrectly. Erase and program with current bitstream. */
 | 
			
		||||
	if( !ok ) {
 | 
			
		||||
		ok = cpld.program(config.block_0, config.block_1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If programming OK, reset CPLD to user mode. Otherwise leave it in
 | 
			
		||||
	 * passive (ISP) state.
 | 
			
		||||
	 */
 | 
			
		||||
	if( ok ) {
 | 
			
		||||
		cpld.disable();
 | 
			
		||||
		cpld.bypass();
 | 
			
		||||
 | 
			
		||||
		/* Initiate SRAM reload from flash we just programmed. */
 | 
			
		||||
		cpld.sample();
 | 
			
		||||
		cpld.clamp();
 | 
			
		||||
		cpld.disable();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
} /* namespace portapack */
 | 
			
		||||
 | 
			
		||||
namespace hackrf {
 | 
			
		||||
namespace cpld {
 | 
			
		||||
 | 
			
		||||
static jtag::GPIOTarget jtag_target_hackrf() {
 | 
			
		||||
	return {
 | 
			
		||||
		hackrf::one::gpio_cpld_tck,
 | 
			
		||||
		hackrf::one::gpio_cpld_tms,
 | 
			
		||||
		hackrf::one::gpio_cpld_tdi,
 | 
			
		||||
		hackrf::one::gpio_cpld_tdo,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool load_sram() {
 | 
			
		||||
	auto jtag_target_hackrf_cpld = jtag_target_hackrf();
 | 
			
		||||
	hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
 | 
			
		||||
 | 
			
		||||
	hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
 | 
			
		||||
	const auto ok = hackrf_cpld.verify_sram(hackrf::one::cpld::verify_blocks);
 | 
			
		||||
 | 
			
		||||
	return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool verify_eeprom() {
 | 
			
		||||
	auto jtag_target_hackrf_cpld = jtag_target_hackrf();
 | 
			
		||||
	hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
 | 
			
		||||
 | 
			
		||||
	const auto ok = hackrf_cpld.verify_eeprom(hackrf::one::cpld::verify_blocks);
 | 
			
		||||
	
 | 
			
		||||
	return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void init_from_eeprom() {
 | 
			
		||||
	auto jtag_target_hackrf_cpld = jtag_target_hackrf();
 | 
			
		||||
	hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
 | 
			
		||||
 | 
			
		||||
	hackrf_cpld.init_from_eeprom();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
} /* namespace hackrf */
 | 
			
		||||
							
								
								
									
										47
									
								
								Software/portapack-mayhem/firmware/common/cpld_update.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Software/portapack-mayhem/firmware/common/cpld_update.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CPLD_UPDATE_H__
 | 
			
		||||
#define __CPLD_UPDATE_H__
 | 
			
		||||
 | 
			
		||||
#include "portapack_cpld_data.hpp"
 | 
			
		||||
 | 
			
		||||
namespace portapack {
 | 
			
		||||
namespace cpld {
 | 
			
		||||
 | 
			
		||||
bool update_if_necessary(
 | 
			
		||||
	const Config config
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
} /* namespace portapack */
 | 
			
		||||
 | 
			
		||||
namespace hackrf {
 | 
			
		||||
namespace cpld {
 | 
			
		||||
 | 
			
		||||
bool load_sram();
 | 
			
		||||
bool verify_eeprom();
 | 
			
		||||
void init_from_eeprom();
 | 
			
		||||
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
} /* namespace hackrf */
 | 
			
		||||
 | 
			
		||||
#endif/*__CPLD_UPDATE_H__*/
 | 
			
		||||
							
								
								
									
										179
									
								
								Software/portapack-mayhem/firmware/common/cpld_xilinx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								Software/portapack-mayhem/firmware/common/cpld_xilinx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cpld_xilinx.hpp"
 | 
			
		||||
 | 
			
		||||
namespace cpld {
 | 
			
		||||
namespace xilinx {
 | 
			
		||||
 | 
			
		||||
void XC2C64A::write_sram(const verify_blocks_t& blocks) {
 | 
			
		||||
	tap.set_repeat(0);
 | 
			
		||||
	tap.set_end_ir(state_t::run_test_idle);
 | 
			
		||||
	tap.set_end_dr(state_t::run_test_idle);
 | 
			
		||||
 | 
			
		||||
	reset();
 | 
			
		||||
	enable();
 | 
			
		||||
 | 
			
		||||
	shift_ir(instruction_t::ISC_WRITE);
 | 
			
		||||
	for(const auto& block : blocks) {
 | 
			
		||||
		tap.state(state_t::shift_dr);
 | 
			
		||||
		tap.shift({ block.data.data(), block_length }, false);
 | 
			
		||||
		tap.shift({ &block.id, block_id_length }, true);
 | 
			
		||||
		tap.state(state_t::run_test_idle);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disable();
 | 
			
		||||
	bypass();
 | 
			
		||||
 | 
			
		||||
	tap.state(state_t::test_logic_reset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XC2C64A::verify_sram(const verify_blocks_t& blocks) {
 | 
			
		||||
	tap.set_repeat(0);
 | 
			
		||||
	tap.set_end_ir(state_t::run_test_idle);
 | 
			
		||||
	tap.set_end_dr(state_t::run_test_idle);
 | 
			
		||||
 | 
			
		||||
	reset();
 | 
			
		||||
	enable();
 | 
			
		||||
 | 
			
		||||
	shift_ir(instruction_t::ISC_SRAM_READ);
 | 
			
		||||
 | 
			
		||||
	// Prime the operation with a read of an empty row.
 | 
			
		||||
	const jtag::tap::bits_t empty_row { block_length };
 | 
			
		||||
 | 
			
		||||
	tap.state(state_t::shift_dr);
 | 
			
		||||
	tap.shift(empty_row, false);
 | 
			
		||||
	
 | 
			
		||||
	auto error = false;
 | 
			
		||||
	for(const auto& block : blocks) {
 | 
			
		||||
		tap.shift({ &block.id, block_id_length }, true);
 | 
			
		||||
		tap.state(state_t::run_test_idle);
 | 
			
		||||
		
 | 
			
		||||
		tap.state(state_t::shift_dr);
 | 
			
		||||
		error |= tap.shift(empty_row, { block.data.data(), block_length }, { block.mask.data(), block_length }, false);
 | 
			
		||||
	}
 | 
			
		||||
	// Redundant operation to finish the row.
 | 
			
		||||
	tap.shift({ &blocks[0].id, block_id_length }, true);
 | 
			
		||||
	tap.state(state_t::run_test_idle);
 | 
			
		||||
	tap.set_end_dr(state_t::run_test_idle);
 | 
			
		||||
 | 
			
		||||
	disable();
 | 
			
		||||
	bypass();
 | 
			
		||||
 | 
			
		||||
	tap.state(state_t::test_logic_reset);
 | 
			
		||||
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XC2C64A::verify_eeprom(const verify_blocks_t& blocks) {
 | 
			
		||||
	tap.set_repeat(0);
 | 
			
		||||
	tap.set_end_ir(state_t::run_test_idle);
 | 
			
		||||
	tap.set_end_dr(state_t::run_test_idle);
 | 
			
		||||
 | 
			
		||||
	reset();
 | 
			
		||||
	bypass();
 | 
			
		||||
	enable();
 | 
			
		||||
 | 
			
		||||
	shift_ir(instruction_t::ISC_READ);
 | 
			
		||||
 | 
			
		||||
	const jtag::tap::bits_t empty_row { block_length };
 | 
			
		||||
 | 
			
		||||
	auto error = false;
 | 
			
		||||
	for(const auto& block : blocks) {
 | 
			
		||||
		tap.set_end_dr(state_t::pause_dr);
 | 
			
		||||
		tap.shift_dr({ &block.id, block_id_length });
 | 
			
		||||
		tap.set_end_ir(state_t::run_test_idle);
 | 
			
		||||
		tap.wait(state_t::pause_dr, state_t::pause_dr, 20);
 | 
			
		||||
		tap.set_end_ir(state_t::run_test_idle);
 | 
			
		||||
		tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
 | 
			
		||||
		error |= tap.shift_dr(empty_row, { block.data.data(), block_length }, { block.mask.data(), block_length });
 | 
			
		||||
		tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disable();
 | 
			
		||||
	bypass();
 | 
			
		||||
 | 
			
		||||
	tap.state(state_t::test_logic_reset);
 | 
			
		||||
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XC2C64A::init_from_eeprom() {
 | 
			
		||||
	tap.set_repeat(0);
 | 
			
		||||
	tap.set_end_ir(state_t::run_test_idle);
 | 
			
		||||
	tap.set_end_dr(state_t::run_test_idle);
 | 
			
		||||
 | 
			
		||||
	reset();
 | 
			
		||||
	enable();
 | 
			
		||||
 | 
			
		||||
	discharge();
 | 
			
		||||
	init();
 | 
			
		||||
	
 | 
			
		||||
	disable();
 | 
			
		||||
	bypass();
 | 
			
		||||
 | 
			
		||||
	tap.state(state_t::test_logic_reset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XC2C64A::shift_ir(const instruction_t instruction) {
 | 
			
		||||
	const ir_t ir_buffer = toUType(instruction);
 | 
			
		||||
	const jtag::tap::bits_t bits { &ir_buffer, ir_length };
 | 
			
		||||
	return tap.shift_ir(bits);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XC2C64A::reset() {
 | 
			
		||||
	tap.state(state_t::test_logic_reset);
 | 
			
		||||
	tap.state(state_t::run_test_idle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XC2C64A::enable() {
 | 
			
		||||
	shift_ir(instruction_t::ISC_ENABLE);
 | 
			
		||||
	tap.wait(state_t::run_test_idle, state_t::run_test_idle, 800);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XC2C64A::enable_otf() {
 | 
			
		||||
	shift_ir(instruction_t::ISC_ENABLE_OTF);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XC2C64A::discharge() {
 | 
			
		||||
	shift_ir(instruction_t::ISC_INIT);
 | 
			
		||||
	tap.wait(state_t::run_test_idle, state_t::run_test_idle, 20);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XC2C64A::init() {
 | 
			
		||||
	tap.set_end_ir(state_t::update_ir);
 | 
			
		||||
	shift_ir(instruction_t::ISC_INIT);
 | 
			
		||||
	tap.set_end_ir(state_t::run_test_idle);
 | 
			
		||||
	tap.state(state_t::capture_dr);
 | 
			
		||||
	tap.wait(state_t::run_test_idle, state_t::run_test_idle, 800);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XC2C64A::disable() {
 | 
			
		||||
	shift_ir(instruction_t::ISC_DISABLE);
 | 
			
		||||
	tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XC2C64A::bypass() {
 | 
			
		||||
	return shift_ir(instruction_t::BYPASS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace xilinx */
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
							
								
								
									
										126
									
								
								Software/portapack-mayhem/firmware/common/cpld_xilinx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								Software/portapack-mayhem/firmware/common/cpld_xilinx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CPLD_XILINX_H__
 | 
			
		||||
#define __CPLD_XILINX_H__
 | 
			
		||||
 | 
			
		||||
#include "jtag_tap.hpp"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
namespace cpld {
 | 
			
		||||
namespace xilinx {
 | 
			
		||||
 | 
			
		||||
using jtag::tap::state_t;
 | 
			
		||||
 | 
			
		||||
class XC2C64A {
 | 
			
		||||
public:
 | 
			
		||||
	using block_id_t = uint8_t;
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t block_length  = 274;
 | 
			
		||||
	static constexpr size_t blocks_count = 98;
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t block_bytes = (block_length + 7) >> 3;
 | 
			
		||||
 | 
			
		||||
	struct verify_block_t {
 | 
			
		||||
		block_id_t id;
 | 
			
		||||
		std::array<uint8_t, block_bytes> data;
 | 
			
		||||
		std::array<uint8_t, block_bytes> mask;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct program_block_t {
 | 
			
		||||
		block_id_t id;
 | 
			
		||||
		std::array<uint8_t, block_bytes> data;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	using verify_blocks_t = std::array<verify_block_t, blocks_count>;
 | 
			
		||||
 | 
			
		||||
	constexpr XC2C64A(
 | 
			
		||||
		jtag::Target& jtag_interface
 | 
			
		||||
	) : tap { jtag_interface }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void write_sram(const verify_blocks_t& blocks);
 | 
			
		||||
	bool verify_sram(const verify_blocks_t& blocks);
 | 
			
		||||
 | 
			
		||||
	bool verify_eeprom(const verify_blocks_t& blocks);
 | 
			
		||||
	void init_from_eeprom();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t idcode_length = 32;
 | 
			
		||||
	using idcode_t = uint32_t;
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t ir_length = 8;
 | 
			
		||||
	static constexpr size_t block_id_length = 7;
 | 
			
		||||
 | 
			
		||||
	static constexpr idcode_t idcode      = 0x06e58093;
 | 
			
		||||
	static constexpr idcode_t idcode_mask = 0x0fff8fff;
 | 
			
		||||
 | 
			
		||||
	using ir_t = uint8_t;
 | 
			
		||||
 | 
			
		||||
	jtag::tap::TAPMachine tap;
 | 
			
		||||
 | 
			
		||||
	enum class instruction_t : ir_t {
 | 
			
		||||
		INTEST           = 0b00000010,	// -> boundary-scan
 | 
			
		||||
		BYPASS           = 0b11111111,	// -> bypass
 | 
			
		||||
		SAMPLE           = 0b00000011,	// -> boundary-scan
 | 
			
		||||
		EXTEST           = 0b00000000,	// -> boundary-scan
 | 
			
		||||
		IDCODE           = 0b00000001,	// -> device ID
 | 
			
		||||
		USERCODE         = 0b11111101,	// -> device ID
 | 
			
		||||
		HIGHZ            = 0b11111100,	// -> bypass
 | 
			
		||||
		ISC_ENABLE_CLAMP = 0b11101001,	// -> ISC shift
 | 
			
		||||
		ISC_ENABLE_OTF   = 0b11100100,	// -> ISC shift
 | 
			
		||||
		ISC_ENABLE       = 0b11101000,	// -> ISC shift
 | 
			
		||||
		ISC_SRAM_READ    = 0b11100111,	// -> ISC shift
 | 
			
		||||
		ISC_WRITE        = 0b11100110,	// -> ISC shift, alias ISC_SRAM_WRITE
 | 
			
		||||
		ISC_ERASE        = 0b11101101,	// -> ISC shift
 | 
			
		||||
		ISC_PROGRAM      = 0b11101010,	// -> ISC shift
 | 
			
		||||
		ISC_READ         = 0b11101110,	// -> ISC shift, alias ISC_VERIFY
 | 
			
		||||
		ISC_INIT         = 0b11110000,	// -> ISC shift
 | 
			
		||||
		ISC_DISABLE      = 0b11000000,	// -> ISC shift
 | 
			
		||||
		TEST_ENABLE      = 0b00010001,	// alias Private1
 | 
			
		||||
		BULKPROG         = 0b00010010,	// alias Private2
 | 
			
		||||
		ERASE_ALL        = 0b00010100,	// alias Private4
 | 
			
		||||
		MVERIFY          = 0b00010011,	// alias Private3
 | 
			
		||||
		TEST_DISABLE     = 0b00010101,	// alias Private5
 | 
			
		||||
		ISC_NOOP         = 0b11100000,	// -> bypass
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	bool shift_ir(const instruction_t instruction);
 | 
			
		||||
 | 
			
		||||
	void reset();
 | 
			
		||||
	void enable();
 | 
			
		||||
	void enable_otf();
 | 
			
		||||
	void discharge();
 | 
			
		||||
	void init();
 | 
			
		||||
	void disable();
 | 
			
		||||
	bool bypass();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace xilinx */
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
 | 
			
		||||
#endif/*__CPLD_XILINX_H__*/
 | 
			
		||||
							
								
								
									
										195
									
								
								Software/portapack-mayhem/firmware/common/crc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								Software/portapack-mayhem/firmware/common/crc.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,195 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CRC_H__
 | 
			
		||||
#define __CRC_H__
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
/* Inspired by
 | 
			
		||||
 * http://www.barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
 | 
			
		||||
 *
 | 
			
		||||
 * ...then munged into a simplified implementation of boost::crc_basic and
 | 
			
		||||
 * boost::crc_optimal.
 | 
			
		||||
 * http://www.boost.org/doc/libs/release/libs/crc/
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright 2001, 2004 Daryle Walker.  Use, modification, and distribution are
 | 
			
		||||
 *  subject to the Boost Software License, Version 1.0.  (See accompanying file
 | 
			
		||||
 *  LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
template<size_t Width, bool RevIn = false, bool RevOut = false>
 | 
			
		||||
class CRC {
 | 
			
		||||
public:
 | 
			
		||||
	using value_type = uint32_t;
 | 
			
		||||
 | 
			
		||||
	constexpr CRC(
 | 
			
		||||
		const value_type truncated_polynomial,
 | 
			
		||||
		const value_type initial_remainder = 0,
 | 
			
		||||
		const value_type final_xor_value = 0
 | 
			
		||||
	) : truncated_polynomial { truncated_polynomial },
 | 
			
		||||
		initial_remainder { initial_remainder },
 | 
			
		||||
		final_xor_value { final_xor_value },
 | 
			
		||||
		remainder { initial_remainder }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	value_type get_initial_remainder() const {
 | 
			
		||||
		return initial_remainder;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void reset(value_type new_initial_remainder) {
 | 
			
		||||
		remainder = new_initial_remainder;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void reset() {
 | 
			
		||||
		remainder = initial_remainder;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void process_bit(bool bit) {
 | 
			
		||||
		remainder ^= (bit ? top_bit() : 0U);
 | 
			
		||||
		const auto do_poly_div = static_cast<bool>(remainder & top_bit());
 | 
			
		||||
		remainder <<= 1;
 | 
			
		||||
		if( do_poly_div ) {
 | 
			
		||||
			remainder ^= truncated_polynomial;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void process_bits(value_type bits, size_t bit_count) {
 | 
			
		||||
		if( RevIn ) {
 | 
			
		||||
			process_bits_lsb_first(bits, bit_count);
 | 
			
		||||
		} else {
 | 
			
		||||
			process_bits_msb_first(bits, bit_count);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void process_byte(const uint8_t byte) {
 | 
			
		||||
		process_bits(byte, 8);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void process_bytes(const void* const data, const size_t length) {
 | 
			
		||||
		const uint8_t* const p = reinterpret_cast<const uint8_t*>(data);
 | 
			
		||||
		for(size_t i=0; i<length; i++) {
 | 
			
		||||
			process_byte(p[i]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<size_t N>
 | 
			
		||||
	void process_bytes(const std::array<uint8_t, N>& data) {
 | 
			
		||||
		process_bytes(data.data(), data.size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	value_type checksum() const {
 | 
			
		||||
		return ((RevOut ? reflect(remainder) : remainder) ^ final_xor_value) & mask();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const value_type truncated_polynomial;
 | 
			
		||||
	const value_type initial_remainder;
 | 
			
		||||
	const value_type final_xor_value;
 | 
			
		||||
	value_type remainder;
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t width() {
 | 
			
		||||
		return Width;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr value_type top_bit() {
 | 
			
		||||
		return 1U << (width() - 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr value_type mask() {
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
 | 
			
		||||
		return (~(~(0UL) << width()));
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static value_type reflect(value_type x) {
 | 
			
		||||
		value_type reflection = 0;
 | 
			
		||||
		for(size_t i=0; i<width(); ++i) {
 | 
			
		||||
			reflection <<= 1;
 | 
			
		||||
			reflection |= (x & 1);
 | 
			
		||||
			x >>= 1;
 | 
			
		||||
		}
 | 
			
		||||
		return reflection;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void process_bits_msb_first(value_type bits, size_t bit_count) {
 | 
			
		||||
		constexpr auto digits = std::numeric_limits<value_type>::digits;
 | 
			
		||||
		constexpr auto mask = static_cast<value_type>(1) << (digits - 1);
 | 
			
		||||
 | 
			
		||||
		bits <<= (std::numeric_limits<value_type>::digits - bit_count);
 | 
			
		||||
		for(size_t i=bit_count; i>0; --i, bits <<= 1) {
 | 
			
		||||
			process_bit(static_cast<bool>(bits & mask));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void process_bits_lsb_first(value_type bits, size_t bit_count) {
 | 
			
		||||
		for(size_t i=bit_count; i>0; --i, bits >>= 1) {
 | 
			
		||||
			process_bit(static_cast<bool>(bits & 0x01));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Adler32 {
 | 
			
		||||
public:
 | 
			
		||||
	void feed(const uint8_t v) {
 | 
			
		||||
		feed_one(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void feed(const void* const data, const size_t n) {
 | 
			
		||||
		const uint8_t* const p = reinterpret_cast<const uint8_t*>(data);
 | 
			
		||||
		for(size_t i=0; i<n; i++) {
 | 
			
		||||
			feed_one(p[i]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	void feed(const T& a) {
 | 
			
		||||
		feed(a.data(), sizeof(T));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::array<uint8_t, 4> bytes() const {
 | 
			
		||||
		return {
 | 
			
		||||
			static_cast<uint8_t>((b >> 8) & 0xff),
 | 
			
		||||
			static_cast<uint8_t>((b >> 0) & 0xff),
 | 
			
		||||
			static_cast<uint8_t>((a >> 8) & 0xff),
 | 
			
		||||
			static_cast<uint8_t>((a >> 0) & 0xff)
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr uint32_t mod = 65521;
 | 
			
		||||
 | 
			
		||||
	uint32_t a { 1 };
 | 
			
		||||
	uint32_t b { 0 };
 | 
			
		||||
 | 
			
		||||
	void feed_one(const uint8_t c) {
 | 
			
		||||
		a = (a + c) % mod;
 | 
			
		||||
		b = (b + a) % mod;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__CRC_H__*/
 | 
			
		||||
							
								
								
									
										108
									
								
								Software/portapack-mayhem/firmware/common/debug.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								Software/portapack-mayhem/firmware/common/debug.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "debug.hpp"
 | 
			
		||||
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
#include <hal.h>
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M0)
 | 
			
		||||
static void debug_indicate_error_init() {
 | 
			
		||||
	// TODO: Get knowledge of LED GPIO port/bit from shared place.
 | 
			
		||||
	LPC_GPIO->CLR[2] = (1 << 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void debug_indicate_error_update() {
 | 
			
		||||
	// Flash RX (yellow) LED to indicate baseband error.
 | 
			
		||||
	// TODO: Get knowledge of LED GPIO port/bit from shared place.
 | 
			
		||||
	LPC_GPIO->NOT[2] = (1 << 2);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
static void debug_indicate_error_init() {
 | 
			
		||||
	// TODO: Get knowledge of LED GPIO port/bit from shared place.
 | 
			
		||||
	LPC_GPIO->CLR[2] = (1 << 8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void debug_indicate_error_update() {
 | 
			
		||||
	// Flash TX (red) LED to indicate baseband error.
 | 
			
		||||
	// TODO: Get knowledge of LED GPIO port/bit from shared place.
 | 
			
		||||
	LPC_GPIO->NOT[2] = (1 << 8);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void runtime_error() {
 | 
			
		||||
	debug_indicate_error_init();
 | 
			
		||||
 | 
			
		||||
	while(true) {
 | 
			
		||||
		volatile size_t n = 1000000U;
 | 
			
		||||
		while(n--);
 | 
			
		||||
		debug_indicate_error_update();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
void port_halt(void) {
 | 
			
		||||
	// Copy debug panic message to M0 region.
 | 
			
		||||
	const auto* p = dbg_panic_msg;
 | 
			
		||||
	for(size_t i=0; i<sizeof(shared_memory.m4_panic_msg); i++) {
 | 
			
		||||
		if( *p == 0 ) {
 | 
			
		||||
			shared_memory.m4_panic_msg[i] = 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			shared_memory.m4_panic_msg[i] = *(p++);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	port_disable();
 | 
			
		||||
	runtime_error();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
CH_IRQ_HANDLER(MemManageVector) {
 | 
			
		||||
#if CH_DBG_ENABLED
 | 
			
		||||
	chDbgPanic("MemManage");
 | 
			
		||||
#else
 | 
			
		||||
	chSysHalt();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CH_IRQ_HANDLER(BusFaultVector) {
 | 
			
		||||
#if CH_DBG_ENABLED
 | 
			
		||||
	chDbgPanic("BusFault");
 | 
			
		||||
#else
 | 
			
		||||
	chSysHalt();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CH_IRQ_HANDLER(UsageFaultVector) {
 | 
			
		||||
#if CH_DBG_ENABLED
 | 
			
		||||
	chDbgPanic("UsageFault");
 | 
			
		||||
#else
 | 
			
		||||
	chSysHalt();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								Software/portapack-mayhem/firmware/common/debug.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Software/portapack-mayhem/firmware/common/debug.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DEBUG_H__
 | 
			
		||||
#define __DEBUG_H__
 | 
			
		||||
 | 
			
		||||
#endif/*__DEBUG_H__*/
 | 
			
		||||
							
								
								
									
										22
									
								
								Software/portapack-mayhem/firmware/common/dsp_fft.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Software/portapack-mayhem/firmware/common/dsp_fft.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_fft.hpp"
 | 
			
		||||
							
								
								
									
										138
									
								
								Software/portapack-mayhem/firmware/common/dsp_fft.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								Software/portapack-mayhem/firmware/common/dsp_fft.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_FFT_H__
 | 
			
		||||
#define __DSP_FFT_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <complex>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
	/* https://github.com/AE9RB/fftbench/blob/master/cxlr.hpp
 | 
			
		||||
	 * Nice trick from AE9RB (David Turnbull) to get compiler to produce simpler
 | 
			
		||||
	 * fma (fused multiply-accumulate) instead of worrying about NaN handling
 | 
			
		||||
	 */
 | 
			
		||||
	inline complex<float>
 | 
			
		||||
	operator*(const complex<float>& v1, const complex<float>& v2) {
 | 
			
		||||
		return complex<float> {
 | 
			
		||||
			v1.real() * v2.real() - v1.imag() * v2.imag(),
 | 
			
		||||
			v1.real() * v2.imag() + v1.imag() * v2.real()
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
} /* namespace std */
 | 
			
		||||
 | 
			
		||||
template<typename T, size_t N>
 | 
			
		||||
void fft_swap(const buffer_c16_t src, std::array<T, N>& dst) {
 | 
			
		||||
	static_assert(power_of_two(N), "only defined for N == power of two");
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<N; i++) {
 | 
			
		||||
		const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
 | 
			
		||||
		const auto s = src.p[i];
 | 
			
		||||
		dst[i_rev] = {
 | 
			
		||||
			static_cast<typename T::value_type>(s.real()),
 | 
			
		||||
			static_cast<typename T::value_type>(s.imag())
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, size_t N>
 | 
			
		||||
void fft_swap(const std::array<complex16_t, N>& src, std::array<T, N>& dst) {
 | 
			
		||||
	static_assert(power_of_two(N), "only defined for N == power of two");
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<N; i++) {
 | 
			
		||||
		const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
 | 
			
		||||
		const auto s = src[i];
 | 
			
		||||
		dst[i_rev] = {
 | 
			
		||||
			static_cast<typename T::value_type>(s.real()),
 | 
			
		||||
			static_cast<typename T::value_type>(s.imag())
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, size_t N>
 | 
			
		||||
void fft_swap(const std::array<T, N>& src, std::array<T, N>& dst) {
 | 
			
		||||
	static_assert(power_of_two(N), "only defined for N == power of two");
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<N; i++) {
 | 
			
		||||
		const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
 | 
			
		||||
		dst[i_rev] = src[i];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, size_t N>
 | 
			
		||||
void fft_swap_in_place(std::array<T, N>& data) {
 | 
			
		||||
	static_assert(power_of_two(N), "only defined for N == power of two");
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<N/2; i++) {
 | 
			
		||||
		const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
 | 
			
		||||
		std::swap(data[i], data[i_rev]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* http://beige.ucs.indiana.edu/B673/node14.html */
 | 
			
		||||
/* http://www.drdobbs.com/cpp/a-simple-and-efficient-fft-implementatio/199500857?pgno=3 */
 | 
			
		||||
 | 
			
		||||
template<typename T, size_t N>
 | 
			
		||||
void fft_c_preswapped(std::array<T, N>& data, const size_t from, const size_t to) {
 | 
			
		||||
	static_assert(power_of_two(N), "only defined for N == power of two");
 | 
			
		||||
	constexpr auto K = log_2(N);
 | 
			
		||||
	if ((to > K) || (from > K)) return;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t K_max = 8;
 | 
			
		||||
	static_assert(K <= K_max, "No FFT twiddle factors for K > 8");
 | 
			
		||||
	static constexpr std::array<std::complex<float>, K_max> wp_table { {
 | 
			
		||||
		{ -2.0f,                        0.0f                     },	// 2
 | 
			
		||||
		{ -1.0f,                       -1.0f                     },	// 4
 | 
			
		||||
		{ -0.2928932188134524756f,     -0.7071067811865475244f   },	// 8
 | 
			
		||||
		{ -0.076120467488713243872f,   -0.38268343236508977173f  },	// 16
 | 
			
		||||
		{ -0.019214719596769550874f,   -0.19509032201612826785f  },	// 32
 | 
			
		||||
		{ -0.0048152733278031137552f,  -0.098017140329560601994f },	// 64
 | 
			
		||||
		{ -0.0012045437948276072852f,  -0.049067674327418014255f },	// 128
 | 
			
		||||
		{ -0.00030118130379577988423f, -0.024541228522912288032f },	// 256
 | 
			
		||||
	} };
 | 
			
		||||
 | 
			
		||||
	/* Provide data to this function, pre-swapped. */
 | 
			
		||||
	for(size_t k = from; k < to; k++) {
 | 
			
		||||
		const size_t mmax = 1 << k;
 | 
			
		||||
		const auto wp = wp_table[k];
 | 
			
		||||
		T w { 1.0f, 0.0f };
 | 
			
		||||
		for(size_t m = 0; m < mmax; ++m) {
 | 
			
		||||
			for(size_t i = m; i < N; i += mmax * 2) {
 | 
			
		||||
				const size_t j = i + mmax;
 | 
			
		||||
				const T temp = w * data[j];
 | 
			
		||||
				data[j]  = data[i] - temp;
 | 
			
		||||
				data[i] += temp;
 | 
			
		||||
			}
 | 
			
		||||
			w += w * wp;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_FFT_H__*/
 | 
			
		||||
							
								
								
									
										22
									
								
								Software/portapack-mayhem/firmware/common/dsp_fir_taps.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Software/portapack-mayhem/firmware/common/dsp_fir_taps.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_fir_taps.hpp"
 | 
			
		||||
							
								
								
									
										431
									
								
								Software/portapack-mayhem/firmware/common/dsp_fir_taps.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										431
									
								
								Software/portapack-mayhem/firmware/common/dsp_fir_taps.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,431 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2017 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_FIR_TAPS_H__
 | 
			
		||||
#define __DSP_FIR_TAPS_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
 | 
			
		||||
template<size_t N>
 | 
			
		||||
struct fir_taps_real {
 | 
			
		||||
	float low_frequency_normalized;
 | 
			
		||||
	float high_frequency_normalized;
 | 
			
		||||
	float transition_normalized;
 | 
			
		||||
	std::array<int16_t, N> taps;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<size_t N>
 | 
			
		||||
struct fir_taps_complex {
 | 
			
		||||
	float low_frequency_normalized;
 | 
			
		||||
	float high_frequency_normalized;
 | 
			
		||||
	float transition_normalized;
 | 
			
		||||
	std::array<complex16_t, N> taps;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// NBFM 16K0F3E emission type /////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR image-reject filter: fs=3072000, pass=8000, stop=344000, decim=8, fout=384000
 | 
			
		||||
constexpr fir_taps_real<24> taps_16k0_decim_0 {
 | 
			
		||||
	.low_frequency_normalized = -8000.0f / 3072000.0f,
 | 
			
		||||
	.high_frequency_normalized = 8000.0f / 3072000.0f,
 | 
			
		||||
	.transition_normalized = 336000.0f / 3072000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		     1,     67,    165,    340,    599,    944,   1361,   1820,
 | 
			
		||||
		  2278,   2684,   2988,   3152,   3152,   2988,   2684,   2278,
 | 
			
		||||
		  1820,   1361,    944,    599,    340,    165,     67,      1,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=384000, pass=8000, stop=40000, decim=8, fout=48000
 | 
			
		||||
constexpr fir_taps_real<32> taps_16k0_decim_1 {
 | 
			
		||||
	.low_frequency_normalized = -8000.0f / 384000.0f,
 | 
			
		||||
	.high_frequency_normalized = 8000.0f / 384000.0f,
 | 
			
		||||
	.transition_normalized = 32000.0f / 384000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -26,   -125,   -180,   -275,   -342,   -359,   -286,    -90,
 | 
			
		||||
		   250,    733,   1337,   2011,   2688,   3289,   3740,   3982,
 | 
			
		||||
		  3982,   3740,   3289,   2688,   2011,   1337,    733,    250,
 | 
			
		||||
		   -90,   -286,   -359,   -342,   -275,   -180,   -125,    -26,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Channel filter: fs=48000, pass=8000, stop=12400, decim=1, fout=48000
 | 
			
		||||
constexpr fir_taps_real<32> taps_16k0_channel {
 | 
			
		||||
	.low_frequency_normalized = -8000.0f / 48000.0f,
 | 
			
		||||
	.high_frequency_normalized = 8000.0f / 48000.0f,
 | 
			
		||||
	.transition_normalized = 4400.0f / 48000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -73,   -285,   -376,     -8,    609,    538,   -584,  -1387,
 | 
			
		||||
		  -148,   2173,   1959,  -2146,  -5267,   -297,  12915,  24737,
 | 
			
		||||
		 24737,  12915,   -297,  -5267,  -2146,   1959,   2173,   -148,
 | 
			
		||||
		 -1387,   -584,    538,    609,     -8,   -376,   -285,    -73,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// NBFM 11K0F3E emission type /////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR image-reject filter: fs=3072000, pass=5500, stop=341500, decim=8, fout=384000
 | 
			
		||||
constexpr fir_taps_real<24> taps_11k0_decim_0 {
 | 
			
		||||
	.low_frequency_normalized = -5500.0f / 3072000.0f,
 | 
			
		||||
	.high_frequency_normalized = 5500.0f / 3072000.0f,
 | 
			
		||||
	.transition_normalized = 336000.0f / 3072000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		    38,    102,    220,    406,    668,   1004,   1397,   1822,
 | 
			
		||||
		  2238,   2603,   2875,   3020,   3020,   2875,   2603,   2238,
 | 
			
		||||
		  1822,   1397,   1004,    668,    406,    220,    102,     38,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=384000, pass=5500, stop=42500, decim=8, fout=48000
 | 
			
		||||
constexpr fir_taps_real<32> taps_11k0_decim_1 {
 | 
			
		||||
	.low_frequency_normalized = -5500.0f / 384000.0f,
 | 
			
		||||
	.high_frequency_normalized = 5500.0f / 384000.0f,
 | 
			
		||||
	.transition_normalized = 37000.0f / 384000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -42,    -87,   -157,   -234,   -298,   -318,   -255,    -75,
 | 
			
		||||
		   246,    713,   1306,   1976,   2656,   3265,   3724,   3971,
 | 
			
		||||
		  3971,   3724,   3265,   2656,   1976,   1306,    713,    246,
 | 
			
		||||
		   -75,   -255,   -318,   -298,   -234,   -157,    -87,    -42,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Channel filter: fs=48000, pass=5500, stop=8900, decim=1, fout=48000
 | 
			
		||||
constexpr fir_taps_real<32> taps_11k0_channel {
 | 
			
		||||
	.low_frequency_normalized = -5500.0f / 48000.0f,
 | 
			
		||||
	.high_frequency_normalized = 5500.0f / 48000.0f,
 | 
			
		||||
	.transition_normalized = 3400.0f / 48000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -68,   -345,   -675,   -867,   -582,    247,   1222,   1562,
 | 
			
		||||
		   634,  -1379,  -3219,  -3068,    310,   6510,  13331,  17795,
 | 
			
		||||
		 17795,  13331,   6510,    310,  -3068,  -3219,  -1379,    634,
 | 
			
		||||
		  1562,   1222,    247,   -582,   -867,   -675,   -345,    -68,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// NBFM 8K50F3E emission type /////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR image-reject filter: fs=3072000, pass=4250, stop=340250, decim=8, fout=384000
 | 
			
		||||
constexpr fir_taps_real<24> taps_4k25_decim_0 {
 | 
			
		||||
	.low_frequency_normalized = -4250.0f / 3072000.0f,
 | 
			
		||||
	.high_frequency_normalized = 4250.0f / 3072000.0f,
 | 
			
		||||
	.transition_normalized = 33600.0f / 3072000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		    38,    103,    222,    409,    671,   1006,   1399,   1821,
 | 
			
		||||
		  2236,   2599,   2868,   3012,   3012,   2868,   2599,   2236,
 | 
			
		||||
		  1821,   1399,   1006,    671,    409,    222,    103,     38,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=384000, pass=4250, stop=43750, decim=8, fout=48000
 | 
			
		||||
constexpr fir_taps_real<32> taps_4k25_decim_1 {
 | 
			
		||||
	.low_frequency_normalized = -4250.0f / 384000.0f,
 | 
			
		||||
	.high_frequency_normalized = 4250.0f / 384000.0f,
 | 
			
		||||
	.transition_normalized = 39500.0f / 384000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -33,    -74,   -139,   -214,   -280,   -306,   -254,    -87,
 | 
			
		||||
		   222,    682,   1274,   1951,   2644,   3268,   3741,   3996,
 | 
			
		||||
		  3996,   3741,   3268,   2644,   1951,   1274,    682,    222,
 | 
			
		||||
		   -87,   -254,   -306,   -280,   -214,   -139,    -74,    -33,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Channel filter: fs=48000, pass=4250, stop=7900, decim=1, fout=48000
 | 
			
		||||
constexpr fir_taps_real<32> taps_4k25_channel {
 | 
			
		||||
	.low_frequency_normalized = -4250.0f / 48000.0f,
 | 
			
		||||
	.high_frequency_normalized = 4250.0f / 48000.0f,
 | 
			
		||||
	.transition_normalized = 3650.0f / 48000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -58,    -14,    153,    484,    871,   1063,    770,   -141,
 | 
			
		||||
		 -1440,  -2488,  -2435,   -614,   3035,   7771,  12226,  14927,
 | 
			
		||||
		 14927,  12226,   7771,   3035,   -614,  -2435,  -2488,  -1440,
 | 
			
		||||
		  -141,    770,   1063,    871,    484,    153,    -14,    -58,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* CTCSS audio filter */
 | 
			
		||||
/* 12kHz int16_t input
 | 
			
		||||
 * -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
 | 
			
		||||
 * -> 6kHz int16_t output, gain of 1.0 (I think).
 | 
			
		||||
 * Padded to multiple of four taps for unrolled FIR code.
 | 
			
		||||
 * sum(abs(taps)): 125270
 | 
			
		||||
 */
 | 
			
		||||
/*constexpr fir_taps_real<64> taps_64_lp_025_025 {
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		     0,      0,     -3,     -7,    -13,    -20,    -27,    -32,
 | 
			
		||||
		   -34,    -33,    -25,    -10,     13,     47,     94,    152,
 | 
			
		||||
		   223,    307,    402,    508,    622,    742,    866,    991,
 | 
			
		||||
		  1113,   1229,   1336,   1430,   1510,   1571,   1614,   1635,
 | 
			
		||||
		  1635,   1614,   1571,   1510,   1430,   1336,   1229,   1113,
 | 
			
		||||
		   991,    866,    742,    622,    508,    402,    307,    223,
 | 
			
		||||
		   152,     94,     47,     13,    -10,    -25,    -33,    -34,
 | 
			
		||||
		   -32,    -27,    -20,    -13,     -7,     -3,      0,      0
 | 
			
		||||
	} },
 | 
			
		||||
};*/
 | 
			
		||||
 | 
			
		||||
/* CTCSS audio filter */
 | 
			
		||||
/* 24kHz int16_t input
 | 
			
		||||
 * -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
 | 
			
		||||
 * -> 12kHz int16_t output, gain of 1.0 (I think).
 | 
			
		||||
 * Padded to multiple of four taps for unrolled FIR code.
 | 
			
		||||
 * sum(abs(taps)): 125270
 | 
			
		||||
 */
 | 
			
		||||
constexpr fir_taps_real<64> taps_64_lp_025_025 {
 | 
			
		||||
	.low_frequency_normalized = 0,
 | 
			
		||||
	.high_frequency_normalized = 0,
 | 
			
		||||
	.transition_normalized = 0,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		0, 0, 2, 6, 12, 20, 32, 46,
 | 
			
		||||
		64, 85, 110, 138, 169, 204, 241, 281,
 | 
			
		||||
		323, 367, 412, 457, 502, 547, 590, 631,
 | 
			
		||||
		669, 704, 735, 762, 784, 801, 812, 818,
 | 
			
		||||
		818, 812, 801, 784, 762, 735, 704, 669,
 | 
			
		||||
		631, 590, 547, 502, 457, 412, 367, 323,
 | 
			
		||||
		281, 241, 204, 169, 138, 110, 85, 64,
 | 
			
		||||
		46, 32, 20, 12, 6, 2, 0, 0
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// DSB AM 6K00A3E emission type ///////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR image-reject filter: fs=3072000, pass=3000, stop=339000, decim=8, fout=384000
 | 
			
		||||
constexpr fir_taps_real<24> taps_6k0_decim_0 {
 | 
			
		||||
	.low_frequency_normalized = -3000.0f / 3072000.0f,
 | 
			
		||||
	.high_frequency_normalized = 3000.0f / 3072000.0f,
 | 
			
		||||
	.transition_normalized = 336000.0f / 3072000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		    39,    104,    224,    412,    674,   1008,   1400,   1821,
 | 
			
		||||
		  2234,   2594,   2863,   3006,   3006,   2863,   2594,   2234,
 | 
			
		||||
		  1821,   1400,   1008,    674,    412,    224,    104,     39,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=384000, pass=3000, stop=45000, decim=8, fout=48000
 | 
			
		||||
constexpr fir_taps_real<32> taps_6k0_decim_1 {
 | 
			
		||||
	.low_frequency_normalized = -3000.0f / 384000.0f,
 | 
			
		||||
	.high_frequency_normalized = 3000.0f / 384000.0f,
 | 
			
		||||
	.transition_normalized = 43000.0f / 384000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -26,    -63,   -123,   -195,   -263,   -295,   -253,    -99,
 | 
			
		||||
		   199,    651,   1242,   1927,   2633,   3273,   3760,   4023,
 | 
			
		||||
		  4023,   3760,   3273,   2633,   1927,   1242,    651,    199,
 | 
			
		||||
		   -99,   -253,   -295,   -263,   -195,   -123,    -63,    -26,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=48000, pass=3000, stop=6700, decim=4, fout=12000
 | 
			
		||||
constexpr fir_taps_real<32> taps_6k0_decim_2 {
 | 
			
		||||
	.low_frequency_normalized = -3000.0f / 48000.0f,
 | 
			
		||||
	.high_frequency_normalized = 3000.0f / 48000.0f,
 | 
			
		||||
	.transition_normalized = 3700.0f / 48000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		    95,    178,    247,    208,    -21,   -474,  -1080,  -1640,
 | 
			
		||||
		 -1857,  -1411,    -83,   2134,   4978,   7946,  10413,  11815,
 | 
			
		||||
		 11815,  10413,   7946,   4978,   2134,    -83,  -1411,  -1857,
 | 
			
		||||
		 -1640,  -1080,   -474,    -21,    208,    247,    178,     95,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Channel filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
 | 
			
		||||
/* NOTE: Slightly less than 1.0 gain (normalized to 65536) due to max(taps) being
 | 
			
		||||
 * slightly larger than 32767 (33312).
 | 
			
		||||
 */
 | 
			
		||||
constexpr fir_taps_complex<64> taps_6k0_dsb_channel {
 | 
			
		||||
	.low_frequency_normalized = -3000.0f / 12000.0f,
 | 
			
		||||
	.high_frequency_normalized = 3000.0f / 12000.0f,
 | 
			
		||||
	.transition_normalized = 300.0f / 12000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		{    -69,      0 }, {   -140,      0 }, {    119,      0 }, {     89,      0 },
 | 
			
		||||
		{   -132,      0 }, {   -134,      0 }, {    197,      0 }, {    167,      0 },
 | 
			
		||||
		{   -273,      0 }, {   -206,      0 }, {    372,      0 }, {    247,      0 },
 | 
			
		||||
		{   -497,      0 }, {   -289,      0 }, {    654,      0 }, {    331,      0 },
 | 
			
		||||
		{   -854,      0 }, {   -372,      0 }, {   1112,      0 }, {    411,      0 },
 | 
			
		||||
		{  -1455,      0 }, {   -446,      0 }, {   1933,      0 }, {    476,      0 },
 | 
			
		||||
		{  -2654,      0 }, {   -501,      0 }, {   3902,      0 }, {    520,      0 },
 | 
			
		||||
		{  -6717,      0 }, {   -531,      0 }, {  20478,      0 }, {  32767,      0 },
 | 
			
		||||
		{  20478,      0 }, {   -531,      0 }, {  -6717,      0 }, {    520,      0 },
 | 
			
		||||
		{   3902,      0 }, {   -501,      0 }, {  -2654,      0 }, {    476,      0 },
 | 
			
		||||
		{   1933,      0 }, {   -446,      0 }, {  -1455,      0 }, {    411,      0 },
 | 
			
		||||
		{   1112,      0 }, {   -372,      0 }, {   -854,      0 }, {    331,      0 },
 | 
			
		||||
		{    654,      0 }, {   -289,      0 }, {   -497,      0 }, {    247,      0 },
 | 
			
		||||
		{    372,      0 }, {   -206,      0 }, {   -273,      0 }, {    167,      0 },
 | 
			
		||||
		{    197,      0 }, {   -134,      0 }, {   -132,      0 }, {     89,      0 },
 | 
			
		||||
		{    119,      0 }, {   -140,      0 }, {    -69,      0 }, {      0,      0 },
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// USB AM 2K80J3E emission type ///////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
 | 
			
		||||
constexpr fir_taps_complex<64> taps_2k8_usb_channel {
 | 
			
		||||
	.low_frequency_normalized = 0,
 | 
			
		||||
	.high_frequency_normalized = 3000.0f / 12000.0f,
 | 
			
		||||
	.transition_normalized = 300.0f / 12000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		{   -146,      0 }, {    -41,    -45 }, {     -1,     10 }, {    -95,     69 },
 | 
			
		||||
		{   -194,    -41 }, {    -91,   -158 }, {     14,    -43 }, {   -150,     67 },
 | 
			
		||||
		{   -299,   -133 }, {   -100,   -307 }, {     50,    -86 }, {   -254,     54 },
 | 
			
		||||
		{   -453,   -329 }, {    -62,   -587 }, {    170,   -189 }, {   -334,      0 },
 | 
			
		||||
		{   -580,   -645 }, {    104,   -986 }, {    418,   -304 }, {   -412,    -88 },
 | 
			
		||||
		{   -680,  -1178 }, {    527,  -1623 }, {    970,   -432 }, {   -441,   -196 },
 | 
			
		||||
		{   -698,  -2149 }, {   1617,  -2800 }, {   2384,   -507 }, {   -429,   -311 },
 | 
			
		||||
		{   -545,  -5181 }, {   6925,  -7691 }, {  14340,      0 }, {  10601,  11773 },
 | 
			
		||||
		{  -1499,  14261 }, {  -8373,   6083 }, {  -5095,  -1083 }, {   -265,   -459 },
 | 
			
		||||
		{   -753,   2318 }, {  -2954,   1315 }, {  -2064,   -919 }, {   -149,   -459 },
 | 
			
		||||
		{   -531,    920 }, {  -1669,    355 }, {  -1100,   -800 }, {    -44,   -419 },
 | 
			
		||||
		{   -346,    384 }, {   -992,      0 }, {   -580,   -645 }, {     35,   -332 },
 | 
			
		||||
		{   -205,    149 }, {   -577,   -123 }, {   -280,   -485 }, {     80,   -247 },
 | 
			
		||||
		{    -91,     40 }, {   -294,   -131 }, {   -101,   -312 }, {     82,   -142 },
 | 
			
		||||
		{    -44,      9 }, {   -147,   -107 }, {    -21,   -197 }, {     79,    -88 },
 | 
			
		||||
		{     10,      0 }, {    -41,    -45 }, {     15,   -145 }, {      0,      0 },
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// LSB AM 2K80J3E emission type ///////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
 | 
			
		||||
constexpr fir_taps_complex<64> taps_2k8_lsb_channel {
 | 
			
		||||
	.low_frequency_normalized = -3000.0f / 12000.0f,
 | 
			
		||||
	.high_frequency_normalized = 0,
 | 
			
		||||
	.transition_normalized = 300.0f / 12000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		{   -146,      0 }, {    -41,     45 }, {     -1,    -10 }, {    -95,    -69 },
 | 
			
		||||
		{   -194,     41 }, {    -91,    158 }, {     14,     43 }, {   -150,    -67 },
 | 
			
		||||
		{   -299,    133 }, {   -100,    307 }, {     50,     86 }, {   -254,    -54 },
 | 
			
		||||
		{   -453,    329 }, {    -62,    587 }, {    170,    189 }, {   -334,      0 },
 | 
			
		||||
		{   -580,    645 }, {    104,    986 }, {    418,    304 }, {   -412,     88 },
 | 
			
		||||
		{   -680,   1178 }, {    527,   1623 }, {    970,    432 }, {   -441,    196 },
 | 
			
		||||
		{   -698,   2149 }, {   1617,   2800 }, {   2384,    507 }, {   -429,    311 },
 | 
			
		||||
		{   -545,   5181 }, {   6925,   7691 }, {  14340,      0 }, {  10601, -11773 },
 | 
			
		||||
		{  -1499, -14261 }, {  -8373,  -6083 }, {  -5095,   1083 }, {   -265,    459 },
 | 
			
		||||
		{   -753,  -2318 }, {  -2954,  -1315 }, {  -2064,    919 }, {   -149,    459 },
 | 
			
		||||
		{   -531,   -920 }, {  -1669,   -355 }, {  -1100,    800 }, {    -44,    419 },
 | 
			
		||||
		{   -346,   -384 }, {   -992,      0 }, {   -580,    645 }, {     35,    332 },
 | 
			
		||||
		{   -205,   -149 }, {   -577,    123 }, {   -280,    485 }, {     80,    247 },
 | 
			
		||||
		{    -91,    -40 }, {   -294,    131 }, {   -101,    312 }, {     82,    142 },
 | 
			
		||||
		{    -44,     -9 }, {   -147,    107 }, {    -21,    197 }, {     79,     88 },
 | 
			
		||||
		{     10,      0 }, {    -41,     45 }, {     15,    145 }, {      0,      0 },
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// USB AM 700Hz filter: fs=12000, start=600, end=800, width=200, stop=40db, decim=1, fout=12000
 | 
			
		||||
 | 
			
		||||
constexpr fir_taps_complex<64> taps_0k7_usb_channel {
 | 
			
		||||
	.low_frequency_normalized = 600.0f / 12000.0f,
 | 
			
		||||
	.high_frequency_normalized = 800.0f / 12000.0f,
 | 
			
		||||
	.transition_normalized = 200.0f / 12000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		{    531,      0 },	{    192,     73 },	{    181,    163 },	{    129,    254 },
 | 
			
		||||
		{     34,    328 },	{    -97,    364 },	{   -251,    345 },	{   -403,    261 },
 | 
			
		||||
		{   -524,    111 },	{   -585,    -92 },	{   -564,   -326 },	{   -448,   -554 },
 | 
			
		||||
		{   -239,   -737 },	{     43,   -836 },	{    366,   -822 },	{    681,   -681 },
 | 
			
		||||
		{    936,   -417 },	{   1085,    -56 },	{   1090,    354 },	{    935,    757 },
 | 
			
		||||
		{    629,   1090 },	{    205,   1296 },	{   -283,   1331 },	{   -766,   1180 },
 | 
			
		||||
		{  -1172,    851 },	{  -1435,    384 },	{  -1510,   -158 },	{  -1377,   -702 },
 | 
			
		||||
		{  -1049,  -1165 },	{   -568,  -1480 },	{      0,  -1596 },	{    574,  -1496 },
 | 
			
		||||
		{   1072,  -1191 },	{   1422,   -724 },	{   1576,   -165 },	{   1515,    406 },
 | 
			
		||||
		{   1251,    908 },	{    827,   1273 },	{    309,   1453 },	{   -226,   1431 },
 | 
			
		||||
		{   -703,   1218 },	{  -1058,    856 },	{  -1248,    405 },	{  -1257,    -65 },
 | 
			
		||||
		{  -1100,   -489 },	{   -810,   -810 },	{   -441,   -992 },	{    -53,  -1024 },
 | 
			
		||||
		{    297,   -916 },	{    566,   -699 },	{    725,   -418 },	{    765,   -121 },
 | 
			
		||||
		{    697,    148 },	{    546,    355 },	{    348,    479 },	{    138,    517 },
 | 
			
		||||
		{    -50,    477 },	{   -194,    381 },	{   -280,    252 },	{   -308,    118 },
 | 
			
		||||
		{   -285,      0 },	{   -228,    -87 },	{   -153,   -138 },	{   -241,   -473 },
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// WFM 200KF8E emission type //////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR image-reject filter: fs=3072000, pass=100000, stop=484000, decim=4, fout=768000
 | 
			
		||||
constexpr fir_taps_real<24> taps_200k_wfm_decim_0 = {
 | 
			
		||||
	.low_frequency_normalized = -100000.0f / 3072000.0f,
 | 
			
		||||
	.high_frequency_normalized = 100000.0f / 3072000.0f,
 | 
			
		||||
	.transition_normalized = 384000.0f / 3072000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		    48,    -18,   -151,   -364,   -557,   -548,   -139,    789,
 | 
			
		||||
		  2187,   3800,   5230,   6071,   6071,   5230,   3800,   2187,
 | 
			
		||||
		   789,   -139,   -548,   -557,   -364,   -151,    -18,     48,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=768000, pass=100000, stop=284000, decim=2, fout=384000
 | 
			
		||||
constexpr fir_taps_real<16> taps_200k_wfm_decim_1 = {
 | 
			
		||||
	.low_frequency_normalized = -100000.0f / 768000.0f,
 | 
			
		||||
	.high_frequency_normalized = 100000.0f / 768000.0f,
 | 
			
		||||
	.transition_normalized = 184000.0f / 768000.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		   -67,   -123,    388,    622,  -1342,  -2185,   4599,  14486,
 | 
			
		||||
		 14486,   4599,  -2185,  -1342,    622,    388,   -123,    -67,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Wideband audio filter */
 | 
			
		||||
/* 96kHz int16_t input
 | 
			
		||||
 * -> FIR filter, <15kHz (0.156fs) pass, >19kHz (0.198fs) stop
 | 
			
		||||
 * -> 48kHz int16_t output, gain of 1.0 (I think).
 | 
			
		||||
 * Padded to multiple of four taps for unrolled FIR code.
 | 
			
		||||
 * sum(abs(taps)): 125270
 | 
			
		||||
 */
 | 
			
		||||
constexpr fir_taps_real<64> taps_64_lp_156_198 {
 | 
			
		||||
	.low_frequency_normalized = -0.156f,
 | 
			
		||||
	.high_frequency_normalized = 0.156f,
 | 
			
		||||
	.transition_normalized = 0.04f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
	   -27,    166,    104,    -36,   -174,   -129,    109,    287,
 | 
			
		||||
	   148,   -232,   -430,   -130,    427,    597,     49,   -716,
 | 
			
		||||
	  -778,    137,   1131,    957,   -493,  -1740,  -1121,   1167,
 | 
			
		||||
	  2733,   1252,  -2633,  -4899,  -1336,   8210,  18660,  23254,
 | 
			
		||||
	 18660,   8210,  -1336,  -4899,  -2633,   1252,   2733,   1167,
 | 
			
		||||
	 -1121,  -1740,   -493,    957,   1131,    137,   -778,   -716,
 | 
			
		||||
	    49,    597,    427,   -130,   -430,   -232,    148,    287,
 | 
			
		||||
	   109,   -129,   -174,    -36,    104,    166,    -27,      0,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TPMS decimation filters ////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// IFIR image-reject filter: fs=2457600, pass=100000, stop=407200, decim=4, fout=614400
 | 
			
		||||
static constexpr fir_taps_real<24> taps_200k_decim_0 = {
 | 
			
		||||
	.low_frequency_normalized = -100000.0f / 2457600.0f,
 | 
			
		||||
	.high_frequency_normalized = 100000.0f / 2457600.0f,
 | 
			
		||||
	.transition_normalized = 307200.0f / 2457600.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
	    90,     94,      4,   -240,   -570,   -776,   -563,    309,
 | 
			
		||||
	  1861,   3808,   5618,   6710,   6710,   5618,   3808,   1861,
 | 
			
		||||
	   309,   -563,   -776,   -570,   -240,      4,     94,     90,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IFIR prototype filter: fs=614400, pass=100000, stop=207200, decim=2, fout=307200
 | 
			
		||||
static constexpr fir_taps_real<16> taps_200k_decim_1 = {
 | 
			
		||||
	.low_frequency_normalized = -100000.0f / 614400.0f,
 | 
			
		||||
	.high_frequency_normalized = 100000.0f / 614400.0f,
 | 
			
		||||
	.transition_normalized = 107200.0f / 614400.0f,
 | 
			
		||||
	.taps = { {
 | 
			
		||||
		  -132,   -256,    545,    834,  -1507,  -2401,   4666,  14583,
 | 
			
		||||
		 14583,   4666,  -2401,  -1507,    834,    545,   -256,   -132,
 | 
			
		||||
	} },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_FIR_TAPS_H__*/
 | 
			
		||||
							
								
								
									
										83
									
								
								Software/portapack-mayhem/firmware/common/dsp_iir.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								Software/portapack-mayhem/firmware/common/dsp_iir.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
 | 
			
		||||
#include <hal.h>
 | 
			
		||||
 | 
			
		||||
void IIRBiquadFilter::configure(const iir_biquad_config_t& new_config) {
 | 
			
		||||
	config = new_config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IIRBiquadFilter::execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out) {
 | 
			
		||||
	const auto a_ = config.a;
 | 
			
		||||
	const auto b_ = config.b;
 | 
			
		||||
	
 | 
			
		||||
	auto x_ = x;
 | 
			
		||||
	auto y_ = y;
 | 
			
		||||
 | 
			
		||||
	// TODO: Assert that buffer_out.count == buffer_in.count.
 | 
			
		||||
	for(size_t i=0; i<buffer_out.count; i++) {
 | 
			
		||||
		x_[0] = x_[1];
 | 
			
		||||
		x_[1] = x_[2];
 | 
			
		||||
		x_[2] = buffer_in.p[i];
 | 
			
		||||
 | 
			
		||||
		y_[0] = y_[1];
 | 
			
		||||
		y_[1] = y_[2];
 | 
			
		||||
		y_[2] = b_[0] * x_[2] + b_[1] * x_[1] + b_[2] * x_[0]
 | 
			
		||||
		                      - a_[1] * y_[1] - a_[2] * y_[0];
 | 
			
		||||
 | 
			
		||||
		buffer_out.p[i] = y_[2];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	x = x_;
 | 
			
		||||
	y = y_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) {
 | 
			
		||||
	execute(buffer, buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IIRBiquadDF2Filter::configure(const iir_biquad_df2_config_t& config) {
 | 
			
		||||
	b0 = config[0] / config[3];
 | 
			
		||||
	b1 = config[1] / config[3];
 | 
			
		||||
	b2 = config[2] / config[3];
 | 
			
		||||
	a1 = config[4] / config[3];
 | 
			
		||||
	a2 = config[5] / config[3];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  scipy.signal.sosfilt
 | 
			
		||||
//
 | 
			
		||||
//  x_n = x[i, n]  # make a temporary copy
 | 
			
		||||
//  # Use direct II transposed structure:
 | 
			
		||||
//  x[i, n] = b[s, 0] * x_n + zi[i, s, 0]
 | 
			
		||||
//  zi[i, s, 0] = (b[s, 1] * x_n - a[s, 0] * x[i, n] + zi[i, s, 1])
 | 
			
		||||
//  zi[i, s, 1] = (b[s, 2] * x_n - a[s, 1] * x[i, n])
 | 
			
		||||
 | 
			
		||||
float IIRBiquadDF2Filter::execute(float x) {
 | 
			
		||||
	float y;
 | 
			
		||||
	
 | 
			
		||||
	y = b0 * x + z0;
 | 
			
		||||
	z0 = b1 * x - a1 * y + z1;
 | 
			
		||||
	z1 = b2 * x - a2 * y;
 | 
			
		||||
 | 
			
		||||
	return y;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								Software/portapack-mayhem/firmware/common/dsp_iir.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								Software/portapack-mayhem/firmware/common/dsp_iir.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_IIR_H__
 | 
			
		||||
#define __DSP_IIR_H__
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
struct iir_biquad_config_t {
 | 
			
		||||
	std::array<float, 3> b;
 | 
			
		||||
	std::array<float, 3> a;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 0..2 - b, 3..5 - a
 | 
			
		||||
typedef std::array<float, 6> iir_biquad_df2_config_t;
 | 
			
		||||
 | 
			
		||||
constexpr iir_biquad_config_t iir_config_passthrough {
 | 
			
		||||
	{ { 1.0f, 0.0f, 0.0f } },
 | 
			
		||||
	{ { 0.0f, 0.0f, 0.0f } },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr iir_biquad_config_t iir_config_no_pass {
 | 
			
		||||
	{ { 0.0f, 0.0f, 0.0f } },
 | 
			
		||||
	{ { 0.0f, 0.0f, 0.0f } },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class IIRBiquadFilter {
 | 
			
		||||
public:
 | 
			
		||||
	// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
 | 
			
		||||
	constexpr IIRBiquadFilter(
 | 
			
		||||
	) : IIRBiquadFilter(iir_config_no_pass)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Assume all coefficients are normalized so that a0=1.0
 | 
			
		||||
	constexpr IIRBiquadFilter(
 | 
			
		||||
		const iir_biquad_config_t& config
 | 
			
		||||
	) : config(config)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void configure(const iir_biquad_config_t& new_config);
 | 
			
		||||
 | 
			
		||||
	void execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out);
 | 
			
		||||
	void execute_in_place(const buffer_f32_t& buffer);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	iir_biquad_config_t config;
 | 
			
		||||
	std::array<float, 3> x { { 0.0f, 0.0f, 0.0f } };
 | 
			
		||||
	std::array<float, 3> y { { 0.0f, 0.0f, 0.0f } };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class IIRBiquadDF2Filter {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	void configure(const iir_biquad_df2_config_t& config);
 | 
			
		||||
	float execute(float z);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	float b0 = 0;
 | 
			
		||||
	float b1 = 0;
 | 
			
		||||
	float b2 = 0;
 | 
			
		||||
	float a1 = 0;
 | 
			
		||||
	float a2 = 0;
 | 
			
		||||
 | 
			
		||||
	float z0 = 0;
 | 
			
		||||
	float z1 = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_IIR_H__*/
 | 
			
		||||
							
								
								
									
										120
									
								
								Software/portapack-mayhem/firmware/common/dsp_iir_config.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								Software/portapack-mayhem/firmware/common/dsp_iir_config.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2017 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_IIR_CONFIG_H__
 | 
			
		||||
#define __DSP_IIR_CONFIG_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(2, 30 / 24000.0, 'highpass', analog=False)
 | 
			
		||||
constexpr iir_biquad_config_t audio_48k_hpf_30hz_config {
 | 
			
		||||
	{  0.99722705f, -1.99445410f,  0.99722705f },
 | 
			
		||||
	{  1.00000000f, -1.99444641f,  0.99446179f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(2, 300 / 24000.0, 'highpass', analog=False)
 | 
			
		||||
constexpr iir_biquad_config_t audio_48k_hpf_300hz_config {
 | 
			
		||||
	{  0.97261390f, -1.94522780f,  0.97261390f },
 | 
			
		||||
	{  1.00000000f, -1.94447766f,  0.94597794f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(2, 300 / 12000.0, 'highpass', analog=False)
 | 
			
		||||
constexpr iir_biquad_config_t audio_24k_hpf_300hz_config {
 | 
			
		||||
	{  0.94597686f, -1.89195371f,  0.94597686f },
 | 
			
		||||
	{  1.00000000f, -1.88903308f,  0.89487434f }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(2, 30 / 12000.0, 'highpass', analog=False)
 | 
			
		||||
constexpr iir_biquad_config_t audio_24k_hpf_30hz_config {
 | 
			
		||||
	{  0.99446179f, -1.98892358f,  0.99446179f },
 | 
			
		||||
	{  1.00000000f, -1.98889291f,  0.98895425f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(2, 300 / 8000.0, 'highpass', analog=False)
 | 
			
		||||
constexpr iir_biquad_config_t audio_16k_hpf_300hz_config {
 | 
			
		||||
	{  0.92006616f, -1.84013232f,  0.92006616f },
 | 
			
		||||
	{  1.00000000f, -1.83373266f,  0.84653197f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(2, 300 / 6000.0, 'highpass', analog=False)
 | 
			
		||||
constexpr iir_biquad_config_t audio_12k_hpf_300hz_config {
 | 
			
		||||
	{  0.89485861f, -1.78971721f,  0.89485861f },
 | 
			
		||||
	{  1.00000000f, -1.77863178f,  0.80080265f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(2, 300 / 4000.0, 'highpass', analog=False)
 | 
			
		||||
constexpr iir_biquad_config_t audio_8k_hpf_300hz_config {
 | 
			
		||||
	{  0.84645925f, -1.69291851f,  0.84645925f },
 | 
			
		||||
	{  1.00000000f, -1.66920314f,  0.71663387f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.iirdesign(wp=8000 / 24000.0, ws= 4000 / 24000.0, gpass=1, gstop=18, ftype='ellip')
 | 
			
		||||
constexpr iir_biquad_config_t non_audio_hpf_config {
 | 
			
		||||
	{  0.51891061f, -0.95714180f,  0.51891061f },
 | 
			
		||||
	{  1.0f       , -0.79878302f,  0.43960231f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(1, 300 / 24000.0, 'lowpass', analog=False)
 | 
			
		||||
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
 | 
			
		||||
constexpr iir_biquad_config_t audio_48k_deemph_300_6_config {
 | 
			
		||||
	{  0.01925927f,  0.01925927f,  0.00000000f },
 | 
			
		||||
	{  1.00000000f, -0.96148145f,  0.00000000f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(1, 300 / 12000.0, 'lowpass', analog=False)
 | 
			
		||||
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
 | 
			
		||||
constexpr iir_biquad_config_t audio_24k_deemph_300_6_config {
 | 
			
		||||
	{  0.03780475f,  0.03780475f,  0.00000000f },
 | 
			
		||||
	{  1.00000000f, -0.92439049f,  0.00000000f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(1, 300 / 8000.0, 'lowpass', analog=False)
 | 
			
		||||
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
 | 
			
		||||
constexpr iir_biquad_config_t audio_16k_deemph_300_6_config {
 | 
			
		||||
	{  0.05568894f,  0.05568894f,  0.00000000f },
 | 
			
		||||
	{  1.00000000f, -0.88862213f,  0.00000000f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(1, 300 / 6000.0, 'lowpass', analog=False)
 | 
			
		||||
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
 | 
			
		||||
constexpr iir_biquad_config_t audio_12k_deemph_300_6_config {
 | 
			
		||||
	{  0.07295966f,  0.07295966f,  0.00000000f },
 | 
			
		||||
	{  1.00000000f, -0.85408069f,  0.00000000f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// scipy.signal.butter(1, 300 / 4000.0, 'lowpass', analog=False)
 | 
			
		||||
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
 | 
			
		||||
constexpr iir_biquad_config_t audio_8k_deemph_300_6_config {
 | 
			
		||||
	{  0.10583178f,  0.10583178f,  0.00000000f },
 | 
			
		||||
	{  1.00000000f, -0.78833643f,  0.00000000f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 75us RC time constant, used in broadcast FM in Americas, South Korea
 | 
			
		||||
// scipy.signal.butter(1, 2122 / 24000.0, 'lowpass', analog=False)
 | 
			
		||||
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
 | 
			
		||||
constexpr iir_biquad_config_t audio_48k_deemph_2122_6_config {
 | 
			
		||||
	{  0.12264116f,  0.12264116f,  0.00000000f },
 | 
			
		||||
	{  1.00000000f, -0.75471767f,  0.00000000f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_IIR_CONFIG_H__*/
 | 
			
		||||
							
								
								
									
										22
									
								
								Software/portapack-mayhem/firmware/common/dsp_sos.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Software/portapack-mayhem/firmware/common/dsp_sos.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020 Belousov Oleg
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_sos.hpp"
 | 
			
		||||
							
								
								
									
										51
									
								
								Software/portapack-mayhem/firmware/common/dsp_sos.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								Software/portapack-mayhem/firmware/common/dsp_sos.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020 Belousov Oleg
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_SOS_H__
 | 
			
		||||
#define __DSP_SOS_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
template <size_t N>
 | 
			
		||||
class SOSFilter {
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    void configure(const iir_biquad_df2_config_t config[N]) {
 | 
			
		||||
        for (size_t i = 0; i < N; i++)
 | 
			
		||||
            filters[i].configure(config[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float execute(float value) {
 | 
			
		||||
        for (auto &filter : filters)
 | 
			
		||||
            value = filter.execute(value);
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
    IIRBiquadDF2Filter filters[N];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_SOS_H__*/
 | 
			
		||||
							
								
								
									
										37
									
								
								Software/portapack-mayhem/firmware/common/dsp_sos_config.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Software/portapack-mayhem/firmware/common/dsp_sos_config.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020 Belousov Oleg
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_SOS_CONFIG_H__
 | 
			
		||||
#define __DSP_SOS_CONFIG_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
 | 
			
		||||
// scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5, rs = 60.0, Wn = 0.5, btype = 'lowpass', output="sos")
 | 
			
		||||
 | 
			
		||||
constexpr iir_biquad_df2_config_t half_band_lpf_config[5] = {
 | 
			
		||||
	{ 0.02339042f,	0.0411599f,		0.02339042f,	1.0f,		-0.95317621f,	0.33446485f },
 | 
			
		||||
	{ 1.0f,			0.82196114f,	1.0f,			1.0f,       -0.50327735f,	0.63611027f },
 | 
			
		||||
	{ 1.0f,         0.32515305f,	1.0f,           1.0f,       -0.18144446f,   0.85269598f },
 | 
			
		||||
	{ 1.0f,         0.14394122f,	1.0f,          	1.0f,       -0.04368236f,	0.94798064f },
 | 
			
		||||
	{ 1.0f,         0.08720754,		1.0f,           1.0f,        0.00220944f,  	0.98743139f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_SOS_CONFIG_H__*/
 | 
			
		||||
							
								
								
									
										36
									
								
								Software/portapack-mayhem/firmware/common/dsp_types.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Software/portapack-mayhem/firmware/common/dsp_types.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_TYPES_H__
 | 
			
		||||
#define __DSP_TYPES_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
#include "buffer.hpp"
 | 
			
		||||
 | 
			
		||||
using buffer_c8_t = buffer_t<complex8_t>;
 | 
			
		||||
using buffer_c16_t = buffer_t<complex16_t>;
 | 
			
		||||
using buffer_s16_t = buffer_t<int16_t>;
 | 
			
		||||
using buffer_c32_t = buffer_t<complex32_t>;
 | 
			
		||||
using buffer_f32_t = buffer_t<float>;
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_TYPES_H__*/
 | 
			
		||||
							
								
								
									
										112
									
								
								Software/portapack-mayhem/firmware/common/emu_cc1101.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								Software/portapack-mayhem/firmware/common/emu_cc1101.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2017 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __EMU_CC1101_H__
 | 
			
		||||
#define __EMU_CC1101_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace cc1101 {
 | 
			
		||||
	
 | 
			
		||||
// Data rate (Bauds)
 | 
			
		||||
// Whitening: Everything except preamble and sync word, init value = 111111111
 | 
			
		||||
// Packet format: preamble, sync word, (opt) length, (opt) address, payload, (opt) CRC
 | 
			
		||||
// Preamble: 8*n bits of 10101010
 | 
			
		||||
// Sync word: 2 bytes (can be repeated twice)
 | 
			
		||||
// Length: 1 byte (address + payload)
 | 
			
		||||
// 2-FSK: 0=-dev, 1=+dev
 | 
			
		||||
// 4-FSK: 00=-1/3dev, 01=-dev, 10=1/3dev, 11=+dev (preamble and sync are in 2-FSK)
 | 
			
		||||
// OOK: PA on or off
 | 
			
		||||
// ASK: Power can be adjusted
 | 
			
		||||
// FEC: ?
 | 
			
		||||
 | 
			
		||||
class CC1101Emu {
 | 
			
		||||
public:
 | 
			
		||||
	//CC1101Emu();
 | 
			
		||||
	//~CC1101Emu();
 | 
			
		||||
	
 | 
			
		||||
	enum packet_mode_t {
 | 
			
		||||
		FIXED_LENGTH,
 | 
			
		||||
		VARIABLE_LENGTH,
 | 
			
		||||
		INFINITE_LENGTH
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	enum modulation_t {
 | 
			
		||||
		TWO_FSK,
 | 
			
		||||
		GFSK,
 | 
			
		||||
		OOK,
 | 
			
		||||
		FOUR_FSK,
 | 
			
		||||
		MSK,
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	void set_sync_word(const uint16_t sync_word) {
 | 
			
		||||
		sync_word_ = sync_word;
 | 
			
		||||
	};
 | 
			
		||||
	void set_address(const uint8_t address) {
 | 
			
		||||
		address_ = address;
 | 
			
		||||
	};
 | 
			
		||||
	void set_packet_length(const uint8_t packet_length) {
 | 
			
		||||
		packet_length_ = packet_length;
 | 
			
		||||
	};
 | 
			
		||||
	void set_data_config(const bool CRC, const bool manchester, const bool whitening) {
 | 
			
		||||
		CRC_ = CRC;
 | 
			
		||||
		manchester_ = manchester;
 | 
			
		||||
		whitening_ = whitening;
 | 
			
		||||
	};
 | 
			
		||||
	void set_packet_mode(const packet_mode_t packet_mode) {
 | 
			
		||||
		packet_mode_ = packet_mode;
 | 
			
		||||
	};
 | 
			
		||||
	void set_modulation(const modulation_t modulation) {
 | 
			
		||||
		modulation_ = modulation;
 | 
			
		||||
	}
 | 
			
		||||
	void set_num_preamble(const uint8_t num_preamble) {		// 2, 3, 4, 6, 8, 12, 16, or 24
 | 
			
		||||
		num_preamble_ = num_preamble;
 | 
			
		||||
	};
 | 
			
		||||
	void set_deviation(const size_t deviation) {
 | 
			
		||||
		deviation_ = deviation;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint16_t sync_word_ { 0xD391 };
 | 
			
		||||
	uint8_t address_ { 0x00 };
 | 
			
		||||
	uint8_t packet_length_ { 0 };
 | 
			
		||||
	bool CRC_ { false };
 | 
			
		||||
	bool manchester_ { false };
 | 
			
		||||
	bool whitening_ { true };
 | 
			
		||||
	packet_mode_t packet_mode_ { VARIABLE_LENGTH };
 | 
			
		||||
	modulation_t modulation_ { TWO_FSK };
 | 
			
		||||
	uint8_t num_preamble_ { 4 };
 | 
			
		||||
	size_t deviation_ { 4000 };
 | 
			
		||||
	
 | 
			
		||||
	uint16_t whitening_pn { 0x1FF };
 | 
			
		||||
	
 | 
			
		||||
	void whitening_init();
 | 
			
		||||
	uint8_t whiten_byte(uint8_t byte);
 | 
			
		||||
	
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace cc1101 */
 | 
			
		||||
 | 
			
		||||
#endif/*__EMU_CC1101_H__*/
 | 
			
		||||
							
								
								
									
										106
									
								
								Software/portapack-mayhem/firmware/common/ert_packet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								Software/portapack-mayhem/firmware/common/ert_packet.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ert_packet.hpp"
 | 
			
		||||
 | 
			
		||||
#include "crc.hpp"
 | 
			
		||||
 | 
			
		||||
namespace ert {
 | 
			
		||||
 | 
			
		||||
size_t Packet::length() const {
 | 
			
		||||
	return decoder_.symbols_count();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::is_valid() const {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Timestamp Packet::received_at() const {
 | 
			
		||||
	return packet_.timestamp();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Packet::Type Packet::type() const {
 | 
			
		||||
	return type_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ID Packet::id() const {
 | 
			
		||||
	if( type() == Type::SCM ) {
 | 
			
		||||
		const auto msb = reader_.read(0, 2);
 | 
			
		||||
		const auto lsb = reader_.read(35, 24);
 | 
			
		||||
		return (msb << 24) | lsb;
 | 
			
		||||
	}
 | 
			
		||||
	if( type() == Type::IDM ) {
 | 
			
		||||
		return reader_.read(5 * 8, 32);
 | 
			
		||||
	}
 | 
			
		||||
	return invalid_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Consumption Packet::consumption() const {
 | 
			
		||||
	if( type() == Type::SCM ) {
 | 
			
		||||
		return reader_.read(11, 24);
 | 
			
		||||
	}
 | 
			
		||||
	if( type() == Type::IDM ) {
 | 
			
		||||
		return reader_.read(25 * 8, 32);
 | 
			
		||||
	}
 | 
			
		||||
	return invalid_consumption;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CommodityType Packet::commodity_type() const {
 | 
			
		||||
	if( type() == Type::SCM ) {
 | 
			
		||||
		return reader_.read(5, 4);
 | 
			
		||||
	}
 | 
			
		||||
	if( type() == Type::IDM ) {
 | 
			
		||||
		return reader_.read(4 * 8 + 4, 4);
 | 
			
		||||
	}
 | 
			
		||||
	return invalid_commodity_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FormattedSymbols Packet::symbols_formatted() const {
 | 
			
		||||
	return format_symbols(decoder_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::crc_ok() const {
 | 
			
		||||
	switch(type()) {
 | 
			
		||||
	case Type::SCM:	return crc_ok_scm();
 | 
			
		||||
	case Type::IDM:	return crc_ok_idm();
 | 
			
		||||
	default:		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::crc_ok_scm() const {
 | 
			
		||||
	CRC<16> ert_bch { 0x6f63 };
 | 
			
		||||
	size_t start_bit = 5;
 | 
			
		||||
	ert_bch.process_byte(reader_.read(0, start_bit));
 | 
			
		||||
	for(size_t i=start_bit; i<length(); i+=8) {
 | 
			
		||||
		ert_bch.process_byte(reader_.read(i, 8));
 | 
			
		||||
	}
 | 
			
		||||
	return ert_bch.checksum() == 0x0000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Packet::crc_ok_idm() const {
 | 
			
		||||
	CRC<16> ert_crc_ccitt { 0x1021, 0xffff, 0x1d0f };
 | 
			
		||||
	for(size_t i=0; i<length(); i+=8) {
 | 
			
		||||
		ert_crc_ccitt.process_byte(reader_.read(i, 8));
 | 
			
		||||
	}
 | 
			
		||||
	return ert_crc_ccitt.checksum() == 0x0000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace ert */
 | 
			
		||||
							
								
								
									
										89
									
								
								Software/portapack-mayhem/firmware/common/ert_packet.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								Software/portapack-mayhem/firmware/common/ert_packet.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __ERT_PACKET_H__
 | 
			
		||||
#define __ERT_PACKET_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#include "field_reader.hpp"
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
#include "manchester.hpp"
 | 
			
		||||
 | 
			
		||||
namespace ert {
 | 
			
		||||
 | 
			
		||||
using ID = uint32_t;
 | 
			
		||||
using Consumption = uint32_t;
 | 
			
		||||
using CommodityType = uint32_t;
 | 
			
		||||
 | 
			
		||||
constexpr ID invalid_id = 0;
 | 
			
		||||
constexpr CommodityType invalid_commodity_type = -1;
 | 
			
		||||
constexpr Consumption invalid_consumption = 0;
 | 
			
		||||
 | 
			
		||||
class Packet {
 | 
			
		||||
public:
 | 
			
		||||
	enum class Type : uint32_t {
 | 
			
		||||
		Unknown = 0,
 | 
			
		||||
		IDM = 1,
 | 
			
		||||
		SCM = 2,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Packet(
 | 
			
		||||
		const Type type,
 | 
			
		||||
		const baseband::Packet& packet
 | 
			
		||||
	) : packet_ { packet },
 | 
			
		||||
		decoder_ { packet_ },
 | 
			
		||||
		reader_ { decoder_ },
 | 
			
		||||
		type_ { type }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t length() const;
 | 
			
		||||
	
 | 
			
		||||
	bool is_valid() const;
 | 
			
		||||
 | 
			
		||||
	Timestamp received_at() const;
 | 
			
		||||
 | 
			
		||||
	Type type() const;
 | 
			
		||||
	ID id() const;
 | 
			
		||||
	CommodityType commodity_type() const;
 | 
			
		||||
	Consumption consumption() const;
 | 
			
		||||
 | 
			
		||||
	FormattedSymbols symbols_formatted() const;
 | 
			
		||||
 | 
			
		||||
	bool crc_ok() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	using Reader = FieldReader<ManchesterDecoder, BitRemapNone>;
 | 
			
		||||
 | 
			
		||||
	const baseband::Packet packet_;
 | 
			
		||||
	const ManchesterDecoder decoder_;
 | 
			
		||||
	const Reader reader_;
 | 
			
		||||
	const Type type_;
 | 
			
		||||
 | 
			
		||||
	bool crc_ok_idm() const;
 | 
			
		||||
	bool crc_ok_scm() const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace ert */
 | 
			
		||||
 | 
			
		||||
#endif/*__ERT_PACKET_H__*/
 | 
			
		||||
							
								
								
									
										24
									
								
								Software/portapack-mayhem/firmware/common/event.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Software/portapack-mayhem/firmware/common/event.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "event.hpp"
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
							
								
								
									
										27
									
								
								Software/portapack-mayhem/firmware/common/event.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Software/portapack-mayhem/firmware/common/event.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __EVENT_H__
 | 
			
		||||
#define __EVENT_H__
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
#endif/*__EVENT_H__*/
 | 
			
		||||
							
								
								
									
										65
									
								
								Software/portapack-mayhem/firmware/common/field_reader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								Software/portapack-mayhem/firmware/common/field_reader.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __FIELD_READER_H__
 | 
			
		||||
#define __FIELD_READER_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
struct BitRemapNone {
 | 
			
		||||
	constexpr size_t operator()(const size_t& bit_index) const {
 | 
			
		||||
		return bit_index;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct BitRemapByteReverse {
 | 
			
		||||
	constexpr size_t operator()(const size_t bit_index) const {
 | 
			
		||||
		return bit_index ^ 7;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename T, typename BitRemap>
 | 
			
		||||
class FieldReader {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr FieldReader(
 | 
			
		||||
		const T& data
 | 
			
		||||
	) : data { data }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The "start_bit" winds up being the MSB of the returned field value. */
 | 
			
		||||
	/* The BitRemap functor determines which bits are read from the source
 | 
			
		||||
	 * packet. */
 | 
			
		||||
	int32_t read(const size_t start_bit, const size_t length) const { //Euquiq: was uint32_t, used for calculating lat / lon in radiosondes, can be negative too
 | 
			
		||||
		uint32_t value = 0;
 | 
			
		||||
		for(size_t i=start_bit; i<(start_bit + length); i++) {
 | 
			
		||||
			value = (value << 1) | data[bit_remap(i)];
 | 
			
		||||
		}
 | 
			
		||||
		return value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const T& data;
 | 
			
		||||
	const BitRemap bit_remap { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__FIELD_READER_H__*/
 | 
			
		||||
							
								
								
									
										239
									
								
								Software/portapack-mayhem/firmware/common/fifo.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								Software/portapack-mayhem/firmware/common/fifo.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __FIFO_H__
 | 
			
		||||
#define __FIFO_H__
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include <hal.h>
 | 
			
		||||
 | 
			
		||||
/* FIFO implementation inspired by Linux kfifo. */
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
class FIFO {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr FIFO(
 | 
			
		||||
		T* data,
 | 
			
		||||
		size_t k
 | 
			
		||||
	) : _data { data },
 | 
			
		||||
		_size { 1U << k },
 | 
			
		||||
		_in { 0 },
 | 
			
		||||
		_out { 0 }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void reset() {
 | 
			
		||||
		_in = _out = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void reset_in() {
 | 
			
		||||
		_in = _out;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void reset_out() {
 | 
			
		||||
		_out = _in;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t len() const {
 | 
			
		||||
		return _in - _out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t unused() const {
 | 
			
		||||
		return size() - (_in - _out);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_empty() const {
 | 
			
		||||
		return _in == _out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_full() const {
 | 
			
		||||
		return unused() == 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool in(const T& val) {
 | 
			
		||||
		if( is_full() ) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_data[_in & mask()] = val;
 | 
			
		||||
		smp_wmb();
 | 
			
		||||
		_in += 1;
 | 
			
		||||
		
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t in(const T* const buf, size_t len) {
 | 
			
		||||
		const size_t l = unused();
 | 
			
		||||
		if( len > l ) {
 | 
			
		||||
			len = l;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		copy_in(buf, len, _in);
 | 
			
		||||
		_in += len;
 | 
			
		||||
		return len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t in_r(const void* const buf, const size_t len) {
 | 
			
		||||
		if( (len + recsize()) > unused() ) {
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		poke_n(len);
 | 
			
		||||
		copy_in((const T*)buf, len, _in + recsize());
 | 
			
		||||
		_in += len + recsize();
 | 
			
		||||
		return len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool out(T& val) {
 | 
			
		||||
		if( is_empty() ) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		val = _data[_out & mask()];		// Crashes
 | 
			
		||||
		smp_wmb();						// Ok
 | 
			
		||||
		_out += 1;						// Crashes
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t out(T* const buf, size_t len) {
 | 
			
		||||
		len = out_peek(buf, len);
 | 
			
		||||
		_out += len;
 | 
			
		||||
		return len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool skip() {
 | 
			
		||||
		if( is_empty() ) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		size_t len = peek_n();
 | 
			
		||||
		_out += len + recsize();
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t peek_r(void* const buf, size_t len) {
 | 
			
		||||
		if( is_empty() ) {
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		size_t n;
 | 
			
		||||
		len = out_copy_r((T*)buf, len, &n);
 | 
			
		||||
		return len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t out_r(void* const buf, size_t len) {
 | 
			
		||||
		if( is_empty() ) {
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		size_t n;
 | 
			
		||||
		len = out_copy_r((T*)buf, len, &n);
 | 
			
		||||
		_out += n + recsize();
 | 
			
		||||
		return len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	size_t size() const {
 | 
			
		||||
		return _size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t esize() {
 | 
			
		||||
		return sizeof(T);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t mask() const {
 | 
			
		||||
		return size() - 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t recsize() {
 | 
			
		||||
		return 2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void smp_wmb() {
 | 
			
		||||
		__DMB();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t peek_n() {
 | 
			
		||||
		size_t l = _data[_out & mask()];
 | 
			
		||||
		if( recsize() > 1 ) {
 | 
			
		||||
			l |= _data[(_out + 1) & mask()] << 8;
 | 
			
		||||
		}
 | 
			
		||||
		return l;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void poke_n(const size_t n) {
 | 
			
		||||
		_data[_in & mask()] = n & 0xff;
 | 
			
		||||
		if( recsize() > 1 ) {
 | 
			
		||||
			_data[(_in + 1) & mask()] = (n >> 8) & 0xff;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void copy_in(const T* const src, const size_t len, size_t off) {
 | 
			
		||||
		off &= mask();
 | 
			
		||||
		const size_t l = std::min(len, size() - off);
 | 
			
		||||
 | 
			
		||||
		memcpy(&_data[off], &src[0], l * esize());
 | 
			
		||||
		memcpy(&_data[0], &src[l], (len - l) * esize());
 | 
			
		||||
		smp_wmb();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void copy_out(T* const dst, const size_t len, size_t off) {
 | 
			
		||||
		off &= mask();
 | 
			
		||||
		const size_t l = std::min(len, size() - off);
 | 
			
		||||
 | 
			
		||||
		memcpy(&dst[0], &_data[off], l * esize());
 | 
			
		||||
		memcpy(&dst[l], &_data[0], (len - l) * esize());
 | 
			
		||||
		smp_wmb();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t out_copy_r(void *buf, size_t len, size_t* const n) {
 | 
			
		||||
		*n = peek_n();
 | 
			
		||||
 | 
			
		||||
		if( len > *n ) {
 | 
			
		||||
			len = *n;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		copy_out((T*)buf, len, _out + recsize());
 | 
			
		||||
		return len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t out_peek(T* const buf, size_t buf_len) {
 | 
			
		||||
		const size_t l = len();
 | 
			
		||||
		if( buf_len > l ) {
 | 
			
		||||
			buf_len = l;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		copy_out(buf, buf_len, _out);
 | 
			
		||||
		return buf_len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	T* const _data;
 | 
			
		||||
	const size_t _size;
 | 
			
		||||
	volatile size_t _in;
 | 
			
		||||
	volatile size_t _out;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__FIFO_H__*/
 | 
			
		||||
							
								
								
									
										54
									
								
								Software/portapack-mayhem/firmware/common/gcc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Software/portapack-mayhem/firmware/common/gcc.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "gcc.hpp"
 | 
			
		||||
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
 | 
			
		||||
#if defined(TOOLCHAIN_GCC)
 | 
			
		||||
 | 
			
		||||
/* Note: Added to deal with static variables:
 | 
			
		||||
 * undefined reference to `__dso_handle'.
 | 
			
		||||
 * Comes up when using random C++ features, e.g. lambdas or std::function?
 | 
			
		||||
 */
 | 
			
		||||
void *__dso_handle;
 | 
			
		||||
 | 
			
		||||
/* prevents the exception handling name demangling code getting pulled in */
 | 
			
		||||
namespace __gnu_cxx {
 | 
			
		||||
	void __verbose_terminate_handler() {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* NOTE: Hack to address bloat when using C++ class virtual destructors.
 | 
			
		||||
 */
 | 
			
		||||
extern "C" __attribute__((weak)) void __cxa_pure_virtual(void) {
 | 
			
		||||
	chSysHalt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Implementing abort() eliminates requirement for _getpid(), _kill(),
 | 
			
		||||
 * _exit().
 | 
			
		||||
 */
 | 
			
		||||
extern "C" void abort() {
 | 
			
		||||
	/* while() loop to avoid noreturn-is-returning warning. */
 | 
			
		||||
	while(1) { chSysHalt(); }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								Software/portapack-mayhem/firmware/common/gcc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Software/portapack-mayhem/firmware/common/gcc.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GCC_H__
 | 
			
		||||
#define __GCC_H__
 | 
			
		||||
 | 
			
		||||
#endif/*__GCC_H__*/
 | 
			
		||||
							
								
								
									
										113
									
								
								Software/portapack-mayhem/firmware/common/gpdma.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Software/portapack-mayhem/firmware/common/gpdma.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "gpdma.hpp"
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
namespace lpc43xx {
 | 
			
		||||
namespace gpdma {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
struct ChannelHandlers {
 | 
			
		||||
	TCHandler tc;
 | 
			
		||||
	ErrHandler err;
 | 
			
		||||
 | 
			
		||||
	constexpr ChannelHandlers(
 | 
			
		||||
	) : tc(nullptr),
 | 
			
		||||
		err(nullptr)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static std::array<ChannelHandlers, channels.size()> handlers_table { {} };
 | 
			
		||||
 | 
			
		||||
namespace channel {
 | 
			
		||||
 | 
			
		||||
void Channel::set_handlers(const TCHandler tc_handler, const ErrHandler err_handler) const {
 | 
			
		||||
	handlers_table[number].tc = tc_handler;
 | 
			
		||||
	handlers_table[number].err = err_handler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Channel::configure(
 | 
			
		||||
	const LLI& first_lli,
 | 
			
		||||
	const uint32_t config
 | 
			
		||||
) const {
 | 
			
		||||
	disable();
 | 
			
		||||
	clear_interrupts();
 | 
			
		||||
 | 
			
		||||
	LPC_GPDMA_Channel_Type* const channel = &LPC_GPDMA->CH[number];
 | 
			
		||||
	channel->SRCADDR = first_lli.srcaddr;
 | 
			
		||||
	channel->DESTADDR = first_lli.destaddr;
 | 
			
		||||
	channel->LLI = first_lli.lli;
 | 
			
		||||
	channel->CONTROL = first_lli.control;
 | 
			
		||||
	channel->CONFIG = config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace channel */
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
CH_IRQ_HANDLER(DMA_IRQHandler) {
 | 
			
		||||
	CH_IRQ_PROLOGUE();
 | 
			
		||||
 | 
			
		||||
	chSysLockFromIsr();
 | 
			
		||||
 | 
			
		||||
	const auto tc_stat = LPC_GPDMA->INTTCSTAT;
 | 
			
		||||
	/* TODO: Service the higher channel numbers first, they're higher priority
 | 
			
		||||
	 * right?!?
 | 
			
		||||
	 */
 | 
			
		||||
	for(size_t i=0; i<handlers_table.size(); i++) {
 | 
			
		||||
		if( (tc_stat >> i) & 1 ) {
 | 
			
		||||
			if( handlers_table[i].tc ) {
 | 
			
		||||
				handlers_table[i].tc();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	LPC_GPDMA->INTTCCLR = tc_stat;
 | 
			
		||||
 | 
			
		||||
	/* Test for *any* error first, before looping, since errors should be
 | 
			
		||||
	 * exceptional and we should spend as little time on them in the common
 | 
			
		||||
	 * case.
 | 
			
		||||
	 */
 | 
			
		||||
	const auto err_stat = LPC_GPDMA->INTERRSTAT;
 | 
			
		||||
	if( err_stat ) {
 | 
			
		||||
		for(size_t i=0; i<handlers_table.size(); i++) {
 | 
			
		||||
			if( (err_stat >> i) & 1 ) {
 | 
			
		||||
				if( handlers_table[i].err ) {
 | 
			
		||||
					handlers_table[i].err();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		LPC_GPDMA->INTERRCLR = err_stat;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chSysUnlockFromIsr();
 | 
			
		||||
 | 
			
		||||
	CH_IRQ_EPILOGUE();
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace gpdma */
 | 
			
		||||
} /* namespace lpc43xx */
 | 
			
		||||
							
								
								
									
										375
									
								
								Software/portapack-mayhem/firmware/common/gpdma.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								Software/portapack-mayhem/firmware/common/gpdma.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,375 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GPDMA_H__
 | 
			
		||||
#define __GPDMA_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace lpc43xx {
 | 
			
		||||
namespace gpdma {
 | 
			
		||||
 | 
			
		||||
/* LPC43xx DMA appears to be the ARM PrimeCell(R) DMA Controller, or very
 | 
			
		||||
 * closely related.
 | 
			
		||||
 * More here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0196g/Chdcdaeb.html
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
constexpr size_t buffer_words(const size_t bytes, const size_t word_size) {
 | 
			
		||||
	return (bytes + word_size - 1) / word_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using TCHandler = void (*)(void);
 | 
			
		||||
using ErrHandler = void (*)(void);
 | 
			
		||||
 | 
			
		||||
enum class FlowControl {
 | 
			
		||||
	MemoryToMemory_DMAControl = 0x0,
 | 
			
		||||
	MemoryToPeripheral_DMAControl = 0x1,
 | 
			
		||||
	PeripheralToMemory_DMAControl = 0x2,
 | 
			
		||||
	SourcePeripheralToDestinationPeripheral_DMAControl = 0x3,
 | 
			
		||||
	SourcePeripheralToDestinationPeripheral_DestinationControl = 0x4,
 | 
			
		||||
	MemoryToPeripheral_PeripheralControl = 0x5,
 | 
			
		||||
	PeripheralToMemory_PeripheralControl = 0x6,
 | 
			
		||||
	SourcePeripheralToDestinationPeripheral_SourceControl = 0x7,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint_fast8_t flow_control_peripheral_source_map = 0b11011100;
 | 
			
		||||
 | 
			
		||||
constexpr uint_fast8_t source_endpoint_type(const FlowControl flow_control) {
 | 
			
		||||
	return (flow_control_peripheral_source_map >> toUType(flow_control)) & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const uint_fast8_t flow_control_peripheral_destination_map = 0b11111010;
 | 
			
		||||
 | 
			
		||||
constexpr uint_fast8_t destination_endpoint_type(const FlowControl flow_control) {
 | 
			
		||||
	return (flow_control_peripheral_destination_map >> toUType(flow_control)) & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace mux {
 | 
			
		||||
 | 
			
		||||
enum class Peripheral0 {
 | 
			
		||||
	SPIFI = 0,
 | 
			
		||||
	SCT_CTOUT_2 = 1,
 | 
			
		||||
	SGPIO14 = 2,
 | 
			
		||||
	TIMER3_MATCH_1 = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral1 {
 | 
			
		||||
	TIMER0_MATCH_0 = 0,
 | 
			
		||||
	USART0_TX = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral2 {
 | 
			
		||||
	TIMER0_MATCH_1 = 0,
 | 
			
		||||
	USART0_RX = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral3 {
 | 
			
		||||
	TIMER1_MATCH_0 = 0,
 | 
			
		||||
	UART1_TX = 1,
 | 
			
		||||
	I2S1_DMAREQ_1 = 2,
 | 
			
		||||
	SSP1_TX = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral4 {
 | 
			
		||||
	TIMER1_MATCH_1 = 0,
 | 
			
		||||
	UART1_RX = 1,
 | 
			
		||||
	I2S1_DMAREQ_2 = 2,
 | 
			
		||||
	SSP1_RX = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral5 {
 | 
			
		||||
	TIMER2_MATCH_0 = 0,
 | 
			
		||||
	USART2_TX = 1,
 | 
			
		||||
	SSP1_TX = 2,
 | 
			
		||||
	SGPIO15 = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral6 {
 | 
			
		||||
	TIMER2_MATCH_1 = 0,
 | 
			
		||||
	USART2_RX = 1,
 | 
			
		||||
	SSP1_RX = 2,
 | 
			
		||||
	SGPIO14 = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral7 {
 | 
			
		||||
	TIMER3_MATCH_0 = 0,
 | 
			
		||||
	USART3_TX = 1,
 | 
			
		||||
	SCT_DMAREQ_0 = 2,
 | 
			
		||||
	ADCHS_WRITE = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral8 {
 | 
			
		||||
	TIMER3_MATCH_1 = 0,
 | 
			
		||||
	USART3_RX = 1,
 | 
			
		||||
	SCT_DMAREQ_1 = 2,
 | 
			
		||||
	ADCHS_READ = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral9 {
 | 
			
		||||
	SSP0_RX = 0,
 | 
			
		||||
	I2S0_DMAREQ_1 = 1,
 | 
			
		||||
	SCT_DMAREQ_1 = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral10 {
 | 
			
		||||
	SSP0_TX = 0,
 | 
			
		||||
	I2S0_DMAREQ_2 = 1,
 | 
			
		||||
	SCT_DMAREQ_0 = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral11 {
 | 
			
		||||
	SSP1_RX = 0,
 | 
			
		||||
	SGPIO14 = 1,
 | 
			
		||||
	USART0_TX = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral12 {
 | 
			
		||||
	SSP1_TX = 0,
 | 
			
		||||
	SGPIO15 = 1,
 | 
			
		||||
	USART0_RX = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral13 {
 | 
			
		||||
	ADC0 = 0,
 | 
			
		||||
	SSP1_RX = 2,
 | 
			
		||||
	USART3_RX = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral14 {
 | 
			
		||||
	ADC1 = 0,
 | 
			
		||||
	SSP1_TX = 2,
 | 
			
		||||
	USART3_TX = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Peripheral15 {
 | 
			
		||||
	DAC = 0,
 | 
			
		||||
	SCT_CTOUT_3 = 1,
 | 
			
		||||
	SGPIO15 = 2,
 | 
			
		||||
	TIMER3_MATCH_0 = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MUX {
 | 
			
		||||
	Peripheral0 peripheral_0;
 | 
			
		||||
	Peripheral1 peripheral_1;
 | 
			
		||||
	Peripheral2 peripheral_2;
 | 
			
		||||
	Peripheral3 peripheral_3;
 | 
			
		||||
	Peripheral4 peripheral_4;
 | 
			
		||||
	Peripheral5 peripheral_5;
 | 
			
		||||
	Peripheral6 peripheral_6;
 | 
			
		||||
	Peripheral7 peripheral_7;
 | 
			
		||||
	Peripheral8 peripheral_8;
 | 
			
		||||
	Peripheral9 peripheral_9;
 | 
			
		||||
	Peripheral10 peripheral_10;
 | 
			
		||||
	Peripheral11 peripheral_11;
 | 
			
		||||
	Peripheral12 peripheral_12;
 | 
			
		||||
	Peripheral13 peripheral_13;
 | 
			
		||||
	Peripheral14 peripheral_14;
 | 
			
		||||
	Peripheral15 peripheral_15;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  (toUType(peripheral_0 ) <<  0)
 | 
			
		||||
			| (toUType(peripheral_1 ) <<  2)
 | 
			
		||||
			| (toUType(peripheral_2 ) <<  4)
 | 
			
		||||
			| (toUType(peripheral_3 ) <<  6)
 | 
			
		||||
			| (toUType(peripheral_4 ) <<  8)
 | 
			
		||||
			| (toUType(peripheral_5 ) << 10)
 | 
			
		||||
			| (toUType(peripheral_6 ) << 12)
 | 
			
		||||
			| (toUType(peripheral_7 ) << 14)
 | 
			
		||||
			| (toUType(peripheral_8 ) << 16)
 | 
			
		||||
			| (toUType(peripheral_9 ) << 18)
 | 
			
		||||
			| (toUType(peripheral_10) << 20)
 | 
			
		||||
			| (toUType(peripheral_11) << 22)
 | 
			
		||||
			| (toUType(peripheral_12) << 24)
 | 
			
		||||
			| (toUType(peripheral_13) << 26)
 | 
			
		||||
			| (toUType(peripheral_14) << 28)
 | 
			
		||||
			| (toUType(peripheral_15) << 30)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace mux */
 | 
			
		||||
 | 
			
		||||
namespace channel {
 | 
			
		||||
 | 
			
		||||
struct LLI {
 | 
			
		||||
	uint32_t srcaddr;
 | 
			
		||||
	uint32_t destaddr;
 | 
			
		||||
	uint32_t lli;
 | 
			
		||||
	uint32_t control;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LLIPointer {
 | 
			
		||||
	uint32_t lm;
 | 
			
		||||
	uint32_t r;
 | 
			
		||||
	uint32_t lli;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((lm & 1) << 0)
 | 
			
		||||
			| ((r & 1) << 1)
 | 
			
		||||
			| (lli & 0xfffffffc)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Control {
 | 
			
		||||
	uint32_t transfersize;
 | 
			
		||||
	uint32_t sbsize;
 | 
			
		||||
	uint32_t dbsize;
 | 
			
		||||
	uint32_t swidth;
 | 
			
		||||
	uint32_t dwidth;
 | 
			
		||||
	uint32_t s;
 | 
			
		||||
	uint32_t d;
 | 
			
		||||
	uint32_t si;
 | 
			
		||||
	uint32_t di;
 | 
			
		||||
	uint32_t prot1;
 | 
			
		||||
	uint32_t prot2;
 | 
			
		||||
	uint32_t prot3;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((transfersize & 0xfff) << 0)
 | 
			
		||||
			| ((sbsize & 7) << 12)
 | 
			
		||||
			| ((dbsize & 7) << 15)
 | 
			
		||||
			| ((swidth & 7) << 18)
 | 
			
		||||
			| ((dwidth & 7) << 21)
 | 
			
		||||
			| ((s & 1) << 24)
 | 
			
		||||
			| ((d & 1) << 25)
 | 
			
		||||
			| ((si & 1) << 26)
 | 
			
		||||
			| ((di & 1) << 27)
 | 
			
		||||
			| ((prot1 & 1) << 28)
 | 
			
		||||
			| ((prot2 & 1) << 29)
 | 
			
		||||
			| ((prot3 & 1) << 30)
 | 
			
		||||
			| ((i & 1) << 31)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Config {
 | 
			
		||||
	uint32_t e;
 | 
			
		||||
	uint32_t srcperipheral;
 | 
			
		||||
	uint32_t destperipheral;
 | 
			
		||||
	FlowControl flowcntrl;
 | 
			
		||||
	uint32_t ie;
 | 
			
		||||
	uint32_t itc;
 | 
			
		||||
	uint32_t l;
 | 
			
		||||
	uint32_t a;
 | 
			
		||||
	uint32_t h;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((e & 1) << 0)
 | 
			
		||||
			| ((srcperipheral & 0x1f) << 1)
 | 
			
		||||
			| ((destperipheral & 0x1f) << 6)
 | 
			
		||||
			| ((toUType(flowcntrl) & 7) << 11)
 | 
			
		||||
			| ((ie & 1) << 14)
 | 
			
		||||
			| ((itc & 1) << 15)
 | 
			
		||||
			| ((l & 1) << 16)
 | 
			
		||||
			| ((a & 1) << 17)
 | 
			
		||||
			| ((h & 1) << 18)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Channel {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr Channel(
 | 
			
		||||
		const size_t number
 | 
			
		||||
	) : number(number)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void enable() const {
 | 
			
		||||
		LPC_GPDMA->CH[number].CONFIG |= (1U << 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_enabled() const {
 | 
			
		||||
		return LPC_GPDMA->CH[number].CONFIG & (1U << 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void disable() const {
 | 
			
		||||
		LPC_GPDMA->CH[number].CONFIG &= ~(1U << 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void clear_interrupts() const {
 | 
			
		||||
		LPC_GPDMA->INTTCCLR = (1U << number);
 | 
			
		||||
		LPC_GPDMA->INTERRCLR = (1U << number);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_handlers(const TCHandler tc_handler, const ErrHandler err_handler) const;
 | 
			
		||||
 | 
			
		||||
	void configure(const LLI& first_lli, const uint32_t config) const;
 | 
			
		||||
 | 
			
		||||
	const LLI* next_lli() const {
 | 
			
		||||
		return reinterpret_cast<LLI*>(LPC_GPDMA->CH[number].LLI);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const size_t number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace channel */
 | 
			
		||||
 | 
			
		||||
constexpr std::array<channel::Channel, 8> channels { {
 | 
			
		||||
	{ 0 }, { 1 }, { 2 }, { 3 },
 | 
			
		||||
	{ 4 }, { 5 }, { 6 }, { 7 },
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
static const gpdma_resources_t gpdma_resources = {
 | 
			
		||||
  .base = { .clk = &LPC_CGU->BASE_M4_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 3) },
 | 
			
		||||
  .branch = { .cfg = &LPC_CCU1->CLK_M4_DMA_CFG, .stat = &LPC_CCU1->CLK_M4_DMA_STAT },
 | 
			
		||||
  .reset = { .output_index = 19 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Controller {
 | 
			
		||||
public:
 | 
			
		||||
	void enable() const {
 | 
			
		||||
		base_clock_enable(&gpdma_resources.base);
 | 
			
		||||
		branch_clock_enable(&gpdma_resources.branch);
 | 
			
		||||
		peripheral_reset(&gpdma_resources.reset);
 | 
			
		||||
		LPC_GPDMA->CONFIG |= (1U << 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void disable() const {
 | 
			
		||||
		for(const auto& channel : channels) {
 | 
			
		||||
			channel.disable();
 | 
			
		||||
		}
 | 
			
		||||
		LPC_GPDMA->CONFIG &= ~(1U << 0);
 | 
			
		||||
		peripheral_reset(&gpdma_resources.reset);
 | 
			
		||||
		branch_clock_disable(&gpdma_resources.branch);
 | 
			
		||||
		base_clock_disable(&gpdma_resources.base);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr Controller controller;
 | 
			
		||||
 | 
			
		||||
} /* namespace gpdma */
 | 
			
		||||
} /* namespace lpc43xx */
 | 
			
		||||
 | 
			
		||||
#endif/*__GPDMA_H__*/
 | 
			
		||||
							
								
								
									
										318
									
								
								Software/portapack-mayhem/firmware/common/gpio.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								Software/portapack-mayhem/firmware/common/gpio.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,318 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GPIO_H__
 | 
			
		||||
#define __GPIO_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
 | 
			
		||||
struct PinConfig {
 | 
			
		||||
	const uint32_t mode;
 | 
			
		||||
	const uint32_t pd;
 | 
			
		||||
	const uint32_t pu;
 | 
			
		||||
	const uint32_t fast;
 | 
			
		||||
	const uint32_t input;
 | 
			
		||||
	const uint32_t ifilt;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint16_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  (((~ifilt) & 1) << 7)
 | 
			
		||||
			|  ((input   & 1) << 6)
 | 
			
		||||
			|  ((fast    & 1) << 5)
 | 
			
		||||
			| (((~pu)    & 1) << 4)
 | 
			
		||||
			|  ((pd      & 1) << 3)
 | 
			
		||||
			|  ((mode    & 7) << 0);
 | 
			
		||||
	}
 | 
			
		||||
/*
 | 
			
		||||
	constexpr operator uint32_t() {
 | 
			
		||||
		return scu::sfs::mode::value(mode)
 | 
			
		||||
			<< scu::sfs::epd::value(pd)
 | 
			
		||||
			<< scu::sfs::epun::value(~pu)
 | 
			
		||||
			<< scu::sfs::ehs::value(fast)
 | 
			
		||||
			<< scu::sfs::ezi::value(input)
 | 
			
		||||
			<< scu::sfs::zif::value(~ifilt)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
*/
 | 
			
		||||
	static constexpr PinConfig reset() {
 | 
			
		||||
		return { .mode = 0, .pd = 0, .pu = 1, .fast = 0, .input = 0, .ifilt = 1 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig floating(
 | 
			
		||||
		const uint32_t mode
 | 
			
		||||
	) {
 | 
			
		||||
		return {
 | 
			
		||||
			.mode = mode,
 | 
			
		||||
			.pd = 0,
 | 
			
		||||
			.pu = 0,
 | 
			
		||||
			.fast = 0,
 | 
			
		||||
			.input = 0,
 | 
			
		||||
			.ifilt = 1
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig floating_input(
 | 
			
		||||
		const uint32_t mode
 | 
			
		||||
	) {
 | 
			
		||||
		return {
 | 
			
		||||
			.mode = mode,
 | 
			
		||||
			.pd = 0,
 | 
			
		||||
			.pu = 0,
 | 
			
		||||
			.fast = 0,
 | 
			
		||||
			.input = 1,
 | 
			
		||||
			.ifilt = 1
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig floating_input_with_pull(
 | 
			
		||||
		const uint32_t pull_direction,
 | 
			
		||||
		const uint32_t mode
 | 
			
		||||
	) {
 | 
			
		||||
		return {
 | 
			
		||||
			.mode = mode,
 | 
			
		||||
			.pd = (pull_direction == 0) ? 1U : 0U,
 | 
			
		||||
			.pu = (pull_direction == 1) ? 1U : 0U,
 | 
			
		||||
			.fast = 0,
 | 
			
		||||
			.input = 1,
 | 
			
		||||
			.ifilt = 1
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig gpio_led(const uint32_t mode) {
 | 
			
		||||
		return { .mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 0, .ifilt = 1 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig gpio_inout_with_pull(
 | 
			
		||||
		const uint32_t mode,
 | 
			
		||||
		const uint32_t pull_direction
 | 
			
		||||
	) {
 | 
			
		||||
		return {
 | 
			
		||||
			.mode = mode,
 | 
			
		||||
			.pd = (pull_direction == 0) ? 1U : 0U,
 | 
			
		||||
			.pu = (pull_direction == 1) ? 1U : 0U,
 | 
			
		||||
			.fast = 0,
 | 
			
		||||
			.input = 1,
 | 
			
		||||
			.ifilt = 1
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig gpio_inout_with_pullup(const uint32_t mode) {
 | 
			
		||||
		return gpio_inout_with_pull(mode, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig gpio_inout_with_pulldown(const uint32_t mode) {
 | 
			
		||||
		return gpio_inout_with_pull(mode, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig gpio_out_with_pull(
 | 
			
		||||
		const uint32_t mode,
 | 
			
		||||
		const uint32_t pull_direction
 | 
			
		||||
	) {
 | 
			
		||||
		return {
 | 
			
		||||
			.mode = mode,
 | 
			
		||||
			.pd = (pull_direction == 0) ? 1U : 0U,
 | 
			
		||||
			.pu = (pull_direction == 1) ? 1U : 0U,
 | 
			
		||||
			.fast = 0,
 | 
			
		||||
			.input = 0,
 | 
			
		||||
			.ifilt = 1
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig gpio_out_with_pulldown(const uint32_t mode) {
 | 
			
		||||
		return gpio_out_with_pull(mode, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig gpio_out_with_pullup(const uint32_t mode) {
 | 
			
		||||
		return gpio_out_with_pull(mode, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig sgpio_in_fast(const uint32_t mode) {
 | 
			
		||||
		return { .mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 1, .ifilt = 0 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig sgpio_out_fast_with_pull(
 | 
			
		||||
		const uint32_t mode,
 | 
			
		||||
		const uint32_t pull_direction
 | 
			
		||||
	) {
 | 
			
		||||
		return {
 | 
			
		||||
			.mode = mode,
 | 
			
		||||
			.pd = (pull_direction == 0) ? 1U : 0U,
 | 
			
		||||
			.pu = (pull_direction == 1) ? 1U : 0U,
 | 
			
		||||
			.fast = 1,
 | 
			
		||||
			.input = 0,
 | 
			
		||||
			.ifilt = 1
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig sgpio_out_fast_with_pullup(const uint32_t mode) {
 | 
			
		||||
		return sgpio_out_fast_with_pull(mode, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig sgpio_inout_fast(const uint32_t mode) {
 | 
			
		||||
		return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig i2c(const uint32_t mode) {
 | 
			
		||||
		return { .mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 1, .ifilt = 1 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig spifi_sck(const uint32_t mode ) {
 | 
			
		||||
		return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig spifi_inout(const uint32_t mode) {
 | 
			
		||||
		return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr PinConfig spifi_cs(const uint32_t mode) {
 | 
			
		||||
		return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Pin {
 | 
			
		||||
	// Pin() = delete;
 | 
			
		||||
	// Pin(const Pin&) = delete;
 | 
			
		||||
	// Pin(Pin&&) = delete;
 | 
			
		||||
 | 
			
		||||
	constexpr Pin(
 | 
			
		||||
		const uint8_t port,
 | 
			
		||||
		const uint8_t pad,
 | 
			
		||||
		const PinConfig initial_config
 | 
			
		||||
	) : _pin_port { port },
 | 
			
		||||
		_pin_pad { pad },
 | 
			
		||||
		_initial_config { initial_config }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
/*
 | 
			
		||||
	constexpr Pin(
 | 
			
		||||
		const Pin& pin
 | 
			
		||||
	) : _pin_port { pin._pin_port },
 | 
			
		||||
		_pin_pad { pin._pin_pad },
 | 
			
		||||
		_initial_config { pin._initial_config }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
*/
 | 
			
		||||
	void init() const {
 | 
			
		||||
		LPC_SCU->SFSP[_pin_port][_pin_pad] = _initial_config;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void mode(const uint_fast16_t mode) const {
 | 
			
		||||
		LPC_SCU->SFSP[_pin_port][_pin_pad] =
 | 
			
		||||
			(LPC_SCU->SFSP[_pin_port][_pin_pad] & 0xfffffff8) | mode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void configure(const PinConfig config) const {
 | 
			
		||||
		LPC_SCU->SFSP[_pin_port][_pin_pad] = config;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t _pin_port;
 | 
			
		||||
	uint8_t _pin_pad;
 | 
			
		||||
	uint16_t _initial_config;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct GPIO {
 | 
			
		||||
	// GPIO() = delete;
 | 
			
		||||
	// GPIO(const GPIO& gpio) = delete;
 | 
			
		||||
	// GPIO(GPIO&&) = delete;
 | 
			
		||||
 | 
			
		||||
	constexpr GPIO(
 | 
			
		||||
		const Pin& pin,
 | 
			
		||||
		const ioportid_t gpio_port,
 | 
			
		||||
		const iopadid_t gpio_pad,
 | 
			
		||||
		const uint16_t gpio_mode
 | 
			
		||||
	) : _pin { pin },
 | 
			
		||||
		_gpio_port { gpio_port },
 | 
			
		||||
		_gpio_pad { gpio_pad },
 | 
			
		||||
		_gpio_mode { gpio_mode }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
/*
 | 
			
		||||
	constexpr GPIO(
 | 
			
		||||
		const GPIO& gpio
 | 
			
		||||
	) : _pin { gpio._pin },
 | 
			
		||||
		_gpio_port { gpio._gpio_port },
 | 
			
		||||
		_gpio_pad { gpio._gpio_pad },
 | 
			
		||||
		_gpio_mode { gpio._gpio_mode }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
*/
 | 
			
		||||
	constexpr ioportid_t port() const {
 | 
			
		||||
		return _gpio_port;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr iopadid_t pad() const {
 | 
			
		||||
		return _gpio_pad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr Pin pin() const {
 | 
			
		||||
		return _pin;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void configure() const {
 | 
			
		||||
		_pin.mode(_gpio_mode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint_fast16_t mode() const {
 | 
			
		||||
		return _gpio_mode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set() const {
 | 
			
		||||
		palSetPad(_gpio_port, _gpio_pad);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void clear() const {
 | 
			
		||||
		palClearPad(_gpio_port, _gpio_pad);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void toggle() const {
 | 
			
		||||
		palTogglePad(_gpio_port, _gpio_pad);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void output() const {
 | 
			
		||||
		palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_OUTPUT_PUSHPULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void input() const {
 | 
			
		||||
		palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_INPUT);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void write(const bool value) const {
 | 
			
		||||
		palWritePad(_gpio_port, _gpio_pad, value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool read() const {
 | 
			
		||||
		return palReadPad(_gpio_port, _gpio_pad);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator!=(const GPIO& other) const {
 | 
			
		||||
		return (port() != other.port()) || (pad() != other.pad());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const Pin _pin;
 | 
			
		||||
	const ioportid_t _gpio_port;
 | 
			
		||||
	const iopadid_t _gpio_pad;
 | 
			
		||||
	const uint16_t _gpio_mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__GPIO_H__*/
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __HACKRF_CPLD_DATA_H__
 | 
			
		||||
#define __HACKRF_CPLD_DATA_H__
 | 
			
		||||
 | 
			
		||||
#include "cpld_xilinx.hpp"
 | 
			
		||||
 | 
			
		||||
namespace hackrf {
 | 
			
		||||
namespace one {
 | 
			
		||||
namespace cpld {
 | 
			
		||||
 | 
			
		||||
using CPLD = ::cpld::xilinx::XC2C64A;
 | 
			
		||||
 | 
			
		||||
extern const CPLD::verify_blocks_t verify_blocks;
 | 
			
		||||
 | 
			
		||||
} /* namespace hackrf */
 | 
			
		||||
} /* namespace one */
 | 
			
		||||
} /* namespace cpld */
 | 
			
		||||
 | 
			
		||||
#endif/*__HACKRF_CPLD_DATA_H__*/
 | 
			
		||||
							
								
								
									
										90
									
								
								Software/portapack-mayhem/firmware/common/hackrf_gpio.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								Software/portapack-mayhem/firmware/common/hackrf_gpio.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __HACKRF_GPIO_H__
 | 
			
		||||
#define __HACKRF_GPIO_H__
 | 
			
		||||
 | 
			
		||||
#include "pins.hpp"
 | 
			
		||||
#include "led.hpp"
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
namespace hackrf {
 | 
			
		||||
namespace one {
 | 
			
		||||
 | 
			
		||||
/* GPIO */
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_led_usb = gpio[GPIO2_1];
 | 
			
		||||
constexpr GPIO gpio_led_rx = gpio[GPIO2_2];
 | 
			
		||||
constexpr GPIO gpio_led_tx = gpio[GPIO2_8];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_1v8_enable = gpio[GPIO3_6];
 | 
			
		||||
constexpr GPIO gpio_vregmode = gpio[GPIO3_7];
 | 
			
		||||
constexpr GPIO gpio_vaa_disable = gpio[GPIO2_9];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_rx_mix_bp = gpio[GPIO2_12];
 | 
			
		||||
constexpr GPIO gpio_tx_mix_bp = gpio[GPIO2_11];
 | 
			
		||||
constexpr GPIO gpio_mix_bypass = gpio[GPIO5_16];
 | 
			
		||||
constexpr GPIO gpio_not_mix_bypass = gpio[GPIO1_0];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_rx = gpio[GPIO5_5];
 | 
			
		||||
constexpr GPIO gpio_tx = gpio[GPIO5_15];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_lp = gpio[GPIO2_10];
 | 
			
		||||
constexpr GPIO gpio_hp = gpio[GPIO2_0];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_rx_amp = gpio[GPIO1_11];
 | 
			
		||||
constexpr GPIO gpio_tx_amp = gpio[GPIO2_15];
 | 
			
		||||
constexpr GPIO gpio_amp_bypass = gpio[GPIO0_14];
 | 
			
		||||
constexpr GPIO gpio_not_rx_amp_pwr = gpio[GPIO1_12];
 | 
			
		||||
constexpr GPIO gpio_not_tx_amp_pwr = gpio[GPIO3_5];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_rffc5072_resetx = gpio[GPIO2_14];
 | 
			
		||||
constexpr GPIO gpio_rffc5072_select = gpio[GPIO2_13];
 | 
			
		||||
constexpr GPIO gpio_rffc5072_clock = gpio[GPIO5_6];
 | 
			
		||||
constexpr GPIO gpio_rffc5072_data = gpio[GPIO3_3];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_max2837_select = gpio[GPIO0_15];
 | 
			
		||||
constexpr GPIO gpio_max2837_enable = gpio[GPIO2_6];
 | 
			
		||||
constexpr GPIO gpio_max2837_rxenable = gpio[GPIO2_5];
 | 
			
		||||
constexpr GPIO gpio_max2837_txenable = gpio[GPIO2_4];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_max5864_select = gpio[GPIO2_7];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_baseband_invert = gpio[GPIO0_13];
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio_cpld_tdo = gpio[GPIO5_18];
 | 
			
		||||
constexpr GPIO gpio_cpld_tck = gpio[GPIO3_0];
 | 
			
		||||
constexpr GPIO gpio_cpld_tms = gpio[GPIO3_4];
 | 
			
		||||
constexpr GPIO gpio_cpld_tdi = gpio[GPIO3_1];
 | 
			
		||||
 | 
			
		||||
/* LEDs */
 | 
			
		||||
 | 
			
		||||
constexpr LED led_usb	{ gpio_led_usb };
 | 
			
		||||
constexpr LED led_rx	{ gpio_led_rx };
 | 
			
		||||
constexpr LED led_tx	{ gpio_led_tx };
 | 
			
		||||
 | 
			
		||||
} /* namespace one */
 | 
			
		||||
} /* namespace hackrf */
 | 
			
		||||
 | 
			
		||||
#endif/*__HACKRF_GPIO_H__*/
 | 
			
		||||
							
								
								
									
										32
									
								
								Software/portapack-mayhem/firmware/common/hackrf_hal.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Software/portapack-mayhem/firmware/common/hackrf_hal.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "hackrf_hal.hpp"
 | 
			
		||||
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
namespace hackrf {
 | 
			
		||||
namespace one {
 | 
			
		||||
 | 
			
		||||
} /* namespace one */
 | 
			
		||||
} /* namespace hackrf */
 | 
			
		||||
							
								
								
									
										79
									
								
								Software/portapack-mayhem/firmware/common/hackrf_hal.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								Software/portapack-mayhem/firmware/common/hackrf_hal.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __HACKRF_HAL_H__
 | 
			
		||||
#define __HACKRF_HAL_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "adc.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
namespace hackrf {
 | 
			
		||||
namespace one {
 | 
			
		||||
 | 
			
		||||
/* Clocks */
 | 
			
		||||
 | 
			
		||||
using ClockFrequency = uint32_t;
 | 
			
		||||
 | 
			
		||||
constexpr ClockFrequency si5351_xtal_f		= 25000000U;
 | 
			
		||||
constexpr ClockFrequency si5351_clkin_f		= 10000000U;
 | 
			
		||||
 | 
			
		||||
/* TODO: Use this many other places. */
 | 
			
		||||
/* TODO: M4/M0 and peripheral rates may be more PortaPack-specific? Move out
 | 
			
		||||
 * of HackRF header? */
 | 
			
		||||
constexpr ClockFrequency base_m4_clk_f		= 200000000U;
 | 
			
		||||
constexpr ClockFrequency base_m0_clk_f		= base_m4_clk_f;
 | 
			
		||||
constexpr ClockFrequency base_apb3_clk_f	= base_m4_clk_f;
 | 
			
		||||
constexpr ClockFrequency ssp1_pclk_f		= base_m4_clk_f;
 | 
			
		||||
 | 
			
		||||
constexpr ClockFrequency max5864_spi_f		= 20000000U;
 | 
			
		||||
constexpr ClockFrequency max2837_spi_f 		= 20000000U;
 | 
			
		||||
 | 
			
		||||
constexpr ClockFrequency rffc5072_reference_f	= 40000000U;
 | 
			
		||||
constexpr ClockFrequency max2837_reference_f	= 40000000U;
 | 
			
		||||
constexpr ClockFrequency mcu_clkin_f			= 40000000U;
 | 
			
		||||
 | 
			
		||||
constexpr uint8_t si5351_i2c_address = 0x60;
 | 
			
		||||
 | 
			
		||||
/* Clock Generator */
 | 
			
		||||
 | 
			
		||||
constexpr size_t clock_generator_output_codec		= 0;
 | 
			
		||||
constexpr size_t clock_generator_output_cpld		= 1;
 | 
			
		||||
constexpr size_t clock_generator_output_sgpio		= 2;
 | 
			
		||||
constexpr size_t clock_generator_output_clkout		= 3;
 | 
			
		||||
constexpr size_t clock_generator_output_first_if	= 4;
 | 
			
		||||
constexpr size_t clock_generator_output_second_if	= 5;
 | 
			
		||||
constexpr size_t clock_generator_output_mcu_clkin	= 7;
 | 
			
		||||
 | 
			
		||||
/* ADC0 */
 | 
			
		||||
 | 
			
		||||
using adc0 = adc::ADC<LPC_ADC0_BASE>;
 | 
			
		||||
 | 
			
		||||
/* ADC1 */
 | 
			
		||||
 | 
			
		||||
using adc1 = adc::ADC<LPC_ADC1_BASE>;
 | 
			
		||||
 | 
			
		||||
} /* namespace one */
 | 
			
		||||
} /* namespace hackrf */
 | 
			
		||||
 | 
			
		||||
#endif/*__HACKRF_HAL_H__*/
 | 
			
		||||
							
								
								
									
										65
									
								
								Software/portapack-mayhem/firmware/common/i2c_pp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								Software/portapack-mayhem/firmware/common/i2c_pp.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "i2c_pp.hpp"
 | 
			
		||||
 | 
			
		||||
void I2C::start(const I2CConfig& config) {
 | 
			
		||||
	i2cStart(_driver, &config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void I2C::stop() {
 | 
			
		||||
	i2cStop(_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool I2C::transfer(
 | 
			
		||||
	const address_t slave_address,
 | 
			
		||||
	const uint8_t* const data_tx, const size_t count_tx,
 | 
			
		||||
	uint8_t* const data_rx, const size_t count_rx,
 | 
			
		||||
	systime_t timeout
 | 
			
		||||
) {
 | 
			
		||||
	i2cAcquireBus(_driver);
 | 
			
		||||
	const msg_t status = i2cMasterTransmitTimeout(
 | 
			
		||||
		_driver, slave_address, data_tx, count_tx, data_rx, count_rx, timeout
 | 
			
		||||
	);
 | 
			
		||||
	i2cReleaseBus(_driver);
 | 
			
		||||
	return (status == RDY_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool I2C::receive(
 | 
			
		||||
	const address_t slave_address,
 | 
			
		||||
	uint8_t* const data, const size_t count,
 | 
			
		||||
	systime_t timeout
 | 
			
		||||
) {
 | 
			
		||||
	i2cAcquireBus(_driver);
 | 
			
		||||
	const msg_t status = i2cMasterReceiveTimeout(
 | 
			
		||||
		_driver, slave_address, data, count, timeout
 | 
			
		||||
	);
 | 
			
		||||
	i2cReleaseBus(_driver);
 | 
			
		||||
	return (status == RDY_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool I2C::transmit(
 | 
			
		||||
	const address_t slave_address,
 | 
			
		||||
	const uint8_t* const data, const size_t count,
 | 
			
		||||
	systime_t timeout
 | 
			
		||||
) {
 | 
			
		||||
	return transfer(slave_address, data, count, NULL, 0, timeout);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								Software/portapack-mayhem/firmware/common/i2c_pp.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								Software/portapack-mayhem/firmware/common/i2c_pp.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __I2C_PP_H__
 | 
			
		||||
#define __I2C_PP_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
 | 
			
		||||
struct I2CClockConfig {
 | 
			
		||||
	float clock_source_f;
 | 
			
		||||
	float bus_f;
 | 
			
		||||
	float high_period_ns;
 | 
			
		||||
 | 
			
		||||
	static constexpr float period_ns(const float f) {
 | 
			
		||||
		return 1e9 / f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr uint32_t i2c_period_count() const {
 | 
			
		||||
		return period_ns(bus_f) / period_ns(clock_source_f) + 0.5f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr uint32_t i2c_high_count() const {
 | 
			
		||||
		return high_period_ns / period_ns(clock_source_f) + 0.5f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr uint32_t i2c_low_count() const {
 | 
			
		||||
		return i2c_period_count() - i2c_high_count();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class I2C {
 | 
			
		||||
public:
 | 
			
		||||
	using address_t = uint8_t;
 | 
			
		||||
 | 
			
		||||
	constexpr I2C(I2CDriver* const driver) :
 | 
			
		||||
		_driver(driver) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void start(const I2CConfig& config);
 | 
			
		||||
	void stop();
 | 
			
		||||
 | 
			
		||||
	bool receive(
 | 
			
		||||
		const address_t slave_address,
 | 
			
		||||
		uint8_t* const data, const size_t count,
 | 
			
		||||
		const systime_t timeout = TIME_INFINITE
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	bool transmit(
 | 
			
		||||
		const address_t slave_address,
 | 
			
		||||
		const uint8_t* const data, const size_t count,
 | 
			
		||||
		const systime_t timeout = TIME_INFINITE
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	I2CDriver* const _driver;
 | 
			
		||||
 | 
			
		||||
	bool transfer(
 | 
			
		||||
		const address_t slave_address,
 | 
			
		||||
		const uint8_t* const data_tx, const size_t count_tx,
 | 
			
		||||
		uint8_t* const data_rx, const size_t count_rx,
 | 
			
		||||
		const systime_t timeout
 | 
			
		||||
	);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__I2C_PP_H__*/
 | 
			
		||||
							
								
								
									
										277
									
								
								Software/portapack-mayhem/firmware/common/i2s.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								Software/portapack-mayhem/firmware/common/i2s.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,277 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __I2S_H__
 | 
			
		||||
#define __I2S_H__
 | 
			
		||||
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace lpc43xx {
 | 
			
		||||
namespace i2s {
 | 
			
		||||
 | 
			
		||||
enum class WordWidth {
 | 
			
		||||
	Bits8 = 0x0,
 | 
			
		||||
	Bits16 = 0x1,
 | 
			
		||||
	Bits32 = 0x3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class ClockSelect {
 | 
			
		||||
	FractionalDivider = 0x0,
 | 
			
		||||
	BaseAudioClkOrExternalMCLK = 0x01,
 | 
			
		||||
	OtherMCLK = 0x2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct DAO {
 | 
			
		||||
	WordWidth wordwidth;
 | 
			
		||||
	uint32_t mono;
 | 
			
		||||
	uint32_t stop;
 | 
			
		||||
	uint32_t reset;
 | 
			
		||||
	uint32_t ws_sel;
 | 
			
		||||
	uint32_t ws_halfperiod;
 | 
			
		||||
	uint32_t mute;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((toUType(wordwidth) & 3) << 0)
 | 
			
		||||
			| ((mono & 1) << 2)
 | 
			
		||||
			| ((stop & 1) << 3)
 | 
			
		||||
			| ((reset & 1) << 4)
 | 
			
		||||
			| ((ws_sel & 1) << 5)
 | 
			
		||||
			| ((ws_halfperiod & 0x1ff) << 6)
 | 
			
		||||
			| ((mute & 1) << 15)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct DAI {
 | 
			
		||||
	WordWidth wordwidth;
 | 
			
		||||
	uint32_t mono;
 | 
			
		||||
	uint32_t stop;
 | 
			
		||||
	uint32_t reset;
 | 
			
		||||
	uint32_t ws_sel;
 | 
			
		||||
	uint32_t ws_halfperiod;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((toUType(wordwidth) & 3) << 0)
 | 
			
		||||
			| ((mono & 1) << 2)
 | 
			
		||||
			| ((stop & 1) << 3)
 | 
			
		||||
			| ((reset & 1) << 4)
 | 
			
		||||
			| ((ws_sel & 1) << 5)
 | 
			
		||||
			| ((ws_halfperiod & 0x1ff) << 6)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MCLKRate {
 | 
			
		||||
	uint32_t x_divider;
 | 
			
		||||
	uint32_t y_divider;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((y_divider & 0xff) << 0)
 | 
			
		||||
			| ((x_divider & 0xff) << 8)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct BitRate {
 | 
			
		||||
	uint32_t bitrate;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return ((bitrate & 0x3f) << 0);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Mode {
 | 
			
		||||
	ClockSelect clksel;
 | 
			
		||||
	uint32_t four_pin;
 | 
			
		||||
	uint32_t mclk_out_en;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((toUType(clksel) & 3) << 0)
 | 
			
		||||
			| ((four_pin & 1) << 2)
 | 
			
		||||
			| ((mclk_out_en & 1) << 3)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct DMA {
 | 
			
		||||
	uint32_t rx_enable;
 | 
			
		||||
	uint32_t tx_enable;
 | 
			
		||||
	size_t rx_depth;
 | 
			
		||||
	size_t tx_depth;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((rx_enable & 1) << 0)
 | 
			
		||||
			| ((tx_enable & 1) << 1)
 | 
			
		||||
			| ((rx_depth & 0xf) << 8)
 | 
			
		||||
			| ((tx_depth & 0xf) << 16)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ConfigTX {
 | 
			
		||||
	uint32_t dao;
 | 
			
		||||
	uint32_t txrate;
 | 
			
		||||
	uint32_t txbitrate;
 | 
			
		||||
	uint32_t txmode;
 | 
			
		||||
	uint32_t sck_in_sel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ConfigRX {
 | 
			
		||||
	uint32_t dai;
 | 
			
		||||
	uint32_t rxrate;
 | 
			
		||||
	uint32_t rxbitrate;
 | 
			
		||||
	uint32_t rxmode;
 | 
			
		||||
	uint32_t sck_in_sel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ConfigDMA {
 | 
			
		||||
	uint32_t dma1;
 | 
			
		||||
	uint32_t dma2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const audio_clock_resources_t audio_clock_resources = {
 | 
			
		||||
	.base = { .clk = &LPC_CGU->BASE_AUDIO_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = 0 },
 | 
			
		||||
	.branch = { .cfg = &LPC_CCU2->CLK_AUDIO_CFG, .stat = &LPC_CCU2->CLK_AUDIO_STAT },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const i2s_resources_t i2s_resources = {
 | 
			
		||||
	.base = { .clk = &LPC_CGU->BASE_APB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 1) },
 | 
			
		||||
	.branch = { .cfg = &LPC_CCU1->CLK_APB1_I2S_CFG, .stat = &LPC_CCU1->CLK_APB1_I2S_STAT },
 | 
			
		||||
	.reset = { { .output_index = 52 }, { .output_index = 53 } },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<uint32_t BaseAddress>
 | 
			
		||||
class I2S {
 | 
			
		||||
public:
 | 
			
		||||
	static void configure(
 | 
			
		||||
		const ConfigTX& config_tx,
 | 
			
		||||
		const ConfigRX& config_rx
 | 
			
		||||
	) {
 | 
			
		||||
		base_clock_enable(&i2s_resources.base);
 | 
			
		||||
		branch_clock_enable(&i2s_resources.branch);
 | 
			
		||||
 | 
			
		||||
		base_clock_enable(&audio_clock_resources.base);
 | 
			
		||||
		branch_clock_enable(&audio_clock_resources.branch);
 | 
			
		||||
 | 
			
		||||
		if( &p() == LPC_I2S0 ) {
 | 
			
		||||
			peripheral_reset(&i2s_resources.reset[0]);
 | 
			
		||||
		}
 | 
			
		||||
		if( &p() == LPC_I2S1 ) {
 | 
			
		||||
			peripheral_reset(&i2s_resources.reset[1]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		reset();
 | 
			
		||||
 | 
			
		||||
		if( &p() == LPC_I2S0 ) {
 | 
			
		||||
			LPC_CREG->CREG6.I2S0_TX_SCK_IN_SEL = config_tx.sck_in_sel;
 | 
			
		||||
			LPC_CREG->CREG6.I2S0_RX_SCK_IN_SEL = config_rx.sck_in_sel;
 | 
			
		||||
		}
 | 
			
		||||
		if( &p() == LPC_I2S1 ) {
 | 
			
		||||
			LPC_CREG->CREG6.I2S1_TX_SCK_IN_SEL = config_tx.sck_in_sel;
 | 
			
		||||
			LPC_CREG->CREG6.I2S1_RX_SCK_IN_SEL = config_rx.sck_in_sel;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p().DAO = config_tx.dao;
 | 
			
		||||
		p().TXRATE = config_tx.txrate;
 | 
			
		||||
		p().TXBITRATE = config_tx.txbitrate;
 | 
			
		||||
		p().TXMODE = config_tx.txmode;
 | 
			
		||||
 | 
			
		||||
		p().DAI = config_rx.dai;
 | 
			
		||||
		p().RXRATE = config_rx.rxrate;
 | 
			
		||||
		p().RXBITRATE = config_rx.rxbitrate;
 | 
			
		||||
		p().RXMODE = config_rx.rxmode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void configure(
 | 
			
		||||
		const ConfigTX& config_tx,
 | 
			
		||||
		const ConfigRX& config_rx,
 | 
			
		||||
		const ConfigDMA& config_dma
 | 
			
		||||
	) {
 | 
			
		||||
		configure(config_tx, config_rx);
 | 
			
		||||
 | 
			
		||||
		p().DMA1 = config_dma.dma1;
 | 
			
		||||
		p().DMA2 = config_dma.dma2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void shutdown() {
 | 
			
		||||
		if( &p() == LPC_I2S0 ) {
 | 
			
		||||
			peripheral_reset(&i2s_resources.reset[0]);
 | 
			
		||||
		}
 | 
			
		||||
		if( &p() == LPC_I2S1 ) {
 | 
			
		||||
			peripheral_reset(&i2s_resources.reset[1]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		branch_clock_disable(&audio_clock_resources.branch);
 | 
			
		||||
		base_clock_disable(&audio_clock_resources.base);
 | 
			
		||||
 | 
			
		||||
		branch_clock_disable(&i2s_resources.branch);
 | 
			
		||||
		base_clock_disable(&i2s_resources.base);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void rx_start() {
 | 
			
		||||
		p().DAI &= ~(1U << 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void rx_stop() {
 | 
			
		||||
		p().DAI |= (1U << 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void tx_start() {
 | 
			
		||||
		p().DAO &= ~(1U << 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void tx_stop() {
 | 
			
		||||
		p().DAO |= (1U << 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void tx_mute() {
 | 
			
		||||
		p().DAO |= (1U << 15);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void tx_unmute() {
 | 
			
		||||
		p().DAO &= ~(1U << 15);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static void reset() {
 | 
			
		||||
		p().DAO |= (1U << 4);
 | 
			
		||||
		p().DAI |= (1U << 4);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static LPC_I2S_Type& p() {
 | 
			
		||||
		return *reinterpret_cast<LPC_I2S_Type*>(BaseAddress);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using i2s0 = I2S<LPC_I2S0_BASE>;
 | 
			
		||||
using i2s1 = I2S<LPC_I2S1_BASE>;
 | 
			
		||||
 | 
			
		||||
} /* namespace i2s */
 | 
			
		||||
} /* namespace lpc43xx */
 | 
			
		||||
 | 
			
		||||
#endif/*__I2S_H__*/
 | 
			
		||||
							
								
								
									
										34
									
								
								Software/portapack-mayhem/firmware/common/jammer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Software/portapack-mayhem/firmware/common/jammer.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "jammer.hpp"
 | 
			
		||||
 | 
			
		||||
#include "baseband_api.hpp"
 | 
			
		||||
#include "portapack.hpp"
 | 
			
		||||
using namespace portapack;
 | 
			
		||||
 | 
			
		||||
#include "string_format.hpp"
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace jammer {
 | 
			
		||||
 | 
			
		||||
} /* namespace jammer */
 | 
			
		||||
							
								
								
									
										45
									
								
								Software/portapack-mayhem/firmware/common/jammer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Software/portapack-mayhem/firmware/common/jammer.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define JAMMER_CH_WIDTH 1000000
 | 
			
		||||
#define JAMMER_MAX_CH 24
 | 
			
		||||
 | 
			
		||||
#ifndef __JAMMER_H__
 | 
			
		||||
#define __JAMMER_H__
 | 
			
		||||
 | 
			
		||||
namespace jammer {
 | 
			
		||||
 | 
			
		||||
typedef struct jammer_range {
 | 
			
		||||
	bool enabled;
 | 
			
		||||
	int64_t min;
 | 
			
		||||
	int64_t max;
 | 
			
		||||
} jammer_range_t;
 | 
			
		||||
 | 
			
		||||
enum JammerType : uint32_t {
 | 
			
		||||
	TYPE_FSK = 0,
 | 
			
		||||
	TYPE_TONE = 1,
 | 
			
		||||
	TYPE_SWEEP = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace jammer */
 | 
			
		||||
 | 
			
		||||
#endif/*__JAMMER_H__*/
 | 
			
		||||
							
								
								
									
										41
									
								
								Software/portapack-mayhem/firmware/common/jtag.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								Software/portapack-mayhem/firmware/common/jtag.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "jtag.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
namespace jtag {
 | 
			
		||||
 | 
			
		||||
uint32_t JTAG::shift(const size_t count, uint32_t value) {
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const auto tdo = target.clock(
 | 
			
		||||
			(i == (count - 1)) ? 1 : 0,
 | 
			
		||||
			value & 1
 | 
			
		||||
		);
 | 
			
		||||
		value >>= 1;
 | 
			
		||||
		value |= tdo << (count - 1);
 | 
			
		||||
	}
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace jtag */
 | 
			
		||||
							
								
								
									
										101
									
								
								Software/portapack-mayhem/firmware/common/jtag.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Software/portapack-mayhem/firmware/common/jtag.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __JTAG_H__
 | 
			
		||||
#define __JTAG_H__
 | 
			
		||||
 | 
			
		||||
#include "jtag_target.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
namespace jtag {
 | 
			
		||||
 | 
			
		||||
class JTAG {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr JTAG(
 | 
			
		||||
		Target& target
 | 
			
		||||
	) : target(target)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void reset() {
 | 
			
		||||
		/* ??? -> Test-Logic-Reset */
 | 
			
		||||
		for(size_t i=0; i<8; i++) {
 | 
			
		||||
			target.clock(1, 0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void run_test_idle() {
 | 
			
		||||
		/* Test-Logic-Reset -> Run-Test/Idle */
 | 
			
		||||
		target.clock(0, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void runtest_tck(const size_t count) {
 | 
			
		||||
		target.delay(count);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t shift_ir(const size_t count, const uint32_t value) {
 | 
			
		||||
		/* Run-Test/Idle -> Select-DR-Scan -> Select-IR-Scan */
 | 
			
		||||
		target.clock(1, 0);
 | 
			
		||||
		target.clock(1, 0);
 | 
			
		||||
		/* Scan -> Capture -> Shift */
 | 
			
		||||
		target.clock(0, 0);
 | 
			
		||||
		target.clock(0, 0);
 | 
			
		||||
 | 
			
		||||
		const auto result = shift(count, value);
 | 
			
		||||
 | 
			
		||||
		/* Exit1 -> Update */
 | 
			
		||||
		target.clock(1, 0);
 | 
			
		||||
		/* Update -> Run-Test/Idle */
 | 
			
		||||
		target.clock(0, 0);
 | 
			
		||||
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t shift_dr(const size_t count, const uint32_t value) {
 | 
			
		||||
		/* Run-Test/Idle -> Select-DR-Scan */
 | 
			
		||||
		target.clock(1, 0);
 | 
			
		||||
		/* Scan -> Capture -> Shift */
 | 
			
		||||
		target.clock(0, 0);
 | 
			
		||||
		target.clock(0, 0);
 | 
			
		||||
 | 
			
		||||
		const auto result = shift(count, value);
 | 
			
		||||
 | 
			
		||||
		/* Exit1 -> Update */
 | 
			
		||||
		target.clock(1, 0);
 | 
			
		||||
		/* Update -> Run-Test/Idle */
 | 
			
		||||
		target.clock(0, 0);
 | 
			
		||||
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Target& target;
 | 
			
		||||
 | 
			
		||||
	uint32_t shift(const size_t count, uint32_t value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace jtag */
 | 
			
		||||
 | 
			
		||||
#endif/*__JTAG_H__*/
 | 
			
		||||
							
								
								
									
										266
									
								
								Software/portapack-mayhem/firmware/common/jtag_tap.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								Software/portapack-mayhem/firmware/common/jtag_tap.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,266 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "jtag_tap.hpp"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace jtag {
 | 
			
		||||
namespace tap {
 | 
			
		||||
 | 
			
		||||
size_t bits_t::length() const {
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bits_t::operator bool() const {
 | 
			
		||||
	return (count > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool bits_t::operator[](const size_t index) const {
 | 
			
		||||
	if( p && (index < count) ) {
 | 
			
		||||
		const auto n = bytes() * 8 - index - 1;
 | 
			
		||||
		const auto byte = n >> 3;
 | 
			
		||||
		const auto bit = (n ^ 7) & 7;
 | 
			
		||||
		return (p[byte] >> bit) & 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		return default_value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t bits_t::bytes() const {
 | 
			
		||||
	return (count + 7) >> 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JTAG_TAP_DEBUG
 | 
			
		||||
static char nibble_to_hex_char(const uint8_t v) {
 | 
			
		||||
	if( v < 0xa ) {
 | 
			
		||||
		return 0x30 + v;
 | 
			
		||||
	} else {
 | 
			
		||||
		return 0x57 + v;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string to_string(const bits_t& bits) {
 | 
			
		||||
	std::string s { std::to_string(bits.length()) + "/0x" };
 | 
			
		||||
	for(size_t i=0; i<bytes(); i++) {
 | 
			
		||||
		s += nibble_to_hex_char((bits.p[i] >> 4) & 0xf);
 | 
			
		||||
		s += nibble_to_hex_char((bits.p[i] >> 0) & 0xf);
 | 
			
		||||
	}
 | 
			
		||||
	return s;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
using route_t = uint16_t;
 | 
			
		||||
 | 
			
		||||
struct entry_t {
 | 
			
		||||
	state_t tms[2];
 | 
			
		||||
	route_t route;
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(entry_t) == 4, "Unexpected size of entry_t");
 | 
			
		||||
 | 
			
		||||
using table_t = std::array<entry_t, 16>;
 | 
			
		||||
static_assert(sizeof(table_t) == (16 * 4), "Unexpected size of table_t");
 | 
			
		||||
 | 
			
		||||
const table_t table { {
 | 
			
		||||
	{ state_t::run_test_idle,	state_t::test_logic_reset,	0b0000000000000001 },	// test_logic_reset	test_logic_reset => 1, others => 0
 | 
			
		||||
	{ state_t::run_test_idle,	state_t::select_dr_scan,	0b1111111111111101 },	// run_test_idle	run_test_idle => 0, others => 1
 | 
			
		||||
	{ state_t::capture_dr,		state_t::select_ir_scan,	0b1111111000000001 },	// select_dr_scan	run_test_idle..update_dr => 0, others => 1
 | 
			
		||||
	{ state_t::shift_dr,		state_t::exit1_dr,			0b1111111111101111 },	// capture_dr		shift_dr => 0, others => 1
 | 
			
		||||
	{ state_t::shift_dr,		state_t::exit1_dr,			0b1111111111101111 },	// shift_dr			shift_dr => 0, others => 1
 | 
			
		||||
	{ state_t::pause_dr,		state_t::update_dr,			0b1111111100111111 },	// exit1_dr			pause_dr, exit2_dr => 0, others => 1
 | 
			
		||||
	{ state_t::pause_dr,		state_t::exit2_dr,			0b1111111110111111 },	// pause_dr			pause_dr => 0, others => 1
 | 
			
		||||
	{ state_t::shift_dr,		state_t::update_dr,			0b1111111111101111 },	// exit2_dr			shift_dr => 0, others => 1
 | 
			
		||||
	{ state_t::run_test_idle, 	state_t::select_dr_scan,	0b1111111111111101 },	// update_dr		run_test_idle => 0, others => 1
 | 
			
		||||
	{ state_t::capture_ir,		state_t::test_logic_reset,	0b0000000000000001 },	// select_ir_scan	test_logic_reset => 1, others => 0
 | 
			
		||||
	{ state_t::shift_ir,		state_t::exit1_ir,			0b1111011111111111 },	// capture_ir		shift_ir => 0, others => 1
 | 
			
		||||
	{ state_t::shift_ir,		state_t::exit1_ir,			0b1111011111111111 },	// shift_ir			shift_ir => 0, others => 1
 | 
			
		||||
	{ state_t::pause_ir,		state_t::update_ir,			0b1001111111111111 },	// exit1_ir			pause_ir, exit2_ir => 0, others => 1
 | 
			
		||||
	{ state_t::pause_ir,		state_t::exit2_ir,			0b1101111111111111 },	// pause_ir			pause_ir => 0, others => 1
 | 
			
		||||
	{ state_t::shift_ir,		state_t::update_ir,			0b1111011111111111 },	// exit2_ir			shift_ir => 0, others => 1
 | 
			
		||||
	{ state_t::run_test_idle,	state_t::select_dr_scan,	0b1111111111111101 },	// update_ir		run_test_idle => 0, others => 1
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
const std::array<const char*, 16> state_name { {
 | 
			
		||||
	"test_logic_reset",
 | 
			
		||||
	"run_test_idle",
 | 
			
		||||
	"select_dr_scan",
 | 
			
		||||
	"capture_dr",
 | 
			
		||||
	"shift_dr",
 | 
			
		||||
	"exit1_dr",
 | 
			
		||||
	"pause_dr",
 | 
			
		||||
	"exit2_dr",
 | 
			
		||||
	"update_dr",
 | 
			
		||||
	"select_ir_scan",
 | 
			
		||||
	"capture_ir",
 | 
			
		||||
	"shift_ir",
 | 
			
		||||
	"exit1_ir",
 | 
			
		||||
	"pause_ir",
 | 
			
		||||
	"exit2_ir",
 | 
			
		||||
	"update_ir",
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
const std::array<const char*, 16> state_long_name { {
 | 
			
		||||
	"Test-Logic-Reset",
 | 
			
		||||
	"Run-Test/Idle",
 | 
			
		||||
	"Select-DR-Scan",
 | 
			
		||||
	"Capture-DR",
 | 
			
		||||
	"Shift-DR",
 | 
			
		||||
	"Exit1-DR",
 | 
			
		||||
	"Pause-DR",
 | 
			
		||||
	"Exit2-DR",
 | 
			
		||||
	"Update-DR",
 | 
			
		||||
	"Select-IR-Scan",
 | 
			
		||||
	"Capture-IR",
 | 
			
		||||
	"Shift-IR",
 | 
			
		||||
	"Exit1-IR",
 | 
			
		||||
	"Pause-IR",
 | 
			
		||||
	"Exit2-IR",
 | 
			
		||||
	"Update-IR",
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
const entry_t& entry(const state_t state) {
 | 
			
		||||
	return table[toUType(state)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace */
 | 
			
		||||
 | 
			
		||||
const char* c_str(const state_t state) {
 | 
			
		||||
	return state_name[toUType(state)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* TAPState **************************************************************/
 | 
			
		||||
 | 
			
		||||
state_t TAPState::state() const {
 | 
			
		||||
	return _state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPState::advance(const bool tms) {
 | 
			
		||||
	_state = entry(_state).tms[tms];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TAPState::advance_toward(const state_t desired_state) const {
 | 
			
		||||
	return (entry(_state).route >> toUType(desired_state)) & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* TAPMachine ************************************************************/
 | 
			
		||||
 | 
			
		||||
void TAPMachine::set_run_test(const uint32_t value) {
 | 
			
		||||
	_run_test = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::set_repeat(const uint8_t value) {
 | 
			
		||||
	_repeat = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::set_end_ir(const state_t state) {
 | 
			
		||||
	_end_ir = state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::set_end_dr(const state_t state) {
 | 
			
		||||
	_end_dr = state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TAPMachine::shift_ir(const bits_t& tdi_value, const bits_t& tdo_expected, const bits_t& tdo_mask) {
 | 
			
		||||
	return shift_data(tdi_value, tdo_expected, tdo_mask, state_t::shift_ir, _end_ir, _run_test);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TAPMachine::shift_dr(const bits_t& tdi_value, const bits_t& tdo_expected, const bits_t& tdo_mask) {
 | 
			
		||||
	return shift_data(tdi_value, tdo_expected, tdo_mask, state_t::shift_dr, _end_dr, _run_test);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::state(const state_t state) {
 | 
			
		||||
	if( state == state_t::test_logic_reset ) {
 | 
			
		||||
		for(int i=0; i<5; i++) {
 | 
			
		||||
			clock(1);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		advance_to_state(state);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::wait(const state_t wait_state, const state_t end_state, const uint32_t wait_time) {
 | 
			
		||||
	advance_to_state(wait_state);
 | 
			
		||||
	delay_us(wait_time);
 | 
			
		||||
	advance_to_state(end_state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TAPMachine::clock(const bool tms, const bool tdi) {
 | 
			
		||||
	tap.advance(tms);
 | 
			
		||||
	return target.clock(tms, tdi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::advance_to_state(const state_t desired_state) {
 | 
			
		||||
	while( tap.state() != desired_state ) {
 | 
			
		||||
		const auto tms = tap.advance_toward(desired_state);
 | 
			
		||||
		clock(tms);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::delay_us(const uint32_t microseconds) {
 | 
			
		||||
	target.delay(microseconds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::shift_start(const state_t state) {
 | 
			
		||||
	advance_to_state(state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TAPMachine::shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms) {
 | 
			
		||||
	if( tdo_expected.length() != tdo_mask.length() ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if( tdo_expected && (tdi.length() != tdo_expected.length()) ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto tdo_error = false;
 | 
			
		||||
	for(uint32_t i=0; i<tdi.length(); i++) {
 | 
			
		||||
		const auto tms = end_tms & (i == (tdi.length() - 1));
 | 
			
		||||
		const auto tdo = clock(tms, tdi[i]);
 | 
			
		||||
		if( tdo_expected && tdo_mask ) {
 | 
			
		||||
			tdo_error |= (tdo & tdo_mask[i]) != (tdo_expected[i] & tdo_mask[i]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tdo_error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TAPMachine::shift_end(const state_t end_state, const uint32_t end_delay) {
 | 
			
		||||
	if( end_delay ) {
 | 
			
		||||
		advance_to_state(state_t::run_test_idle);
 | 
			
		||||
		delay_us(end_delay);
 | 
			
		||||
	} else {
 | 
			
		||||
		advance_to_state(end_state);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TAPMachine::shift_data(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const state_t state, const state_t end_state, const uint32_t end_delay) {
 | 
			
		||||
	shift_start(state);
 | 
			
		||||
	const auto result = shift(tdi, tdo_expected, tdo_mask, true);
 | 
			
		||||
	shift_end(end_state, end_delay);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace tap */
 | 
			
		||||
} /* namespace jtag */
 | 
			
		||||
							
								
								
									
										155
									
								
								Software/portapack-mayhem/firmware/common/jtag_tap.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								Software/portapack-mayhem/firmware/common/jtag_tap.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __JTAG_TAP_H__
 | 
			
		||||
#define __JTAG_TAP_H__
 | 
			
		||||
 | 
			
		||||
#include "jtag_target.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
namespace jtag {
 | 
			
		||||
namespace tap {
 | 
			
		||||
 | 
			
		||||
class bits_t {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr bits_t(
 | 
			
		||||
	) : p { nullptr },
 | 
			
		||||
		count { 0 }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr bits_t(
 | 
			
		||||
		const size_t count,
 | 
			
		||||
		const bool default_value = true
 | 
			
		||||
	) : p { nullptr },
 | 
			
		||||
		count { count },
 | 
			
		||||
		default_value { default_value }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr bits_t(
 | 
			
		||||
		const uint8_t* const p,
 | 
			
		||||
		const size_t count
 | 
			
		||||
	) : p { p },
 | 
			
		||||
		count { count }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t length() const;
 | 
			
		||||
 | 
			
		||||
	explicit operator bool() const;
 | 
			
		||||
 | 
			
		||||
	bool operator[](const size_t index) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const uint8_t* p { nullptr };
 | 
			
		||||
	size_t count { 0 };
 | 
			
		||||
	bool default_value { false };
 | 
			
		||||
 | 
			
		||||
	size_t bytes() const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class state_t : uint8_t {
 | 
			
		||||
	/* Ordinal values are important for "routes" values, and to match XSVF definitions. */
 | 
			
		||||
	test_logic_reset = 0,
 | 
			
		||||
	run_test_idle = 1,
 | 
			
		||||
	select_dr_scan = 2,
 | 
			
		||||
	capture_dr = 3,
 | 
			
		||||
	shift_dr = 4,
 | 
			
		||||
	exit1_dr = 5,
 | 
			
		||||
	pause_dr = 6,
 | 
			
		||||
	exit2_dr = 7,
 | 
			
		||||
	update_dr = 8,
 | 
			
		||||
	select_ir_scan = 9,
 | 
			
		||||
	capture_ir = 10,
 | 
			
		||||
	shift_ir = 11,
 | 
			
		||||
	exit1_ir = 12,
 | 
			
		||||
	pause_ir = 13,
 | 
			
		||||
	exit2_ir = 14,
 | 
			
		||||
	update_ir = 15,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class TAPState {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr TAPState(
 | 
			
		||||
	) : _state { state_t::test_logic_reset }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state_t state() const;
 | 
			
		||||
	void advance(const bool tms);
 | 
			
		||||
	bool advance_toward(const state_t desired_state) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	state_t _state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class TAPMachine {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr TAPMachine(
 | 
			
		||||
		jtag::Target& target
 | 
			
		||||
	) : target { target }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_run_test(const uint32_t value);
 | 
			
		||||
	void set_repeat(const uint8_t value);
 | 
			
		||||
	void set_end_ir(const state_t state);
 | 
			
		||||
	void set_end_dr(const state_t state);
 | 
			
		||||
 | 
			
		||||
	bool shift(const bits_t& tdi, const bool end_tms) {
 | 
			
		||||
		return shift(tdi, {}, {}, end_tms);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	bool shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms);
 | 
			
		||||
 | 
			
		||||
	bool shift_ir(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
 | 
			
		||||
	bool shift_dr(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
 | 
			
		||||
 | 
			
		||||
	void state(const state_t state);
 | 
			
		||||
	
 | 
			
		||||
	void wait(const state_t wait_state, const state_t end_state, const uint32_t wait_time);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	jtag::Target& target;
 | 
			
		||||
	TAPState tap { };
 | 
			
		||||
 | 
			
		||||
	uint32_t _run_test { 0 };
 | 
			
		||||
	uint8_t _repeat { 0 };
 | 
			
		||||
	state_t _end_ir { };
 | 
			
		||||
	state_t _end_dr { };
 | 
			
		||||
 | 
			
		||||
	bool clock(const bool tms, const bool tdi=false);
 | 
			
		||||
	void advance_to_state(const state_t desired_state);
 | 
			
		||||
	void delay_us(const uint32_t microseconds);
 | 
			
		||||
 | 
			
		||||
	void shift_start(const state_t state);
 | 
			
		||||
	void shift_end(const state_t end_state, const uint32_t end_delay);
 | 
			
		||||
 | 
			
		||||
	bool shift_data(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const state_t state, const state_t end_state, const uint32_t end_delay);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace tap */
 | 
			
		||||
} /* namespace jtag */
 | 
			
		||||
 | 
			
		||||
#endif/*__JTAG_TAP_H__*/
 | 
			
		||||
							
								
								
									
										46
									
								
								Software/portapack-mayhem/firmware/common/jtag_target.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Software/portapack-mayhem/firmware/common/jtag_target.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __JTAG_TARGET_H__
 | 
			
		||||
#define __JTAG_TARGET_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
namespace jtag {
 | 
			
		||||
 | 
			
		||||
class Target {
 | 
			
		||||
public:
 | 
			
		||||
	using bit_t = uint_fast8_t;
 | 
			
		||||
 | 
			
		||||
	virtual ~Target() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void delay(const size_t n) = 0;
 | 
			
		||||
	virtual bit_t clock(
 | 
			
		||||
		const bit_t tms_value,
 | 
			
		||||
		const bit_t tdi_value
 | 
			
		||||
	) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace jtag */
 | 
			
		||||
 | 
			
		||||
#endif/*__JTAG_TARGET_H__*/
 | 
			
		||||
							
								
								
									
										140
									
								
								Software/portapack-mayhem/firmware/common/jtag_target_gpio.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								Software/portapack-mayhem/firmware/common/jtag_target_gpio.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __JTAG_TARGET_GPIO_H__
 | 
			
		||||
#define __JTAG_TARGET_GPIO_H__
 | 
			
		||||
 | 
			
		||||
#include "jtag_target.hpp"
 | 
			
		||||
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
namespace jtag {
 | 
			
		||||
 | 
			
		||||
class GPIOTarget : public Target {
 | 
			
		||||
public:
 | 
			
		||||
	// Tightly control how this object can be constructor or copied, since
 | 
			
		||||
	// it initializes GPIOs in the constructor. I don't want it re-
 | 
			
		||||
	// initializing a bunch as the object gets passed around. So don't let
 | 
			
		||||
	// it get passed around...
 | 
			
		||||
	/*
 | 
			
		||||
	GPIOTarget() = delete;
 | 
			
		||||
	GPIOTarget(const GPIOTarget&) = delete;
 | 
			
		||||
	GPIOTarget(GPIOTarget&&) = delete;
 | 
			
		||||
	GPIOTarget& operator=(const GPIOTarget&) = delete;
 | 
			
		||||
	GPIOTarget& operator=(GPIOTarget&&) = delete;
 | 
			
		||||
	*/
 | 
			
		||||
	GPIOTarget(
 | 
			
		||||
		GPIO gpio_tck,
 | 
			
		||||
		GPIO gpio_tms,
 | 
			
		||||
		GPIO gpio_tdi,
 | 
			
		||||
		GPIO gpio_tdo
 | 
			
		||||
	) : gpio_tck { gpio_tck },
 | 
			
		||||
		gpio_tms { gpio_tms },
 | 
			
		||||
		gpio_tdi { gpio_tdi },
 | 
			
		||||
		gpio_tdo { gpio_tdo }
 | 
			
		||||
	{
 | 
			
		||||
		gpio_tdi.write(1);
 | 
			
		||||
		gpio_tdi.output();
 | 
			
		||||
		gpio_tdi.configure();
 | 
			
		||||
 | 
			
		||||
		gpio_tms.write(1);
 | 
			
		||||
		gpio_tms.output();
 | 
			
		||||
		gpio_tms.configure();
 | 
			
		||||
 | 
			
		||||
		gpio_tck.write(0);
 | 
			
		||||
		gpio_tck.output();
 | 
			
		||||
		gpio_tck.configure();
 | 
			
		||||
 | 
			
		||||
		gpio_tdo.input();
 | 
			
		||||
		gpio_tdo.configure();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~GPIOTarget() {
 | 
			
		||||
		gpio_tdi.input();
 | 
			
		||||
		gpio_tms.input();
 | 
			
		||||
		gpio_tck.input();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void delay(const size_t clocks) override {
 | 
			
		||||
		/* TODO: Use more precise timing mechanism, using the frequency
 | 
			
		||||
		 * specified by SVF file.
 | 
			
		||||
		 */
 | 
			
		||||
        halPolledDelay(clocks * systicks_per_tck);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Target::bit_t clock(
 | 
			
		||||
		const Target::bit_t tms_value,
 | 
			
		||||
		const Target::bit_t tdi_value
 | 
			
		||||
	) override {
 | 
			
		||||
		/* TODO: Use more precise timing mechanism, using the frequency
 | 
			
		||||
		 * specified by SVF file.
 | 
			
		||||
		 */
 | 
			
		||||
		const auto result = tdo();
 | 
			
		||||
		tms(tms_value);
 | 
			
		||||
		tdi(tdi_value);
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		tck(1);
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		__asm__("nop");
 | 
			
		||||
		tck(0);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	/* At 200MHz, one 18MHz cycle is 11 systicks. */
 | 
			
		||||
	static constexpr size_t systicks_per_tck = 11;
 | 
			
		||||
 | 
			
		||||
	GPIO gpio_tck;
 | 
			
		||||
	GPIO gpio_tms;
 | 
			
		||||
	GPIO gpio_tdi;
 | 
			
		||||
	GPIO gpio_tdo;
 | 
			
		||||
 | 
			
		||||
	void tck(const Target::bit_t value) {
 | 
			
		||||
		gpio_tck.write(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void tdi(const Target::bit_t value) {
 | 
			
		||||
		gpio_tdi.write(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void tms(const bit_t value) {
 | 
			
		||||
		gpio_tms.write(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Target::bit_t tdo() {
 | 
			
		||||
		return gpio_tdo.read();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace jtag */
 | 
			
		||||
 | 
			
		||||
#endif/*__JTAG_TARGET_GPIO_H__*/
 | 
			
		||||
							
								
								
									
										660
									
								
								Software/portapack-mayhem/firmware/common/lcd_ili9341.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										660
									
								
								Software/portapack-mayhem/firmware/common/lcd_ili9341.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,660 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lcd_ili9341.hpp"
 | 
			
		||||
#include "bmp.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_io.hpp"
 | 
			
		||||
using namespace portapack;
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
#include "file.hpp"
 | 
			
		||||
 | 
			
		||||
#include <complex>
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace lcd {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
void lcd_reset() {
 | 
			
		||||
	io.lcd_reset_state(false);
 | 
			
		||||
	chThdSleepMilliseconds(1);
 | 
			
		||||
	io.lcd_reset_state(true);
 | 
			
		||||
	chThdSleepMilliseconds(10);
 | 
			
		||||
	io.lcd_reset_state(false);
 | 
			
		||||
	chThdSleepMilliseconds(120);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_sleep_in() {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x10, {});
 | 
			
		||||
	// "It will be necessary to wait 5msec before sending next command,
 | 
			
		||||
	// this is to allow time for the supply voltages and clock circuits
 | 
			
		||||
	// to stabilize."
 | 
			
		||||
	chThdSleepMilliseconds(5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_sleep_out() {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x11, {});
 | 
			
		||||
	// "It will be necessary to wait 120msec after sending Sleep Out
 | 
			
		||||
	// command (when in Sleep In Mode) before Sleep In command can be
 | 
			
		||||
	// sent."
 | 
			
		||||
	chThdSleepMilliseconds(120);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_display_on() {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x29, {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_display_off() {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x28, {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_sleep() {
 | 
			
		||||
	lcd_display_off();
 | 
			
		||||
	lcd_sleep_in();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_wake() {
 | 
			
		||||
	lcd_sleep_out();
 | 
			
		||||
	lcd_display_on();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_init() {
 | 
			
		||||
	// LCDs are configured for IM[2:0] = 001
 | 
			
		||||
	// 8080-I system, 16-bit parallel bus
 | 
			
		||||
 | 
			
		||||
	//
 | 
			
		||||
	// 0x3a: DBI[2:0] = 101
 | 
			
		||||
	// MDT[1:0] = XX (if not in 18-bit mode, right?)
 | 
			
		||||
 | 
			
		||||
	// Power control B
 | 
			
		||||
	// 0
 | 
			
		||||
	// PCEQ=1, DRV_ena=0, Power control=3
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xCF, { 0x00, 0xD9, 0x30 });
 | 
			
		||||
 | 
			
		||||
	// Power on sequence control
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xED, { 0x64, 0x03, 0x12, 0x81 });
 | 
			
		||||
 | 
			
		||||
	// Driver timing control A
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xE8, { 0x85, 0x10, 0x78 });
 | 
			
		||||
 | 
			
		||||
	// Power control A
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xCB, { 0x39, 0x2C, 0x00, 0x34, 0x02 });
 | 
			
		||||
 | 
			
		||||
	// Pump ratio control
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xF7, { 0x20 });
 | 
			
		||||
 | 
			
		||||
	// Driver timing control B
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xEA, { 0x00, 0x00 });
 | 
			
		||||
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xB1, { 0x00, 0x1B });
 | 
			
		||||
 | 
			
		||||
	// Blanking Porch Control
 | 
			
		||||
	// VFP = 0b0000010 = 2 (number of HSYNC of vertical front porch)
 | 
			
		||||
	// VBP = 0b0000010 = 2 (number of HSYNC of vertical back porch)
 | 
			
		||||
	// HFP = 0b0001010 = 10 (number of DOTCLOCK of horizontal front porch)
 | 
			
		||||
	// HBP = 0b0010100 = 20 (number of DOTCLOCK of horizontal back porch)
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xB5, { 0x02, 0x02, 0x0a, 0x14 });
 | 
			
		||||
 | 
			
		||||
	// Display Function Control
 | 
			
		||||
	// PT[1:0] = 0b10
 | 
			
		||||
	// PTG[1:0] = 0b10
 | 
			
		||||
	// ISC[3:0] = 0b0010 (scan cycle interval of gate driver: 5 frames)
 | 
			
		||||
	// SM = 0 (gate driver pin arrangement in combination with GS)
 | 
			
		||||
	// SS = 1 (source output scan direction S720 -> S1)
 | 
			
		||||
	// GS = 0 (gate output scan direction G1 -> G320)
 | 
			
		||||
	// REV = 1 (normally white)
 | 
			
		||||
	// NL = 0b100111 (default)
 | 
			
		||||
	// PCDIV = 0b000000 (default?)
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xB6, { 0x0A, 0xA2, 0x27, 0x00 });
 | 
			
		||||
 | 
			
		||||
	// Power Control 1
 | 
			
		||||
	//VRH[5:0]
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xC0, { 0x1B });
 | 
			
		||||
 | 
			
		||||
	// Power Control 2
 | 
			
		||||
	//SAP[2:0];BT[3:0]
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xC1, { 0x12 });
 | 
			
		||||
 | 
			
		||||
	// VCOM Control 1
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xC5, { 0x32, 0x3C });
 | 
			
		||||
 | 
			
		||||
	// VCOM Control 2
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xC7, { 0x9B });
 | 
			
		||||
 | 
			
		||||
	// Memory Access Control
 | 
			
		||||
	// Invert X and Y memory access order, so upper-left of
 | 
			
		||||
	// screen is (0,0) when writing to display.
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x36, {
 | 
			
		||||
		(1 << 7) |	// MY=1
 | 
			
		||||
		(1 << 6) |	// MX=1
 | 
			
		||||
		(0 << 5) |	// MV=0
 | 
			
		||||
		(1 << 4) |	// ML=1: reverse vertical refresh to simplify scrolling logic
 | 
			
		||||
		(1 << 3)	// BGR=1: For Kingtech LCD, BGR filter.
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// COLMOD: Pixel Format Set
 | 
			
		||||
	// DPI=101 (16 bits/pixel), DBI=101 (16 bits/pixel)
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x3A, { 0x55 });
 | 
			
		||||
 | 
			
		||||
	//io.lcd_data_write_command_and_data(0xF6, { 0x01, 0x30 });
 | 
			
		||||
	// WEMODE=1 (reset column and page number on overflow)
 | 
			
		||||
	// MDT[1:0]
 | 
			
		||||
	// EPF[1:0]=00 (use channel MSB for LSB)
 | 
			
		||||
	// RIM=0 (If COLMOD[6:4]=101 (65k color), 16-bit RGB interface (1 transfer/pixel))
 | 
			
		||||
	// RM=0 (system interface/VSYNC interface)
 | 
			
		||||
	// DM[1:0]=00 (internal clock operation)
 | 
			
		||||
	// ENDIAN=0 (doesn't matter with 16-bit interface)
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xF6, { 0x01, 0x30, 0x00 });
 | 
			
		||||
 | 
			
		||||
	// 3Gamma Function Disable
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xF2, { 0x00 });
 | 
			
		||||
 | 
			
		||||
	// Gamma curve selected
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x26, { 0x01 });
 | 
			
		||||
 | 
			
		||||
	// Set Gamma
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xE0, {
 | 
			
		||||
		0x0F, 0x1D, 0x19, 0x0E, 0x10, 0x07, 0x4C, 0x63,
 | 
			
		||||
		0x3F, 0x03, 0x0D, 0x00, 0x26, 0x24, 0x04
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// Set Gamma
 | 
			
		||||
	io.lcd_data_write_command_and_data(0xE1, {
 | 
			
		||||
		0x00, 0x1C, 0x1F, 0x02, 0x0F, 0x03, 0x35, 0x25,
 | 
			
		||||
		0x47, 0x04, 0x0C, 0x0B, 0x29, 0x2F, 0x05
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	lcd_wake();
 | 
			
		||||
 | 
			
		||||
	// Turn on Tearing Effect Line (TE) output signal.
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x35, { 0b00000000 });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_set(const uint_fast8_t command, const uint_fast16_t start, const uint_fast16_t end) {
 | 
			
		||||
	io.lcd_data_write_command_and_data(command, {
 | 
			
		||||
		static_cast<uint8_t>(start >> 8), static_cast<uint8_t>(start & 0xff),
 | 
			
		||||
		static_cast<uint8_t>(end   >> 8), static_cast<uint8_t>(end   & 0xff)
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_ramwr_start() {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x2c, {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_ramrd_start() {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x2e, {});
 | 
			
		||||
	io.lcd_read_word();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_caset(const uint_fast16_t start_column, uint_fast16_t end_column) {
 | 
			
		||||
	lcd_set(0x2a, start_column, end_column);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_paset(const uint_fast16_t start_page, const uint_fast16_t end_page) {
 | 
			
		||||
	lcd_set(0x2b, start_page, end_page);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_start_ram_write(
 | 
			
		||||
	const ui::Point p,
 | 
			
		||||
	const ui::Size s
 | 
			
		||||
) {
 | 
			
		||||
	lcd_caset(p.x(), p.x() + s.width()  - 1);
 | 
			
		||||
	lcd_paset(p.y(), p.y() + s.height() - 1);
 | 
			
		||||
	lcd_ramwr_start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_start_ram_read(
 | 
			
		||||
	const ui::Point p,
 | 
			
		||||
	const ui::Size s
 | 
			
		||||
) {
 | 
			
		||||
	lcd_caset(p.x(), p.x() + s.width()  - 1);
 | 
			
		||||
	lcd_paset(p.y(), p.y() + s.height() - 1);
 | 
			
		||||
	lcd_ramrd_start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_start_ram_write(
 | 
			
		||||
	const ui::Rect& r
 | 
			
		||||
) {
 | 
			
		||||
	lcd_start_ram_write(r.location(), r.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_start_ram_read(
 | 
			
		||||
	const ui::Rect& r
 | 
			
		||||
) {
 | 
			
		||||
	lcd_start_ram_read(r.location(), r.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_vertical_scrolling_definition(
 | 
			
		||||
	const uint_fast16_t top_fixed_area,
 | 
			
		||||
	const uint_fast16_t vertical_scrolling_area,
 | 
			
		||||
	const uint_fast16_t bottom_fixed_area
 | 
			
		||||
) {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x33, {
 | 
			
		||||
		static_cast<uint8_t>(top_fixed_area            >> 8),
 | 
			
		||||
		static_cast<uint8_t>(top_fixed_area          & 0xff),
 | 
			
		||||
		static_cast<uint8_t>(vertical_scrolling_area   >> 8),
 | 
			
		||||
		static_cast<uint8_t>(vertical_scrolling_area & 0xff),
 | 
			
		||||
		static_cast<uint8_t>(bottom_fixed_area         >> 8),
 | 
			
		||||
		static_cast<uint8_t>(bottom_fixed_area       & 0xff)
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_vertical_scrolling_start_address(
 | 
			
		||||
	const uint_fast16_t vertical_scrolling_pointer
 | 
			
		||||
) {
 | 
			
		||||
	io.lcd_data_write_command_and_data(0x37, {
 | 
			
		||||
		static_cast<uint8_t>(vertical_scrolling_pointer >> 8),
 | 
			
		||||
		static_cast<uint8_t>(vertical_scrolling_pointer & 0xff)
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::init() {
 | 
			
		||||
	lcd_reset();
 | 
			
		||||
	lcd_init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::shutdown() {
 | 
			
		||||
	lcd_reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::sleep() {
 | 
			
		||||
	lcd_sleep();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::wake() {
 | 
			
		||||
	lcd_wake();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) {
 | 
			
		||||
	const auto r_clipped = r.intersect(screen_rect());
 | 
			
		||||
	if( !r_clipped.is_empty() ) {
 | 
			
		||||
		lcd_start_ram_write(r_clipped);
 | 
			
		||||
		size_t count = r_clipped.width() * r_clipped.height();
 | 
			
		||||
		io.lcd_write_pixels(c, count);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::fill_rectangle_unrolled8(ui::Rect r, const ui::Color c) {
 | 
			
		||||
	const auto r_clipped = r.intersect(screen_rect());
 | 
			
		||||
	if( !r_clipped.is_empty() ) {
 | 
			
		||||
		lcd_start_ram_write(r_clipped);
 | 
			
		||||
		size_t count = r_clipped.width() * r_clipped.height();
 | 
			
		||||
		io.lcd_write_pixels_unrolled8(c, count);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer) {
 | 
			
		||||
	lcd_start_ram_write(p, { count, 1 });
 | 
			
		||||
	io.lcd_write_pixels(line_buffer, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer) {
 | 
			
		||||
	lcd_start_ram_write(p, s);
 | 
			
		||||
	io.lcd_write_pixels(line_buffer, s.width() * s.height());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RLE_4 BMP loader (delta not implemented)
 | 
			
		||||
void ILI9341::drawBMP(const ui::Point p, const uint8_t * bitmap, const bool transparency) {
 | 
			
		||||
	const bmp_header_t * bmp_header = (const bmp_header_t *)bitmap;
 | 
			
		||||
	uint32_t data_idx;
 | 
			
		||||
	uint8_t by, c, count, transp_idx = 0;
 | 
			
		||||
	ui::Color line_buffer[240];
 | 
			
		||||
	uint16_t px = 0, py;
 | 
			
		||||
	ui::Color palette[16];
 | 
			
		||||
	
 | 
			
		||||
	// Abort if bad depth or no RLE
 | 
			
		||||
	if ((bmp_header->bpp != 4) ||
 | 
			
		||||
		(bmp_header->compression != 2)) return;
 | 
			
		||||
 | 
			
		||||
	data_idx = bmp_header->image_data;
 | 
			
		||||
	const bmp_palette_t * bmp_palette = (const bmp_palette_t *)&bitmap[bmp_header->BIH_size + 14];
 | 
			
		||||
	
 | 
			
		||||
	// Convert palette and find pure magenta index (alpha color key)
 | 
			
		||||
	for (c = 0; c < 16; c++) {
 | 
			
		||||
		palette[c] = ui::Color(bmp_palette->color[c].R, bmp_palette->color[c].G, bmp_palette->color[c].B);
 | 
			
		||||
		if ((bmp_palette->color[c].R == 0xFF) &&
 | 
			
		||||
			(bmp_palette->color[c].G == 0x00) &&
 | 
			
		||||
			(bmp_palette->color[c].B == 0xFF)) transp_idx = c;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!transparency) {
 | 
			
		||||
		py = bmp_header->height + 16;
 | 
			
		||||
		do {
 | 
			
		||||
			by = bitmap[data_idx++];
 | 
			
		||||
			if (by) {
 | 
			
		||||
				count = by >> 1;
 | 
			
		||||
				by = bitmap[data_idx++];
 | 
			
		||||
				for (c = 0; c < count; c++) {
 | 
			
		||||
					line_buffer[px++] = palette[by >> 4];
 | 
			
		||||
					if (px < bmp_header->width) line_buffer[px++] = palette[by & 15];
 | 
			
		||||
				}
 | 
			
		||||
				if (data_idx & 1) data_idx++;
 | 
			
		||||
			} else {
 | 
			
		||||
				by = bitmap[data_idx++];
 | 
			
		||||
				if (by == 0) {
 | 
			
		||||
					render_line({p.x(), p.y() + py}, bmp_header->width, line_buffer);
 | 
			
		||||
					py--;
 | 
			
		||||
					px = 0;
 | 
			
		||||
				} else if (by == 1) {
 | 
			
		||||
					break;
 | 
			
		||||
				} else if (by == 2) {
 | 
			
		||||
					// Delta
 | 
			
		||||
				} else {
 | 
			
		||||
					count = by >> 1;
 | 
			
		||||
					for (c = 0; c < count; c++) {
 | 
			
		||||
						by = bitmap[data_idx++];
 | 
			
		||||
						line_buffer[px++] = palette[by >> 4];
 | 
			
		||||
						if (px < bmp_header->width) line_buffer[px++] = palette[by & 15];
 | 
			
		||||
					}
 | 
			
		||||
					if (data_idx & 1) data_idx++;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} while (1);
 | 
			
		||||
	} else {
 | 
			
		||||
		py = bmp_header->height;
 | 
			
		||||
		do {
 | 
			
		||||
			by = bitmap[data_idx++];
 | 
			
		||||
			if (by) {
 | 
			
		||||
				count = by >> 1;
 | 
			
		||||
				by = bitmap[data_idx++];
 | 
			
		||||
				for (c = 0; c < count; c++) {
 | 
			
		||||
					if ((by >> 4) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by >> 4]);
 | 
			
		||||
					px++;
 | 
			
		||||
					if (px < bmp_header->width) {
 | 
			
		||||
						if ((by & 15) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by & 15]);
 | 
			
		||||
					}
 | 
			
		||||
					px++;
 | 
			
		||||
				}
 | 
			
		||||
				if (data_idx & 1) data_idx++;
 | 
			
		||||
			} else {
 | 
			
		||||
				by = bitmap[data_idx++];
 | 
			
		||||
				if (by == 0) {
 | 
			
		||||
					py--;
 | 
			
		||||
					px = 0;
 | 
			
		||||
				} else if (by == 1) {
 | 
			
		||||
					break;
 | 
			
		||||
				} else if (by == 2) {
 | 
			
		||||
					// Delta
 | 
			
		||||
				} else {
 | 
			
		||||
					count = by >> 1;
 | 
			
		||||
					for (c = 0; c < count; c++) {
 | 
			
		||||
						by = bitmap[data_idx++];
 | 
			
		||||
						if ((by >> 4) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by >> 4]);
 | 
			
		||||
						px++;
 | 
			
		||||
						if (px < bmp_header->width) {
 | 
			
		||||
							if ((by & 15) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by & 15]);
 | 
			
		||||
						}
 | 
			
		||||
						px++;
 | 
			
		||||
					}
 | 
			
		||||
					if (data_idx & 1) data_idx++;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} while (1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Draw BMP from SD card.
 | 
			
		||||
	Currently supported formats:
 | 
			
		||||
		16bpp ARGB, RGB565
 | 
			
		||||
		24bpp RGB
 | 
			
		||||
		32bpp ARGB
 | 
			
		||||
*/
 | 
			
		||||
bool ILI9341::drawBMP2(const ui::Point p, const std::string file) {
 | 
			
		||||
	File bmpimage;
 | 
			
		||||
	size_t file_pos = 0;
 | 
			
		||||
	uint16_t pointer = 0;
 | 
			
		||||
	int16_t px = 0, py, width, height;
 | 
			
		||||
	bmp_header_t bmp_header;
 | 
			
		||||
	uint8_t type = 0;
 | 
			
		||||
	char buffer[257];
 | 
			
		||||
	ui::Color line_buffer[240];
 | 
			
		||||
 | 
			
		||||
	auto result = bmpimage.open(file);
 | 
			
		||||
	if(result.is_valid())
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	bmpimage.seek(file_pos);
 | 
			
		||||
	auto read_size = bmpimage.read(&bmp_header, sizeof(bmp_header));
 | 
			
		||||
	if (!((bmp_header.signature == 0x4D42) && // "BM" Signature
 | 
			
		||||
		(bmp_header.planes == 1) && // Seems always to be 1
 | 
			
		||||
		(bmp_header.compression == 0 || bmp_header.compression == 3 ))) {	// No compression
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch(bmp_header.bpp) {
 | 
			
		||||
		case 16:
 | 
			
		||||
			file_pos = 0x36;
 | 
			
		||||
			memset(buffer, 0, 16);
 | 
			
		||||
			bmpimage.read(buffer, 16);
 | 
			
		||||
			if(buffer[1] == 0x7C)
 | 
			
		||||
				type = 3; // A1R5G5B5
 | 
			
		||||
			else
 | 
			
		||||
				type = 0; // R5G6B5
 | 
			
		||||
			break;
 | 
			
		||||
		case 24:
 | 
			
		||||
			type = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 32:
 | 
			
		||||
		default:
 | 
			
		||||
			type = 2;
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	width = bmp_header.width;
 | 
			
		||||
	height = bmp_header.height;
 | 
			
		||||
 | 
			
		||||
	file_pos = bmp_header.image_data;
 | 
			
		||||
 | 
			
		||||
	py = height + 16;
 | 
			
		||||
 | 
			
		||||
	while(1) {
 | 
			
		||||
		while(px < width) {
 | 
			
		||||
			bmpimage.seek(file_pos);
 | 
			
		||||
			memset(buffer, 0, 257);
 | 
			
		||||
			read_size = bmpimage.read(buffer, 256);
 | 
			
		||||
			if (read_size.is_error())
 | 
			
		||||
				return false;	// Read error
 | 
			
		||||
 | 
			
		||||
			pointer = 0;
 | 
			
		||||
			while(pointer < 256) {
 | 
			
		||||
				if(pointer + 4 > 256)
 | 
			
		||||
					break;
 | 
			
		||||
				switch(type) {
 | 
			
		||||
					case 0:
 | 
			
		||||
					case 3:
 | 
			
		||||
						if(!type)
 | 
			
		||||
							line_buffer[px] = ui::Color((uint16_t)buffer[pointer] | ((uint16_t)buffer[pointer + 1] << 8));
 | 
			
		||||
						else
 | 
			
		||||
							line_buffer[px] = ui::Color(((uint16_t)buffer[pointer] & 0x1F) | ((uint16_t)buffer[pointer] & 0xE0) << 1 | ((uint16_t)buffer[pointer + 1] & 0x7F) << 9);
 | 
			
		||||
						pointer += 2;
 | 
			
		||||
						file_pos += 2;
 | 
			
		||||
						break;
 | 
			
		||||
					case 1:
 | 
			
		||||
					default:
 | 
			
		||||
						line_buffer[px] = ui::Color(buffer[pointer + 2], buffer[pointer + 1], buffer[pointer]);
 | 
			
		||||
						pointer += 3;
 | 
			
		||||
						file_pos += 3;
 | 
			
		||||
						break;
 | 
			
		||||
					case 2:
 | 
			
		||||
						line_buffer[px] = ui::Color(buffer[pointer + 2], buffer[pointer + 1], buffer[pointer]);
 | 
			
		||||
						pointer += 4;
 | 
			
		||||
						file_pos += 4;
 | 
			
		||||
						break;
 | 
			
		||||
				}
 | 
			
		||||
				px++;
 | 
			
		||||
				if(px >= width) {
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if(read_size.value() != 256)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		render_line({ p.x(), p.y() + py }, px, line_buffer);
 | 
			
		||||
		px = 0;
 | 
			
		||||
		py--;
 | 
			
		||||
 | 
			
		||||
		if(read_size.value() < 256 || py < 0)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::draw_line(const ui::Point start, const ui::Point end, const ui::Color color) {
 | 
			
		||||
	int x0 = start.x();
 | 
			
		||||
	int y0 = start.y();
 | 
			
		||||
	int x1 = end.x();
 | 
			
		||||
	int y1 = end.y();
 | 
			
		||||
	
 | 
			
		||||
	int dx = std::abs(x1-x0), sx = x0<x1 ? 1 : -1;
 | 
			
		||||
	int dy = std::abs(y1-y0), sy = y0<y1 ? 1 : -1; 
 | 
			
		||||
	int err = (dx>dy ? dx : -dy)/2, e2;
 | 
			
		||||
 
 | 
			
		||||
	for(;;){
 | 
			
		||||
		draw_pixel({static_cast<ui::Coord>(x0), static_cast<ui::Coord>(y0)}, color);
 | 
			
		||||
		if (x0==x1 && y0==y1) break;
 | 
			
		||||
		e2 = err;
 | 
			
		||||
		if (e2 >-dx) { err -= dy; x0 += sx; }
 | 
			
		||||
		if (e2 < dy) { err += dx; y0 += sy; }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::fill_circle(
 | 
			
		||||
	const ui::Point center,
 | 
			
		||||
	const ui::Dim radius,
 | 
			
		||||
	const ui::Color foreground,
 | 
			
		||||
	const ui::Color background
 | 
			
		||||
) {
 | 
			
		||||
	const uint32_t radius2 = radius * radius;
 | 
			
		||||
	for(int32_t y=-radius; y<radius; y++) {
 | 
			
		||||
		const int32_t y2 = y * y;
 | 
			
		||||
		for(int32_t x=-radius; x<radius; x++) {
 | 
			
		||||
			const int32_t x2 = x * x;
 | 
			
		||||
			const uint32_t d2 = x2 + y2;
 | 
			
		||||
			const bool inside = d2 < radius2;
 | 
			
		||||
			const auto color = inside ? foreground : background;
 | 
			
		||||
			draw_pixel({ x + center.x(), y + center.y() }, color);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::draw_pixel(
 | 
			
		||||
	const ui::Point p,
 | 
			
		||||
	const ui::Color color
 | 
			
		||||
) {
 | 
			
		||||
	if( screen_rect().contains(p) ) {
 | 
			
		||||
		lcd_start_ram_write(p, { 1, 1 });
 | 
			
		||||
		io.lcd_write_pixel(color);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::draw_pixels(
 | 
			
		||||
	const ui::Rect r,
 | 
			
		||||
	const ui::Color* const colors,
 | 
			
		||||
	const size_t count
 | 
			
		||||
) {
 | 
			
		||||
	/* TODO: Assert that rectangle width x height < count */
 | 
			
		||||
	lcd_start_ram_write(r);
 | 
			
		||||
	io.lcd_write_pixels(colors, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::read_pixels(
 | 
			
		||||
	const ui::Rect r,
 | 
			
		||||
	ui::ColorRGB888* const colors,
 | 
			
		||||
	const size_t count
 | 
			
		||||
) {
 | 
			
		||||
	/* TODO: Assert that rectangle width x height < count */
 | 
			
		||||
	lcd_start_ram_read(r);
 | 
			
		||||
	io.lcd_read_bytes(
 | 
			
		||||
		reinterpret_cast<uint8_t*>(colors),
 | 
			
		||||
		count * sizeof(ui::ColorRGB888)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::draw_bitmap(
 | 
			
		||||
	const ui::Point p,
 | 
			
		||||
	const ui::Size size,
 | 
			
		||||
	const uint8_t* const pixels,
 | 
			
		||||
	const ui::Color foreground,
 | 
			
		||||
	const ui::Color background
 | 
			
		||||
) {
 | 
			
		||||
	lcd_start_ram_write(p, size);
 | 
			
		||||
 | 
			
		||||
	const size_t count = size.width() * size.height();
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const auto pixel = pixels[i >> 3] & (1U << (i & 0x7));
 | 
			
		||||
		io.lcd_write_pixel(pixel ? foreground : background);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::draw_glyph(
 | 
			
		||||
	const ui::Point p,
 | 
			
		||||
	const ui::Glyph& glyph,
 | 
			
		||||
	const ui::Color foreground,
 | 
			
		||||
	const ui::Color background
 | 
			
		||||
) {
 | 
			
		||||
	draw_bitmap(p, glyph.size(), glyph.pixels(), foreground, background);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::scroll_set_area(
 | 
			
		||||
	const ui::Coord top_y,
 | 
			
		||||
	const ui::Coord bottom_y
 | 
			
		||||
) {
 | 
			
		||||
	scroll_state.top_area = top_y;
 | 
			
		||||
	scroll_state.bottom_area = height() - bottom_y;
 | 
			
		||||
	scroll_state.height = bottom_y - top_y;
 | 
			
		||||
	lcd_vertical_scrolling_definition(scroll_state.top_area, scroll_state.height, scroll_state.bottom_area);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ui::Coord ILI9341::scroll_set_position(
 | 
			
		||||
	const ui::Coord position
 | 
			
		||||
) {
 | 
			
		||||
	scroll_state.current_position = position % scroll_state.height;
 | 
			
		||||
	const uint_fast16_t address = scroll_state.top_area + scroll_state.current_position;
 | 
			
		||||
	lcd_vertical_scrolling_start_address(address);
 | 
			
		||||
	return address;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ui::Coord ILI9341::scroll(const int32_t delta) {
 | 
			
		||||
	return scroll_set_position(scroll_state.current_position + scroll_state.height - delta);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ui::Coord ILI9341::scroll_area_y(const ui::Coord y) const {
 | 
			
		||||
	const auto wrapped_y = (scroll_state.current_position + y) % scroll_state.height;
 | 
			
		||||
	return wrapped_y + scroll_state.top_area;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341::scroll_disable() {
 | 
			
		||||
	lcd_vertical_scrolling_definition(0, height(), 0);
 | 
			
		||||
	lcd_vertical_scrolling_start_address(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace lcd */
 | 
			
		||||
							
								
								
									
										124
									
								
								Software/portapack-mayhem/firmware/common/lcd_ili9341.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								Software/portapack-mayhem/firmware/common/lcd_ili9341.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LCD_ILI9341_H__
 | 
			
		||||
#define __LCD_ILI9341_H__
 | 
			
		||||
 | 
			
		||||
#include "ui.hpp"
 | 
			
		||||
#include "ui_text.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
namespace lcd {
 | 
			
		||||
 | 
			
		||||
class ILI9341 {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr ILI9341(
 | 
			
		||||
	) : scroll_state { 0, 0, height(), 0 }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ILI9341(const ILI9341&) = delete;
 | 
			
		||||
	ILI9341(ILI9341&&) = delete;
 | 
			
		||||
	void operator=(const ILI9341&) = delete;
 | 
			
		||||
 | 
			
		||||
	void init();
 | 
			
		||||
	void shutdown();
 | 
			
		||||
 | 
			
		||||
	void sleep();
 | 
			
		||||
	void wake();
 | 
			
		||||
 | 
			
		||||
	void fill_rectangle(ui::Rect r, const ui::Color c);
 | 
			
		||||
	void fill_rectangle_unrolled8(ui::Rect r, const ui::Color c);
 | 
			
		||||
	void draw_line(const ui::Point start, const ui::Point end, const ui::Color color);
 | 
			
		||||
	void fill_circle(
 | 
			
		||||
		const ui::Point center,
 | 
			
		||||
		const ui::Dim radius,
 | 
			
		||||
		const ui::Color foreground,
 | 
			
		||||
		const ui::Color background
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	void draw_pixel(const ui::Point p, const ui::Color color);
 | 
			
		||||
	void drawBMP(const ui::Point p, const uint8_t * bitmap, const bool transparency);
 | 
			
		||||
	bool drawBMP2(const ui::Point p, const std::string file);
 | 
			
		||||
	void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
 | 
			
		||||
	void render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer);
 | 
			
		||||
	
 | 
			
		||||
	template<size_t N>
 | 
			
		||||
	void draw_pixels(
 | 
			
		||||
		const ui::Rect r,
 | 
			
		||||
		const std::array<ui::Color, N>& colors
 | 
			
		||||
	) {
 | 
			
		||||
		draw_pixels(r, colors.data(), colors.size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<size_t N>
 | 
			
		||||
	void read_pixels(
 | 
			
		||||
		const ui::Rect r,
 | 
			
		||||
		std::array<ui::ColorRGB888, N>& colors
 | 
			
		||||
	) {
 | 
			
		||||
		read_pixels(r, colors.data(), colors.size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void draw_bitmap(
 | 
			
		||||
		const ui::Point p,
 | 
			
		||||
		const ui::Size size,
 | 
			
		||||
		const uint8_t* const data,
 | 
			
		||||
		const ui::Color foreground,
 | 
			
		||||
		const ui::Color background
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	void draw_glyph(
 | 
			
		||||
		const ui::Point p,
 | 
			
		||||
		const ui::Glyph& glyph,
 | 
			
		||||
		const ui::Color foreground,
 | 
			
		||||
		const ui::Color background
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	void scroll_set_area(const ui::Coord top_y, const ui::Coord bottom_y);
 | 
			
		||||
	ui::Coord scroll_set_position(const ui::Coord position);
 | 
			
		||||
	ui::Coord scroll(const int32_t delta);
 | 
			
		||||
	ui::Coord scroll_area_y(const ui::Coord y) const;
 | 
			
		||||
	void scroll_disable();
 | 
			
		||||
 | 
			
		||||
	constexpr ui::Dim width() const { return 240; }
 | 
			
		||||
	constexpr ui::Dim height() const { return 320; }
 | 
			
		||||
	constexpr ui::Rect screen_rect() const { return { 0, 0, width(), height() }; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	struct scroll_t {
 | 
			
		||||
		ui::Coord top_area;
 | 
			
		||||
		ui::Coord bottom_area;
 | 
			
		||||
		ui::Dim height;
 | 
			
		||||
		ui::Coord current_position;
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	scroll_t scroll_state;
 | 
			
		||||
 | 
			
		||||
	void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count);
 | 
			
		||||
	void read_pixels(const ui::Rect r, ui::ColorRGB888* const colors, const size_t count);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace lcd */
 | 
			
		||||
 | 
			
		||||
#endif/*__LCD_ILI9341_H__*/
 | 
			
		||||
							
								
								
									
										58
									
								
								Software/portapack-mayhem/firmware/common/led.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								Software/portapack-mayhem/firmware/common/led.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LED_H__
 | 
			
		||||
#define __LED_H__
 | 
			
		||||
 | 
			
		||||
#include "gpio.hpp"
 | 
			
		||||
 | 
			
		||||
struct LED {
 | 
			
		||||
	constexpr LED(const GPIO gpio) :
 | 
			
		||||
		_gpio { gpio } {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setup() const {
 | 
			
		||||
		_gpio.clear();
 | 
			
		||||
		_gpio.output();
 | 
			
		||||
		_gpio.configure();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void on() const {
 | 
			
		||||
		_gpio.set();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void off() const {
 | 
			
		||||
		_gpio.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void toggle() const {
 | 
			
		||||
		_gpio.toggle();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void write(const bool value) const {
 | 
			
		||||
		_gpio.write(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const GPIO _gpio;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__LED_H__*/
 | 
			
		||||
							
								
								
									
										106
									
								
								Software/portapack-mayhem/firmware/common/lfsr_random.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								Software/portapack-mayhem/firmware/common/lfsr_random.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lfsr_random.hpp"
 | 
			
		||||
 | 
			
		||||
static void lfsr_iterate_internal(lfsr_word_t& v)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	    Generated with lfsr-generator:
 | 
			
		||||
	    http://lfsr-generator.sourceforge.net
 | 
			
		||||
	    =============================================
 | 
			
		||||
		config          : fibonacci
 | 
			
		||||
		length          : 31
 | 
			
		||||
		taps            : (31, 18)
 | 
			
		||||
		shift-amounts   : (12, 12, 8)
 | 
			
		||||
		shift-direction : left
 | 
			
		||||
	*/
 | 
			
		||||
	enum {
 | 
			
		||||
		length         = 31,
 | 
			
		||||
		tap_0          = 31,
 | 
			
		||||
		tap_1          = 18,
 | 
			
		||||
		shift_amount_0 = 12,
 | 
			
		||||
		shift_amount_1 = 12,
 | 
			
		||||
		shift_amount_2 =  8
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const lfsr_word_t zero = 0;
 | 
			
		||||
	v = (
 | 
			
		||||
		(
 | 
			
		||||
			v << shift_amount_0
 | 
			
		||||
		) | (
 | 
			
		||||
			(
 | 
			
		||||
				(v >> (tap_0 - shift_amount_0)) ^
 | 
			
		||||
				(v >> (tap_1 - shift_amount_0))
 | 
			
		||||
			) & (
 | 
			
		||||
				~(~zero << shift_amount_0)
 | 
			
		||||
			)
 | 
			
		||||
		)
 | 
			
		||||
	);
 | 
			
		||||
	v = (
 | 
			
		||||
		(
 | 
			
		||||
			v << shift_amount_1
 | 
			
		||||
		) | (
 | 
			
		||||
			(
 | 
			
		||||
				(v >> (tap_0 - shift_amount_1)) ^
 | 
			
		||||
				(v >> (tap_1 - shift_amount_1))
 | 
			
		||||
			) & (
 | 
			
		||||
				~(~zero << shift_amount_1)
 | 
			
		||||
			)
 | 
			
		||||
		)
 | 
			
		||||
	);
 | 
			
		||||
	v = (
 | 
			
		||||
		(
 | 
			
		||||
			v << shift_amount_2
 | 
			
		||||
		) | (
 | 
			
		||||
			(
 | 
			
		||||
				(v >> (tap_0 - shift_amount_2)) ^
 | 
			
		||||
				(v >> (tap_1 - shift_amount_2))
 | 
			
		||||
			) & (
 | 
			
		||||
				~(~zero << shift_amount_2)
 | 
			
		||||
			)
 | 
			
		||||
		)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lfsr_word_t lfsr_iterate(lfsr_word_t v) {
 | 
			
		||||
	lfsr_iterate_internal(v);
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lfsr_fill(lfsr_word_t& v, lfsr_word_t* buffer, size_t word_count) {
 | 
			
		||||
	while( word_count != 0 ) {
 | 
			
		||||
		lfsr_iterate_internal(v);
 | 
			
		||||
		*(buffer++) = v;
 | 
			
		||||
		word_count--;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool lfsr_compare(lfsr_word_t& v, const lfsr_word_t* buffer, size_t word_count) {
 | 
			
		||||
	while( word_count != 0 ) {
 | 
			
		||||
		lfsr_iterate_internal(v);
 | 
			
		||||
		if( *(buffer++) != v ) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		word_count--;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								Software/portapack-mayhem/firmware/common/lfsr_random.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Software/portapack-mayhem/firmware/common/lfsr_random.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LFSR_RANDOM_HPP__
 | 
			
		||||
#define __LFSR_RANDOM_HPP__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
using lfsr_word_t = uint32_t;
 | 
			
		||||
 | 
			
		||||
lfsr_word_t lfsr_iterate(lfsr_word_t v);
 | 
			
		||||
void lfsr_fill(lfsr_word_t& v, lfsr_word_t* buffer, size_t word_count);
 | 
			
		||||
bool lfsr_compare(lfsr_word_t& v, const lfsr_word_t* buffer, size_t word_count);
 | 
			
		||||
 | 
			
		||||
#endif/*__LFSR_RANDOM_HPP__*/
 | 
			
		||||
							
								
								
									
										566
									
								
								Software/portapack-mayhem/firmware/common/lpc43xx_cpp.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										566
									
								
								Software/portapack-mayhem/firmware/common/lpc43xx_cpp.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,566 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.	If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LPC43XX_CPP_H__
 | 
			
		||||
#define __LPC43XX_CPP_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include <hal.h>
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace lpc43xx {
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
namespace m4 {
 | 
			
		||||
 | 
			
		||||
static inline bool flag_saturation() {
 | 
			
		||||
	return __get_APSR() & (1U << 27);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void clear_flag_saturation() {
 | 
			
		||||
	uint32_t flags = 1;
 | 
			
		||||
	__asm volatile ("MSR APSR_nzcvqg, %0" : : "r" (flags));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace m4 */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace creg {
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, CREG0) == 0x004, "CREG0 offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, M4MEMMAP) == 0x100, "M4MEMMAP offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, CREG5) == 0x118, "CREG5 offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, CHIPID) == 0x200, "CHIPID offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, M0SUBMEMMAP) == 0x308, "M0SUBMEMMAP offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, M0APPTXEVENT) == 0x400, "M0APPTXEVENT offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, USB0FLADJ) == 0x500, "USB0FLADJ offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_CREG_Type, USB1FLADJ) == 0x600, "USB1FLADJ offset wrong");
 | 
			
		||||
 | 
			
		||||
namespace m4txevent {
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M0)
 | 
			
		||||
inline void enable() {
 | 
			
		||||
	nvicEnableVector(M4CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4TXEVENT_IRQ_PRIORITY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void disable() {
 | 
			
		||||
	nvicDisableVector(M4CORE_IRQn);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
inline void assert_event() {
 | 
			
		||||
	__SEV();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline void clear() {
 | 
			
		||||
	LPC_CREG->M4TXEVENT = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace m4txevent */
 | 
			
		||||
 | 
			
		||||
namespace m0apptxevent {
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
inline void enable() {
 | 
			
		||||
	nvicEnableVector(M0CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M0APPTXEVENT_IRQ_PRIORITY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void disable() {
 | 
			
		||||
	nvicDisableVector(M0CORE_IRQn);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M0)
 | 
			
		||||
inline void assert_event() {
 | 
			
		||||
	__SEV();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline void clear() {
 | 
			
		||||
	LPC_CREG->M0APPTXEVENT = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace */
 | 
			
		||||
 | 
			
		||||
} /* namespace creg */
 | 
			
		||||
 | 
			
		||||
namespace cgu {
 | 
			
		||||
 | 
			
		||||
enum class CLK_SEL : uint8_t {
 | 
			
		||||
	RTC_32KHZ	= 0x00,
 | 
			
		||||
	IRC			= 0x01,
 | 
			
		||||
	ENET_RX_CLK = 0x02,
 | 
			
		||||
	ENET_TX_CLK = 0x03,
 | 
			
		||||
	GP_CLKIN	= 0x04,
 | 
			
		||||
	XTAL		= 0x06,
 | 
			
		||||
	PLL0USB		= 0x07,
 | 
			
		||||
	PLL0AUDIO	= 0x08,
 | 
			
		||||
	PLL1		= 0x09,
 | 
			
		||||
	IDIVA		= 0x0c,
 | 
			
		||||
	IDIVB		= 0x0d,
 | 
			
		||||
	IDIVC		= 0x0e,
 | 
			
		||||
	IDIVD		= 0x0f,
 | 
			
		||||
	IDIVE		= 0x10,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct IDIV_CTRL {
 | 
			
		||||
	uint32_t pd;
 | 
			
		||||
	uint32_t idiv;
 | 
			
		||||
	uint32_t autoblock;
 | 
			
		||||
	CLK_SEL clk_sel;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((pd & 1) << 0)
 | 
			
		||||
			| ((idiv & 255) << 2)
 | 
			
		||||
			| ((autoblock & 1) << 11)
 | 
			
		||||
			| ((toUType(clk_sel) & 0x1f) << 24)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace pll0audio {
 | 
			
		||||
 | 
			
		||||
struct CTRL {
 | 
			
		||||
	uint32_t pd;
 | 
			
		||||
	uint32_t bypass;
 | 
			
		||||
	uint32_t directi;
 | 
			
		||||
	uint32_t directo;
 | 
			
		||||
	uint32_t clken;
 | 
			
		||||
	uint32_t frm;
 | 
			
		||||
	uint32_t autoblock;
 | 
			
		||||
	uint32_t pllfract_req;
 | 
			
		||||
	uint32_t sel_ext;
 | 
			
		||||
	uint32_t mod_pd;
 | 
			
		||||
	CLK_SEL clk_sel;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((pd & 1) << 0)
 | 
			
		||||
			| ((bypass & 1) << 1)
 | 
			
		||||
			| ((directi & 1) << 2)
 | 
			
		||||
			| ((directo & 1) << 3)
 | 
			
		||||
			| ((clken & 1) << 4)
 | 
			
		||||
			| ((frm & 1) << 6)
 | 
			
		||||
			| ((autoblock & 1) << 11)
 | 
			
		||||
			| ((pllfract_req & 1) << 12)
 | 
			
		||||
			| ((sel_ext & 1) << 13)
 | 
			
		||||
			| ((mod_pd & 1) << 14)
 | 
			
		||||
			| ((toUType(clk_sel) & 0x1f) << 24)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MDIV {
 | 
			
		||||
	uint32_t mdec;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return ((mdec & 0x1ffff) << 0);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct NP_DIV {
 | 
			
		||||
	uint32_t pdec;
 | 
			
		||||
	uint32_t ndec;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((pdec & 0x7f) << 0)
 | 
			
		||||
			| ((ndec & 0x3ff) << 12)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FRAC {
 | 
			
		||||
	uint32_t pllfract_ctrl;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return ((pllfract_ctrl & 0x3fffff) << 0);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline void ctrl(const CTRL& value) {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_CTRL = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void mdiv(const MDIV& value) {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_MDIV = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void np_div(const NP_DIV& value) {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_NP_DIV = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void frac(const FRAC& value) {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_FRAC = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void power_up() {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void power_down() {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_CTRL |= (1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool is_locked() {
 | 
			
		||||
	return LPC_CGU->PLL0AUDIO_STAT & (1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void clock_enable() {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_CTRL |= (1U << 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void clock_disable() {
 | 
			
		||||
	LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace pll0audio */
 | 
			
		||||
 | 
			
		||||
namespace pll1 {
 | 
			
		||||
 | 
			
		||||
struct CTRL {
 | 
			
		||||
	uint32_t pd;
 | 
			
		||||
	uint32_t bypass;
 | 
			
		||||
	uint32_t fbsel;
 | 
			
		||||
	uint32_t direct;
 | 
			
		||||
	uint32_t psel;
 | 
			
		||||
	uint32_t autoblock;
 | 
			
		||||
	uint32_t nsel;
 | 
			
		||||
	uint32_t msel;
 | 
			
		||||
	CLK_SEL clk_sel;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((pd & 1) << 0)
 | 
			
		||||
			| ((bypass & 1) << 1)
 | 
			
		||||
			| ((fbsel & 1) << 6)
 | 
			
		||||
			| ((direct & 1) << 7)
 | 
			
		||||
			| ((psel & 3) << 8)
 | 
			
		||||
			| ((autoblock & 1) << 11)
 | 
			
		||||
			| ((nsel & 3) << 12)
 | 
			
		||||
			| ((msel & 0xff) << 16)
 | 
			
		||||
			| ((toUType(clk_sel) & 0x1f) << 24)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline void ctrl(const CTRL& value) {
 | 
			
		||||
	LPC_CGU->PLL1_CTRL = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void enable() {
 | 
			
		||||
	LPC_CGU->PLL1_CTRL &= ~(1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void disable() {
 | 
			
		||||
	LPC_CGU->PLL1_CTRL |= (1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void direct() {
 | 
			
		||||
	LPC_CGU->PLL1_CTRL |= (1U << 7);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool is_locked() {
 | 
			
		||||
	return LPC_CGU->PLL1_STAT & (1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace pll1 */
 | 
			
		||||
 | 
			
		||||
} /* namespace cgu */
 | 
			
		||||
 | 
			
		||||
namespace ccu1 {
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_CCU1_Type, CLK_ADCHS_STAT) == 0xb04, "CLK_ADCHS_STAT offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace ccu1 */
 | 
			
		||||
 | 
			
		||||
namespace rgu {
 | 
			
		||||
 | 
			
		||||
enum class Reset {
 | 
			
		||||
	CORE = 0,
 | 
			
		||||
	PERIPH = 1,
 | 
			
		||||
	MASTER = 2,
 | 
			
		||||
	WWDT = 4,
 | 
			
		||||
	CREG = 5,
 | 
			
		||||
	BUS = 8,
 | 
			
		||||
	SCU = 9,
 | 
			
		||||
	M0_SUB = 12,
 | 
			
		||||
	M4_RST = 13,
 | 
			
		||||
	LCD = 16,
 | 
			
		||||
	USB0 = 17,
 | 
			
		||||
	USB1 = 18,
 | 
			
		||||
	DMA = 19,
 | 
			
		||||
	SDIO = 20,
 | 
			
		||||
	EMC = 21,
 | 
			
		||||
	ETHERNET = 22,
 | 
			
		||||
	FLASHA = 25,
 | 
			
		||||
	EEPROM = 27,
 | 
			
		||||
	GPIO = 28,
 | 
			
		||||
	FLASHB = 29,
 | 
			
		||||
	TIMER0 = 32,
 | 
			
		||||
	TIMER1 = 33,
 | 
			
		||||
	TIMER2 = 34,
 | 
			
		||||
	TIMER3 = 35,
 | 
			
		||||
	RITIMER = 36,
 | 
			
		||||
	SCT = 37,
 | 
			
		||||
	MOTOCONPWM = 38,
 | 
			
		||||
	QEI = 39,
 | 
			
		||||
	ADC0 = 40,
 | 
			
		||||
	ADC1 = 41,
 | 
			
		||||
	DAC = 42,
 | 
			
		||||
	UART0 = 44,
 | 
			
		||||
	UART1 = 45,
 | 
			
		||||
	UART2 = 46,
 | 
			
		||||
	UART3 = 47,
 | 
			
		||||
	I2C0 = 48,
 | 
			
		||||
	I2C1 = 49,
 | 
			
		||||
	SSP0 = 50,
 | 
			
		||||
	SSP1 = 51,
 | 
			
		||||
	I2S = 52,
 | 
			
		||||
	SPIFI = 53,
 | 
			
		||||
	CAN1 = 54,
 | 
			
		||||
	CAN0 = 55,
 | 
			
		||||
	M0APP = 56,
 | 
			
		||||
	SGPIO = 57,
 | 
			
		||||
	SPI = 58,
 | 
			
		||||
	ADCHS = 60,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Status {
 | 
			
		||||
	NotActive = 0b00,
 | 
			
		||||
	ActivatedByRGUInput = 0b01,
 | 
			
		||||
	ActivatedBySoftware = 0b11,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline void reset(const Reset reset) {
 | 
			
		||||
	LPC_RGU->RESET_CTRL[toUType(reset) >> 5] = (1U << (toUType(reset) & 0x1f));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void reset_mask(const uint64_t mask) {
 | 
			
		||||
	LPC_RGU->RESET_CTRL[0] = mask & 0xffffffffU;
 | 
			
		||||
	LPC_RGU->RESET_CTRL[1] = mask >> 32;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Status status(const Reset reset) {
 | 
			
		||||
	return static_cast<Status>(
 | 
			
		||||
		(LPC_RGU->RESET_STATUS[toUType(reset) >> 4] >> ((toUType(reset) & 0xf) * 2)) & 3
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool active(const Reset reset) {
 | 
			
		||||
	return (LPC_RGU->RESET_ACTIVE_STATUS[toUType(reset) >> 5] >> (toUType(reset) & 0x1f)) & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint32_t external_status(const Reset reset) {
 | 
			
		||||
	return LPC_RGU->RESET_EXT_STAT[toUType(reset)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint64_t operator|(Reset r1, Reset r2) {
 | 
			
		||||
	return (1ULL << toUType(r1)) | (1ULL << toUType(r2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint64_t operator|(uint64_t m, Reset r) {
 | 
			
		||||
	return m | (1ULL << toUType(r));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_RGU_Type, RESET_CTRL[0]) == 0x100, "RESET_CTRL[0] offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_RGU_Type, RESET_STATUS[0]) == 0x110, "RESET_STATUS[0] offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_RGU_Type, RESET_ACTIVE_STATUS[0]) == 0x150, "RESET_ACTIVE_STATUS[0] offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_RGU_Type, RESET_EXT_STAT[1]) == 0x404, "RESET_EXT_STAT[1] offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_RGU_Type, RESET_EXT_STAT[60]) == 0x4f0, "RESET_EXT_STAT[60] offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace rgu */
 | 
			
		||||
 | 
			
		||||
namespace scu {
 | 
			
		||||
 | 
			
		||||
struct SFS {
 | 
			
		||||
	uint32_t mode;
 | 
			
		||||
	uint32_t epd;
 | 
			
		||||
	uint32_t epun;
 | 
			
		||||
	uint32_t ehs;
 | 
			
		||||
	uint32_t ezi;
 | 
			
		||||
	uint32_t zif;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((mode & 7) << 0)
 | 
			
		||||
			| ((epd	& 1) << 3)
 | 
			
		||||
			| ((epun & 1) << 4)
 | 
			
		||||
			| ((ehs	& 1) << 5)
 | 
			
		||||
			| ((ezi	& 1) << 6)
 | 
			
		||||
			| ((zif	& 1) << 7)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_SCU_Type, PINTSEL0) == 0xe00, "PINTSEL0 offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace scu */
 | 
			
		||||
 | 
			
		||||
namespace sgpio {
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, MASK_A) == 0x0200, "SGPIO MASK_A offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, GPIO_OUTREG) == 0x0214, "SGPIO GPIO_OUTREG offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, CTRL_DISABLE) == 0x0220, "SGPIO CTRL_DISABLE offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_0) == 0x0f00, "SGPIO CLR_EN_0 offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_1) == 0x0f20, "SGPIO CLR_EN_1 offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_2) == 0x0f40, "SGPIO CLR_EN_2 offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_3) == 0x0f60, "SGPIO CLR_EN_3 offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SGPIO_Type, SET_STATUS_3) == 0x0f74, "SGPIO SET_STATUS_3 offset wrong");
 | 
			
		||||
static_assert(sizeof(LPC_SGPIO_Type) == 0x0f78, "SGPIO type size wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace sgpio */
 | 
			
		||||
 | 
			
		||||
namespace gpdma {
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_GPDMA_Type, SYNC) == 0x034, "GPDMA SYNC offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_GPDMA_Type, CH[0]) == 0x100, "GPDMA CH[0] offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_GPDMA_Type, CH[7]) == 0x1e0, "GPDMA CH[7] offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace gpdma */
 | 
			
		||||
 | 
			
		||||
namespace sdmmc {
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_SDMMC_Type, RESP0) == 0x030, "SDMMC RESP0 offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SDMMC_Type, TCBCNT) == 0x05c, "SDMMC TCBCNT offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SDMMC_Type, RST_N) == 0x078, "SDMMC RST_N offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SDMMC_Type, BMOD) == 0x080, "SDMMC BMOD offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_SDMMC_Type, DATA) == 0x100, "SDMMC DATA offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace sdmmc */
 | 
			
		||||
 | 
			
		||||
namespace spifi {
 | 
			
		||||
 | 
			
		||||
struct CTRL {
 | 
			
		||||
	uint32_t timeout;
 | 
			
		||||
	uint32_t cshigh;
 | 
			
		||||
	uint32_t d_prftch_dis;
 | 
			
		||||
	uint32_t inten;
 | 
			
		||||
	uint32_t mode3;
 | 
			
		||||
	uint32_t prftch_dis;
 | 
			
		||||
	uint32_t dual;
 | 
			
		||||
	uint32_t rfclk;
 | 
			
		||||
	uint32_t fbclk;
 | 
			
		||||
	uint32_t dmaen;
 | 
			
		||||
 | 
			
		||||
	constexpr operator uint32_t() const {
 | 
			
		||||
		return
 | 
			
		||||
			  ((timeout & 0xffff) <<	0)
 | 
			
		||||
			| ((cshigh & 1) << 16)
 | 
			
		||||
			| ((d_prftch_dis & 1) << 21)
 | 
			
		||||
			| ((inten & 1) << 22)
 | 
			
		||||
			| ((mode3 & 1) << 23)
 | 
			
		||||
			| ((prftch_dis & 1) << 27)
 | 
			
		||||
			| ((dual & 1) << 28)
 | 
			
		||||
			| ((rfclk & 1) << 29)
 | 
			
		||||
			| ((fbclk & 1) << 30)
 | 
			
		||||
			| ((dmaen & 1) << 31)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_SPIFI_Type, STAT) == 0x01c, "SPIFI STAT offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace spifi */
 | 
			
		||||
 | 
			
		||||
namespace timer {
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_TIMER_Type, MR[0]) == 0x018, "TIMER MR[0] offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_TIMER_Type, CCR) == 0x028, "TIMER CCR offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_TIMER_Type, EMR) == 0x03c, "TIMER EMR offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_TIMER_Type, CTCR) == 0x070, "TIMER CTCR offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace timer */
 | 
			
		||||
 | 
			
		||||
namespace rtc {
 | 
			
		||||
 | 
			
		||||
namespace interrupt {
 | 
			
		||||
 | 
			
		||||
inline void clear_all() {
 | 
			
		||||
	LPC_RTC->ILR = (1U << 1) | (1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void enable_second_inc() {
 | 
			
		||||
	LPC_RTC->CIIR = (1U << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace */
 | 
			
		||||
 | 
			
		||||
#if HAL_USE_RTC
 | 
			
		||||
struct RTC : public RTCTime {
 | 
			
		||||
	constexpr RTC(
 | 
			
		||||
		uint32_t year,
 | 
			
		||||
		uint32_t month,
 | 
			
		||||
		uint32_t day,
 | 
			
		||||
		uint32_t hour,
 | 
			
		||||
		uint32_t minute,
 | 
			
		||||
		uint32_t second
 | 
			
		||||
	) : RTCTime {
 | 
			
		||||
			(year << 16) | (month << 8) | (day << 0),
 | 
			
		||||
			(hour << 16) | (minute << 8) | (second << 0)
 | 
			
		||||
		}
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr RTC(
 | 
			
		||||
	) : RTCTime { 0, 0 }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint16_t year() const {
 | 
			
		||||
		return (tv_date >> 16) & 0xfff;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t month() const {
 | 
			
		||||
		return (tv_date >> 8) & 0x00f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t day() const {
 | 
			
		||||
		return (tv_date >> 0) & 0x01f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t hour() const {
 | 
			
		||||
		return (tv_time >> 16) & 0x01f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t minute() const {
 | 
			
		||||
		return (tv_time >> 8) & 0x03f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t second() const {
 | 
			
		||||
		return (tv_time >> 0) & 0x03f;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static_assert(offsetof(LPC_RTC_Type, CCR) == 0x008, "RTC CCR offset wrong");
 | 
			
		||||
static_assert(offsetof(LPC_RTC_Type, ASEC) == 0x060, "RTC ASEC offset wrong");
 | 
			
		||||
 | 
			
		||||
} /* namespace rtc */
 | 
			
		||||
 | 
			
		||||
} /* namespace lpc43xx */
 | 
			
		||||
 | 
			
		||||
#endif/*__LPC43XX_CPP_H__*/
 | 
			
		||||
							
								
								
									
										96
									
								
								Software/portapack-mayhem/firmware/common/manchester.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								Software/portapack-mayhem/firmware/common/manchester.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "manchester.hpp"
 | 
			
		||||
 | 
			
		||||
#include "string_format.hpp"
 | 
			
		||||
 | 
			
		||||
size_t ManchesterBase::symbols_count() const {
 | 
			
		||||
	return packet.size() / 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DecodedSymbol ManchesterDecoder::operator[](const size_t index) const {
 | 
			
		||||
	const size_t encoded_index = index * 2;
 | 
			
		||||
	if( (encoded_index + 1) < packet.size() ) {
 | 
			
		||||
		const auto value = packet[encoded_index + sense];
 | 
			
		||||
		const auto error = packet[encoded_index + 0] == packet[encoded_index + 1];
 | 
			
		||||
		return { value, error };
 | 
			
		||||
	} else {
 | 
			
		||||
		return { 0, 1 };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DecodedSymbol BiphaseMDecoder::operator[](const size_t index) const {
 | 
			
		||||
	const size_t encoded_index = index * 2;
 | 
			
		||||
	if( (encoded_index + 1) < packet.size() ) {
 | 
			
		||||
		const auto value = packet[encoded_index + 0] != packet[encoded_index + 1];
 | 
			
		||||
		const uint_fast8_t error = encoded_index ? (packet[encoded_index - 1] == packet[encoded_index + 0]) : 0;
 | 
			
		||||
		return { value, error };
 | 
			
		||||
	} else {
 | 
			
		||||
		return { 0, 1 };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FormattedSymbols format_symbols(
 | 
			
		||||
	const ManchesterBase& decoder
 | 
			
		||||
) {
 | 
			
		||||
	const size_t payload_length_decoded = decoder.symbols_count();
 | 
			
		||||
	const size_t payload_length_hex_characters = (payload_length_decoded + 3) / 4;
 | 
			
		||||
	const size_t payload_length_symbols_rounded = payload_length_hex_characters * 4;
 | 
			
		||||
 | 
			
		||||
	std::string hex_data;
 | 
			
		||||
	std::string hex_error;
 | 
			
		||||
	hex_data.reserve(payload_length_hex_characters);
 | 
			
		||||
	hex_error.reserve(payload_length_hex_characters);
 | 
			
		||||
 | 
			
		||||
	uint_fast8_t data = 0;
 | 
			
		||||
	uint_fast8_t error = 0;
 | 
			
		||||
	for(size_t i=0; i<payload_length_symbols_rounded; i++) {
 | 
			
		||||
		const auto symbol = decoder[i];
 | 
			
		||||
 | 
			
		||||
		data <<= 1;
 | 
			
		||||
		data |= symbol.value;
 | 
			
		||||
 | 
			
		||||
		error <<= 1;
 | 
			
		||||
		error |= symbol.error;
 | 
			
		||||
 | 
			
		||||
		if( (i & 3) == 3 ) {
 | 
			
		||||
			hex_data += to_string_hex(data & 0xf, 1);
 | 
			
		||||
			hex_error += to_string_hex(error & 0xf, 1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return { hex_data, hex_error };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense) {
 | 
			
		||||
	uint8_t part = sense ? 0 : 0xFF;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t c = 0; c < length; c++) {
 | 
			
		||||
		if ((src[c >> 3] << (c & 7)) & 0x80) {
 | 
			
		||||
			*(dest++) = part;
 | 
			
		||||
			*(dest++) = ~part;
 | 
			
		||||
		} else {
 | 
			
		||||
			*(dest++) = ~part;
 | 
			
		||||
			*(dest++) = part;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								Software/portapack-mayhem/firmware/common/manchester.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								Software/portapack-mayhem/firmware/common/manchester.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MANCHESTER_H__
 | 
			
		||||
#define __MANCHESTER_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
 | 
			
		||||
struct DecodedSymbol {
 | 
			
		||||
	uint_fast8_t value;
 | 
			
		||||
	uint_fast8_t error;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ManchesterBase {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr ManchesterBase(
 | 
			
		||||
		const baseband::Packet& packet,
 | 
			
		||||
		const size_t sense = 0
 | 
			
		||||
	) : packet { packet },
 | 
			
		||||
		sense { sense }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	virtual DecodedSymbol operator[](const size_t index) const = 0;
 | 
			
		||||
 | 
			
		||||
	virtual size_t symbols_count() const;
 | 
			
		||||
	
 | 
			
		||||
	virtual ~ManchesterBase() { };
 | 
			
		||||
	
 | 
			
		||||
protected:
 | 
			
		||||
	const baseband::Packet& packet;
 | 
			
		||||
	const size_t sense;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ManchesterDecoder : public ManchesterBase {
 | 
			
		||||
public:
 | 
			
		||||
	using ManchesterBase::ManchesterBase;
 | 
			
		||||
	DecodedSymbol operator[](const size_t index) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BiphaseMDecoder : public ManchesterBase {
 | 
			
		||||
public:
 | 
			
		||||
	using ManchesterBase::ManchesterBase;
 | 
			
		||||
	DecodedSymbol operator[](const size_t index) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
T operator|(const T& l, const DecodedSymbol& r) {
 | 
			
		||||
	return l | r.value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct FormattedSymbols {
 | 
			
		||||
	const std::string data;
 | 
			
		||||
	const std::string errors;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FormattedSymbols format_symbols(
 | 
			
		||||
	const ManchesterBase& decoder
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense = 0);
 | 
			
		||||
 | 
			
		||||
#endif/*__MANCHESTER_H__*/
 | 
			
		||||
							
								
								
									
										88
									
								
								Software/portapack-mayhem/firmware/common/memory_map.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								Software/portapack-mayhem/firmware/common/memory_map.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MEMORY_MAP_H__
 | 
			
		||||
#define __MEMORY_MAP_H__
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace portapack {
 | 
			
		||||
namespace memory {
 | 
			
		||||
 | 
			
		||||
struct region_t {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr region_t(
 | 
			
		||||
		const uint32_t base,
 | 
			
		||||
		const size_t size
 | 
			
		||||
	) : base_ { base },
 | 
			
		||||
		size_ { size } {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr uint32_t base() const {
 | 
			
		||||
		return base_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr uint32_t end() const {
 | 
			
		||||
		return base_ + size_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr size_t size() const {
 | 
			
		||||
		return size_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const uint32_t base_;
 | 
			
		||||
	const size_t size_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace map {
 | 
			
		||||
 | 
			
		||||
constexpr region_t local_sram_0		{ 0x10000000,  96_KiB };
 | 
			
		||||
constexpr region_t local_sram_1		{ 0x10080000,  40_KiB };
 | 
			
		||||
 | 
			
		||||
constexpr region_t ahb_ram_0		{ 0x20000000,  32_KiB };
 | 
			
		||||
constexpr region_t ahb_ram_1		{ 0x20008000,  16_KiB };
 | 
			
		||||
constexpr region_t ahb_ram_2		{ 0x2000c000,  16_KiB };
 | 
			
		||||
 | 
			
		||||
constexpr region_t backup_ram		{ LPC_BACKUP_REG_BASE,        256   };
 | 
			
		||||
 | 
			
		||||
constexpr region_t spifi_uncached	{ LPC_SPIFI_DATA_BASE,        1_MiB };
 | 
			
		||||
constexpr region_t spifi_cached		{ LPC_SPIFI_DATA_CACHED_BASE, spifi_uncached.size() };
 | 
			
		||||
 | 
			
		||||
/////////////////////////////////
 | 
			
		||||
 | 
			
		||||
constexpr region_t m4_code			{ local_sram_1.base(), 32_KiB };
 | 
			
		||||
constexpr region_t shared_memory	{ m4_code.end(),        8_KiB };
 | 
			
		||||
 | 
			
		||||
constexpr region_t m4_code_hackrf	= local_sram_0;
 | 
			
		||||
 | 
			
		||||
} /* namespace map */
 | 
			
		||||
} /* namespace memory */
 | 
			
		||||
} /* namespace portapack */
 | 
			
		||||
 | 
			
		||||
#endif/*__MEMORY_MAP_H__*/
 | 
			
		||||
							
								
								
									
										1140
									
								
								Software/portapack-mayhem/firmware/common/message.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1140
									
								
								Software/portapack-mayhem/firmware/common/message.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										37
									
								
								Software/portapack-mayhem/firmware/common/message_queue.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Software/portapack-mayhem/firmware/common/message_queue.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "message_queue.hpp"
 | 
			
		||||
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M0)
 | 
			
		||||
void MessageQueue::signal() {
 | 
			
		||||
	creg::m0apptxevent::assert_event();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(LPC43XX_M4)
 | 
			
		||||
void MessageQueue::signal() {
 | 
			
		||||
	creg::m4txevent::assert_event();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										118
									
								
								Software/portapack-mayhem/firmware/common/message_queue.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								Software/portapack-mayhem/firmware/common/message_queue.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MESSAGE_QUEUE_H__
 | 
			
		||||
#define __MESSAGE_QUEUE_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
#include "fifo.hpp"
 | 
			
		||||
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
 | 
			
		||||
class MessageQueue {
 | 
			
		||||
public:
 | 
			
		||||
	MessageQueue() = delete;
 | 
			
		||||
	MessageQueue(const MessageQueue&) = delete;
 | 
			
		||||
	MessageQueue(MessageQueue&&) = delete;
 | 
			
		||||
	
 | 
			
		||||
	MessageQueue(
 | 
			
		||||
		uint8_t* const data,
 | 
			
		||||
		size_t k
 | 
			
		||||
	) : fifo { data, k }
 | 
			
		||||
	{
 | 
			
		||||
		chMtxInit(&mutex_write);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	bool push(const T& message) {
 | 
			
		||||
		static_assert(sizeof(T) <= Message::MAX_SIZE, "Message::MAX_SIZE too small for message type");
 | 
			
		||||
		static_assert(std::is_base_of<Message, T>::value, "type is not based on Message");
 | 
			
		||||
 | 
			
		||||
		return push(&message, sizeof(message));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	bool push_and_wait(const T& message) {
 | 
			
		||||
		const bool result = push(message);
 | 
			
		||||
		if( result ) {
 | 
			
		||||
			// TODO: More graceful method of waiting for empty? Maybe sleep for a bit?
 | 
			
		||||
			while( !is_empty() );
 | 
			
		||||
		}
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename HandlerFn>
 | 
			
		||||
	void handle(HandlerFn handler) {
 | 
			
		||||
		std::array<uint8_t, Message::MAX_SIZE> message_buffer;
 | 
			
		||||
		while(Message* const message = peek(message_buffer)) {
 | 
			
		||||
			handler(message);
 | 
			
		||||
			skip();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_empty() const {
 | 
			
		||||
		return fifo.is_empty();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void reset() {
 | 
			
		||||
		fifo.reset();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	FIFO<uint8_t> fifo;
 | 
			
		||||
	Mutex mutex_write { };
 | 
			
		||||
 | 
			
		||||
	Message* peek(std::array<uint8_t, Message::MAX_SIZE>& buf) {
 | 
			
		||||
		Message* const p = reinterpret_cast<Message*>(buf.data());
 | 
			
		||||
		return fifo.peek_r(buf.data(), buf.size()) ? p : nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool skip() {
 | 
			
		||||
		return fifo.skip();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Message* pop(std::array<uint8_t, Message::MAX_SIZE>& buf) {
 | 
			
		||||
		Message* const p = reinterpret_cast<Message*>(buf.data());
 | 
			
		||||
		return fifo.out_r(buf.data(), buf.size()) ? p : nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t len() const {
 | 
			
		||||
		return fifo.len();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool push(const void* const buf, const size_t len) {
 | 
			
		||||
		chMtxLock(&mutex_write);
 | 
			
		||||
		const auto result = fifo.in_r(buf, len);
 | 
			
		||||
		chMtxUnlock();
 | 
			
		||||
 | 
			
		||||
		const bool success = (result == len);
 | 
			
		||||
		if( success ) {
 | 
			
		||||
			signal();
 | 
			
		||||
		}
 | 
			
		||||
		return success;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void signal();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__MESSAGE_QUEUE_H__*/
 | 
			
		||||
							
								
								
									
										2
									
								
								Software/portapack-mayhem/firmware/common/modules.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								Software/portapack-mayhem/firmware/common/modules.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
const char md5_baseband[16] = {0xb8,0x9e,0x9b,0x08,0x44,0x34,0x04,0x20,0x0b,0xbc,0x60,0x7e,0x67,0x88,0x53,0xf7,};
 | 
			
		||||
const char md5_baseband_tx[16] = {0xd5,0xaf,0x76,0xd5,0xa3,0x32,0x5d,0x9a,0x9d,0x83,0x46,0x37,0x02,0x2d,0xd0,0x57,};
 | 
			
		||||
							
								
								
									
										91
									
								
								Software/portapack-mayhem/firmware/common/morse.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								Software/portapack-mayhem/firmware/common/morse.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "morse.hpp"
 | 
			
		||||
 | 
			
		||||
#include "baseband_api.hpp"
 | 
			
		||||
#include "portapack.hpp"
 | 
			
		||||
using namespace portapack;
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace morse {
 | 
			
		||||
 | 
			
		||||
// Returns 0 if message is too long
 | 
			
		||||
size_t morse_encode(std::string& message, const uint32_t time_unit_ms,
 | 
			
		||||
	const uint32_t tone, uint32_t * const time_units) {
 | 
			
		||||
	
 | 
			
		||||
	size_t i, c;
 | 
			
		||||
	uint16_t code, code_size;
 | 
			
		||||
	uint8_t morse_message[256];
 | 
			
		||||
	uint32_t delta;
 | 
			
		||||
	
 | 
			
		||||
	*time_units = 0;
 | 
			
		||||
	
 | 
			
		||||
	i = 0;
 | 
			
		||||
	for (char& ch : message) {
 | 
			
		||||
		if (i > 256) return 0;						// Message too long
 | 
			
		||||
		
 | 
			
		||||
		if ((ch >= 'a') && (ch <= 'z'))				// Make uppercase
 | 
			
		||||
			ch -= 32;
 | 
			
		||||
		
 | 
			
		||||
		if ((ch >= '!') && (ch <= '_')) {
 | 
			
		||||
			code = morse_ITU[ch - '!'];
 | 
			
		||||
		} else {								
 | 
			
		||||
			code = 0;								// Default to space char
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (!code) {
 | 
			
		||||
			if (i)
 | 
			
		||||
				morse_message[i - 1] = 4;			// Word space
 | 
			
		||||
		} else {
 | 
			
		||||
			code_size = code & 7;
 | 
			
		||||
			
 | 
			
		||||
			for (c = 0; c < code_size; c++) {
 | 
			
		||||
				morse_message[i++] = ((code << c) & 0x8000) ? 1 : 0;	// Dot/dash
 | 
			
		||||
				morse_message[i++] = 2;				// Symbol space
 | 
			
		||||
			}
 | 
			
		||||
			morse_message[i - 1] = 3;				// Letter space
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Count time units
 | 
			
		||||
	for (c = 0; c < i; c++) {
 | 
			
		||||
		*time_units += morse_symbols[morse_message[c]];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	memcpy(shared_memory.bb_data.tones_data.message, morse_message, i);
 | 
			
		||||
	
 | 
			
		||||
	// Setup tone "symbols"
 | 
			
		||||
	for (c = 0; c < 5; c++) {
 | 
			
		||||
		if (c < 2)
 | 
			
		||||
			delta = TONES_F2D(tone, TONES_SAMPLERATE);	// Dot and dash
 | 
			
		||||
		else
 | 
			
		||||
			delta = 0;					// Pause
 | 
			
		||||
		
 | 
			
		||||
		baseband::set_tone(c, delta, (TONES_SAMPLERATE * morse_symbols[c] * time_unit_ms) / 1000);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace morse */
 | 
			
		||||
							
								
								
									
										148
									
								
								Software/portapack-mayhem/firmware/common/morse.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								Software/portapack-mayhem/firmware/common/morse.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MORSE_H__
 | 
			
		||||
#define __MORSE_H__
 | 
			
		||||
 | 
			
		||||
#include "tonesets.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#define MORSE_DOT 1
 | 
			
		||||
#define MORSE_DASH 3
 | 
			
		||||
#define MORSE_SYMBOL_SPACE 1
 | 
			
		||||
#define MORSE_LETTER_SPACE 3
 | 
			
		||||
#define MORSE_WORD_SPACE 7
 | 
			
		||||
 | 
			
		||||
namespace morse {
 | 
			
		||||
	
 | 
			
		||||
const uint32_t morse_symbols[5] = {
 | 
			
		||||
	MORSE_DOT,
 | 
			
		||||
	MORSE_DASH,
 | 
			
		||||
	MORSE_SYMBOL_SPACE,
 | 
			
		||||
	MORSE_LETTER_SPACE,
 | 
			
		||||
	MORSE_WORD_SPACE
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
size_t morse_encode(std::string& message, const uint32_t time_unit_ms,
 | 
			
		||||
	const uint32_t tone, uint32_t * const time_units);
 | 
			
		||||
 | 
			
		||||
constexpr char foxhunt_codes[11][4] = {
 | 
			
		||||
	{ "MOE" },	// -----.
 | 
			
		||||
	{ "MOI" },	// -----..
 | 
			
		||||
	{ "MOS" },	// -----...
 | 
			
		||||
	{ "MOH" },	// -----....
 | 
			
		||||
	{ "MO5" },	// -----.....
 | 
			
		||||
	{ "MON" },	// ------.
 | 
			
		||||
	{ "MOD" },	// ------..
 | 
			
		||||
	{ "MOB" },	// ------...
 | 
			
		||||
	{ "MO6" },	// ------....
 | 
			
		||||
	{ "MO" },	// -----
 | 
			
		||||
	{ "S" }		// ...
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 0=dot 1=dash
 | 
			
		||||
constexpr uint16_t morse_ITU[63] = {
 | 
			
		||||
						//    Code    Size
 | 
			
		||||
	0b1010110000000110,	// !: 101011- 110
 | 
			
		||||
	0b0100100000000110,	// ": 010010- 110
 | 
			
		||||
	0,					// #
 | 
			
		||||
	0b0001001000000111,	// $: 0001001 111
 | 
			
		||||
	0,					// %
 | 
			
		||||
	0b0100000000000101,	// &: 01000-- 101
 | 
			
		||||
	0b0111100000000110,	// ': 011110- 110
 | 
			
		||||
	0b1011000000000101,	// (: 10110-- 101
 | 
			
		||||
	0b1011010000000110,	// ): 101101- 110
 | 
			
		||||
	0,					// *
 | 
			
		||||
	0b0101000000000101,	// +: 01010-- 101
 | 
			
		||||
	0b1100110000000110,	// ,: 110011- 110
 | 
			
		||||
	0b1000010000000110,	// -: 100001- 110
 | 
			
		||||
	0b0101010000000110,	// .: 010101- 110
 | 
			
		||||
	0b1001000000000101,	// /: 10010-- 101
 | 
			
		||||
	0b1111100000000101,	// 0: 11111-- 101
 | 
			
		||||
	0b0111100000000101,	// 1: 01111-- 101
 | 
			
		||||
	0b0011100000000101,	// 2: 00111-- 101
 | 
			
		||||
	0b0001100000000101,	// 3: 00011-- 101
 | 
			
		||||
	0b0000100000000101,	// 4: 00001-- 101
 | 
			
		||||
	0b0000000000000101,	// 5: 00000-- 101
 | 
			
		||||
	0b1000000000000101,	// 6: 10000-- 101
 | 
			
		||||
	0b1100000000000101,	// 7: 11000-- 101
 | 
			
		||||
	0b1110000000000101,	// 8: 11100-- 101
 | 
			
		||||
	0b1111000000000101,	// 9: 11110-- 101
 | 
			
		||||
	0b1110000000000110,	// :: 111000- 110
 | 
			
		||||
	0b1010100000000110,	// ;: 101010- 110
 | 
			
		||||
	0,					// <
 | 
			
		||||
	0b1000100000000101,	// =: 10001-- 101
 | 
			
		||||
	0,					// >
 | 
			
		||||
	0b0011000000000110,	// ?: 001100- 110
 | 
			
		||||
	0b0110100000000110,	// @: 011010- 110
 | 
			
		||||
	0b0100000000000010,	// A: 01----- 010
 | 
			
		||||
	0b1000000000000100,	// B: 1000--- 100
 | 
			
		||||
	0b1010000000000100,	// C: 1010--- 100
 | 
			
		||||
	0b1000000000000011,	// D: 100---- 011
 | 
			
		||||
	0b0000000000000001,	// E: 0------ 001
 | 
			
		||||
	0b0010000000000100,	// F: 0010--- 100
 | 
			
		||||
	0b1100000000000011,	// G: 110---- 011
 | 
			
		||||
	0b0000000000000100,	// H: 0000--- 100
 | 
			
		||||
	0b0000000000000010,	// I: 00----- 010
 | 
			
		||||
	0b0111000000000100,	// J: 0111--- 100
 | 
			
		||||
	0b1010000000000011,	// K: 101---- 011
 | 
			
		||||
	0b0100000000000100,	// L: 0100--- 100
 | 
			
		||||
	0b1100000000000010,	// M: 11----- 010
 | 
			
		||||
	0b1000000000000010,	// N: 10----- 010
 | 
			
		||||
	0b1110000000000011,	// O: 111---- 011
 | 
			
		||||
	0b0110000000000100,	// P: 0110--- 100 .#-###-###.# ##.#-### ##.#-###.# ##.#.# ##.#.#.# = 48 units
 | 
			
		||||
	0b1101000000000100,	// Q: 1101--- 100
 | 
			
		||||
	0b0100000000000011,	// R: 010---- 011
 | 
			
		||||
	0b0000000000000011,	// S: 000---- 011
 | 
			
		||||
	0b1000000000000001,	// T: 1------ 001
 | 
			
		||||
	0b0010000000000011,	// U: 001---- 011
 | 
			
		||||
	0b0001000000000100,	// V: 0001--- 100
 | 
			
		||||
	0b0110000000000011,	// W: 011---- 011
 | 
			
		||||
	0b1001000000000100,	// X: 1001--- 100
 | 
			
		||||
	0b1011000000000100,	// Y: 1011--- 100
 | 
			
		||||
	0b1100000000000100,	// Z: 1100--- 100
 | 
			
		||||
	0,					// [
 | 
			
		||||
	0,					// Back-slash
 | 
			
		||||
	0,					// ]
 | 
			
		||||
	0,					// ^
 | 
			
		||||
	0b0011010000000110	// _: 001101- 110
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr uint16_t prosigns[12] = {
 | 
			
		||||
						//    	  Code		Size
 | 
			
		||||
	0b0001110000001001,	// <SOS>: 000111000	1001
 | 
			
		||||
	0b0101000000000100,	// <AA>:  0101----- 0100
 | 
			
		||||
	0b0101000000000101,	// <AR>:  01010---- 0101
 | 
			
		||||
	0b0100000000000101,	// <AS>:  01000---- 0101
 | 
			
		||||
	0b1000100000000101,	// <BT>:  10001---- 0101
 | 
			
		||||
	0b1010100000000101,	// <CT>:  10101---- 0101
 | 
			
		||||
	0b0000000000001000,	// <HH>:  00000000- 1000
 | 
			
		||||
	0b1010000000000011,	// <K>:   101------ 0011
 | 
			
		||||
	0b1011000000000101,	// <KN>:  10110---- 0101
 | 
			
		||||
	0b1001110000000110,	// <NJ>:  100111--- 0110
 | 
			
		||||
	0b0001010000000110,	// <SK>:  000101--- 0110
 | 
			
		||||
	0b0001100000000101,	// <SN>:  00010---- 0101
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace morse */
 | 
			
		||||
 | 
			
		||||
#endif/*__MORSE_H__*/
 | 
			
		||||
							
								
								
									
										341
									
								
								Software/portapack-mayhem/firmware/common/msgpack.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								Software/portapack-mayhem/firmware/common/msgpack.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,341 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * 
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "msgpack.hpp"
 | 
			
		||||
 | 
			
		||||
bool MsgPack::get_bool(const void * buffer, const bool inc, bool * value) {
 | 
			
		||||
	uint8_t v;
 | 
			
		||||
	
 | 
			
		||||
	if (seek_ptr >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	
 | 
			
		||||
	v = ((uint8_t*)buffer)[seek_ptr];
 | 
			
		||||
	if (v == MSGPACK_FALSE)
 | 
			
		||||
		*value = false;
 | 
			
		||||
	else if (v == MSGPACK_TRUE)
 | 
			
		||||
		*value = true;
 | 
			
		||||
	else
 | 
			
		||||
		return false;		// Not a bool
 | 
			
		||||
	
 | 
			
		||||
	if (inc) seek_ptr++;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::get_raw_byte(const void * buffer, const bool inc, uint8_t * byte) {
 | 
			
		||||
	if (seek_ptr >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	*byte = ((uint8_t*)buffer)[seek_ptr];
 | 
			
		||||
	if (inc) seek_ptr++;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::get_raw_word(const void * buffer, const bool inc, uint16_t * word) {
 | 
			
		||||
	if ((seek_ptr + 1) >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	*word = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
 | 
			
		||||
	if (inc) seek_ptr += 2;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::get_u8(const void * buffer, const bool inc, uint8_t * value) {
 | 
			
		||||
	uint8_t v;
 | 
			
		||||
	
 | 
			
		||||
	if (seek_ptr >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	
 | 
			
		||||
	v = ((uint8_t*)buffer)[seek_ptr];
 | 
			
		||||
 | 
			
		||||
	if (!(v & 0x80))
 | 
			
		||||
		*value = ((uint8_t*)buffer)[seek_ptr];	// Fixnum
 | 
			
		||||
	else if (v == MSGPACK_TYPE_U8)
 | 
			
		||||
		*value = ((uint8_t*)buffer)[seek_ptr + 1];	// u8
 | 
			
		||||
	else
 | 
			
		||||
		return false;		// Value isn't a u8 or fixnum
 | 
			
		||||
	
 | 
			
		||||
	if (inc) seek_ptr++;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: Typecheck function
 | 
			
		||||
 | 
			
		||||
bool MsgPack::get_u16(const void * buffer, const bool inc, uint16_t * value) {
 | 
			
		||||
	uint8_t byte;
 | 
			
		||||
	
 | 
			
		||||
	if ((seek_ptr + 1) >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_U16)) return false;		// Value isn't a u16
 | 
			
		||||
	*value = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
 | 
			
		||||
	if (inc) seek_ptr += 2;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::get_s32(const void * buffer, const bool inc, int32_t * value) {
 | 
			
		||||
	uint8_t byte;
 | 
			
		||||
	
 | 
			
		||||
	if ((seek_ptr + 3) >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S32)) return false;		// Value isn't a s32
 | 
			
		||||
	*value = (((uint8_t*)buffer)[seek_ptr] << 24) | (((uint8_t*)buffer)[seek_ptr + 1] << 16) |
 | 
			
		||||
				(((uint8_t*)buffer)[seek_ptr + 2] << 8) | ((uint8_t*)buffer)[seek_ptr + 3];
 | 
			
		||||
	if (inc) seek_ptr += 4;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::get_string(const void * buffer, const bool inc, std::string& value) {
 | 
			
		||||
	size_t length;
 | 
			
		||||
	uint8_t byte;
 | 
			
		||||
	
 | 
			
		||||
	// Todo: Set max length !
 | 
			
		||||
	if ((seek_ptr + 3) >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_STR8)
 | 
			
		||||
			&& (byte != MSGPACK_TYPE_STR16)) return false;		// Value isn't a str8 or str16
 | 
			
		||||
 | 
			
		||||
	if (byte == MSGPACK_TYPE_STR8) {
 | 
			
		||||
		if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false;		// Couldn't get str8 length
 | 
			
		||||
	} else if (byte == MSGPACK_TYPE_STR16) {
 | 
			
		||||
		if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false;		// Couldn't get str16 length
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	memcpy(&value[0], ((uint8_t*)buffer), length); //std::string(
 | 
			
		||||
 | 
			
		||||
	if (inc) seek_ptr += length;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::init_search(const void * buffer, const size_t size) {
 | 
			
		||||
	uint8_t byte;
 | 
			
		||||
	uint16_t map_size;
 | 
			
		||||
	
 | 
			
		||||
	if (!size) return false;
 | 
			
		||||
	buffer_size = size;
 | 
			
		||||
	seek_ptr = 0;
 | 
			
		||||
	if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_MAP16)) return false;		// First record isn't a map16
 | 
			
		||||
	if (!get_raw_word(buffer, true, &map_size)) return false;		// Couldn't get map16 size
 | 
			
		||||
	if (!map_size) return false;
 | 
			
		||||
	
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::skip(const void * buffer) {
 | 
			
		||||
	uint8_t byte, c;
 | 
			
		||||
	size_t length;
 | 
			
		||||
	
 | 
			
		||||
	if (!get_raw_byte(buffer, true, &byte)) return false;		// Couldn't get type
 | 
			
		||||
	
 | 
			
		||||
	if (!(byte & 0x80)) return true;			// Positive fixnum, already skipped by get_raw_byte
 | 
			
		||||
	if ((byte & 0xE0) == 0xE0) return true;		// Negative fixnum, already skipped by get_raw_byte
 | 
			
		||||
	if ((byte & 0xE0) == 0xA0) {				// Fixstr
 | 
			
		||||
		seek_ptr += (byte & 0x1F);
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	if ((byte & 0xF0) == 0x80) {				// Fixmap
 | 
			
		||||
		length = (byte & 0x0F) * 2;
 | 
			
		||||
		for (c = 0; c < length; c++)
 | 
			
		||||
			skip(buffer);
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	if ((byte & 0xF0) == 0x90) {				// Fixarray
 | 
			
		||||
		length = byte & 0x0F;
 | 
			
		||||
		for (c = 0; c < length; c++)
 | 
			
		||||
			skip(buffer);
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	switch (byte) {
 | 
			
		||||
		case MSGPACK_NIL:
 | 
			
		||||
		case MSGPACK_FALSE:
 | 
			
		||||
		case MSGPACK_TRUE:		// Already skipped by get_raw_byte
 | 
			
		||||
			break;
 | 
			
		||||
		case MSGPACK_TYPE_U8:
 | 
			
		||||
		case MSGPACK_TYPE_S8:
 | 
			
		||||
			seek_ptr++;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSGPACK_TYPE_U16:
 | 
			
		||||
		case MSGPACK_TYPE_S16:
 | 
			
		||||
			seek_ptr += 2;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSGPACK_TYPE_U32:
 | 
			
		||||
		case MSGPACK_TYPE_S32:
 | 
			
		||||
			seek_ptr += 4;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSGPACK_TYPE_U64:
 | 
			
		||||
		case MSGPACK_TYPE_S64:
 | 
			
		||||
			seek_ptr += 8;
 | 
			
		||||
			break;
 | 
			
		||||
			
 | 
			
		||||
		case MSGPACK_TYPE_STR8:
 | 
			
		||||
			if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false;		// Couldn't get str8 length
 | 
			
		||||
			seek_ptr += length;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSGPACK_TYPE_STR16:
 | 
			
		||||
			if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false;		// Couldn't get str16 length
 | 
			
		||||
			seek_ptr += length;
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		case MSGPACK_TYPE_ARR16:
 | 
			
		||||
			if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false;		// Couldn't get arr16 length
 | 
			
		||||
			for (c = 0; c < length; c++)
 | 
			
		||||
				skip(buffer);
 | 
			
		||||
			break;
 | 
			
		||||
			
 | 
			
		||||
		case MSGPACK_TYPE_MAP16:
 | 
			
		||||
			if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false;		// Couldn't get map16 length
 | 
			
		||||
			for (c = 0; c < (length * 2); c++)
 | 
			
		||||
				skip(buffer);
 | 
			
		||||
			break;
 | 
			
		||||
			
 | 
			
		||||
		default:
 | 
			
		||||
			return false;	// Type unsupported
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::search_key(const void * buffer, const MsgPack::RecID record_id) {
 | 
			
		||||
	uint8_t byte;
 | 
			
		||||
	uint16_t key;
 | 
			
		||||
	
 | 
			
		||||
	while (get_raw_byte(buffer, false, &byte)) {
 | 
			
		||||
		if (!get_u16(buffer, true, &key)) return false;	// Couldn't get key
 | 
			
		||||
		if (key == record_id) return true;				// Found record
 | 
			
		||||
		if (!skip(buffer)) return false;				// Can't skip to next key
 | 
			
		||||
	};
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, bool * value) {
 | 
			
		||||
	init_search(buffer, size);
 | 
			
		||||
	if (!search_key(buffer, record_id)) return false;	// Record not found
 | 
			
		||||
	if (!get_bool(buffer, false, value)) return false;	// Value isn't a bool
 | 
			
		||||
	
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, uint8_t * value) {
 | 
			
		||||
	if (!init_search(buffer, size)) return false;
 | 
			
		||||
	if (!search_key(buffer, record_id)) return false;	// Record not found
 | 
			
		||||
	if (!get_u8(buffer, false, value)) return false;	// Value isn't a u8
 | 
			
		||||
	
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, int64_t * value) {
 | 
			
		||||
	uint8_t byte;
 | 
			
		||||
	
 | 
			
		||||
	init_search(buffer, size);
 | 
			
		||||
	if (!search_key(buffer, record_id)) return false;	// Record not found
 | 
			
		||||
	
 | 
			
		||||
	if ((seek_ptr + 3) >= buffer_size) return false;	// End of buffer
 | 
			
		||||
	if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S64)) return false;		// Value isn't a s64
 | 
			
		||||
	*value = ((int64_t)((uint8_t*)buffer)[seek_ptr] << 56) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 1] << 48) |
 | 
			
		||||
				((int64_t)((uint8_t*)buffer)[seek_ptr + 2] << 40) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 3] << 32) |
 | 
			
		||||
				(((uint8_t*)buffer)[seek_ptr + 4] << 24) | (((uint8_t*)buffer)[seek_ptr + 5] << 16) |
 | 
			
		||||
				(((uint8_t*)buffer)[seek_ptr + 6] << 8) | ((uint8_t*)buffer)[seek_ptr + 7];
 | 
			
		||||
	
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, std::string& value) {
 | 
			
		||||
	init_search(buffer, size);
 | 
			
		||||
	if (!search_key(buffer, record_id)) return false;	// Record not found
 | 
			
		||||
	if (!get_string(buffer, false, value)) return false;	// Value isn't a char array
 | 
			
		||||
	
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void MsgPack::msgpack_init(const void * buffer, size_t * ptr) {
 | 
			
		||||
	((uint8_t*)buffer)[0] = MSGPACK_TYPE_MAP16;
 | 
			
		||||
	((uint8_t*)buffer)[1] = 0;
 | 
			
		||||
	((uint8_t*)buffer)[2] = 0;
 | 
			
		||||
	
 | 
			
		||||
	*ptr = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MsgPack::add_key(const void * buffer, size_t * ptr, const RecID record_id) {
 | 
			
		||||
	uint16_t key;
 | 
			
		||||
	
 | 
			
		||||
	((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U16;
 | 
			
		||||
	((uint8_t*)buffer)[(*ptr)++] = record_id >> 8;
 | 
			
		||||
	((uint8_t*)buffer)[(*ptr)++] = record_id & 0xFF;
 | 
			
		||||
	
 | 
			
		||||
	// Auto-inc MAP16 size which should be at the beginning of the buffer
 | 
			
		||||
	
 | 
			
		||||
	key = (((uint8_t*)buffer)[1] << 8) | ((uint8_t*)buffer)[2];
 | 
			
		||||
	key++;
 | 
			
		||||
	
 | 
			
		||||
	((uint8_t*)buffer)[1] = key >> 8;
 | 
			
		||||
	((uint8_t*)buffer)[2] = key & 0xFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, bool value) {
 | 
			
		||||
	add_key(buffer, ptr, record_id);
 | 
			
		||||
	
 | 
			
		||||
	if (value)
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TRUE;
 | 
			
		||||
	else
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = MSGPACK_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, uint8_t value) {
 | 
			
		||||
	add_key(buffer, ptr, record_id);
 | 
			
		||||
	
 | 
			
		||||
	if (value < 128) {
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = value;
 | 
			
		||||
	} else {
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U8;
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, int64_t value) {
 | 
			
		||||
	uint8_t c;
 | 
			
		||||
	
 | 
			
		||||
	add_key(buffer, ptr, record_id);
 | 
			
		||||
	
 | 
			
		||||
	((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_S64;
 | 
			
		||||
	
 | 
			
		||||
	for (c = 0; c < 8; c++)
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = (value >> (8 * (7 - c))) & 0xFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, std::string value) {
 | 
			
		||||
	uint8_t c;
 | 
			
		||||
	size_t length;
 | 
			
		||||
	
 | 
			
		||||
	add_key(buffer, ptr, record_id);
 | 
			
		||||
	
 | 
			
		||||
	length = value.size();
 | 
			
		||||
	
 | 
			
		||||
	if (length < 32) {
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = length | 0xA0;			// Fixstr
 | 
			
		||||
	} else if ((length >= 32) && (length < 256)) {
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR8;
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = length;
 | 
			
		||||
	} else if ((length >= 256) && (length < 65536)) {
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR16;
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = length >> 8;
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = length & 0xFF;
 | 
			
		||||
	} else {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	for (c = 0; c < length; c++)
 | 
			
		||||
		((uint8_t*)buffer)[(*ptr)++] = value[c];
 | 
			
		||||
		
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								Software/portapack-mayhem/firmware/common/msgpack.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Software/portapack-mayhem/firmware/common/msgpack.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * 
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MSGPACK_H__
 | 
			
		||||
#define __MSGPACK_H__
 | 
			
		||||
 | 
			
		||||
#include "ui.hpp"
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_NIL			0xC0
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_FALSE		0xC2
 | 
			
		||||
#define MSGPACK_TRUE		0xC3
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_TYPE_F32	0xCA
 | 
			
		||||
#define MSGPACK_TYPE_F64	0xCB
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_TYPE_U8		0xCC
 | 
			
		||||
#define MSGPACK_TYPE_U16	0xCD
 | 
			
		||||
#define MSGPACK_TYPE_U32	0xCE
 | 
			
		||||
#define MSGPACK_TYPE_U64	0xCF
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_TYPE_S8		0xD0
 | 
			
		||||
#define MSGPACK_TYPE_S16	0xD1
 | 
			
		||||
#define MSGPACK_TYPE_S32	0xD2
 | 
			
		||||
#define MSGPACK_TYPE_S64	0xD3
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_TYPE_STR8	0xD9
 | 
			
		||||
#define MSGPACK_TYPE_STR16	0xDA
 | 
			
		||||
#define MSGPACK_TYPE_STR32	0xDB
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_TYPE_ARR16	0xDC
 | 
			
		||||
#define MSGPACK_TYPE_ARR32	0xDD
 | 
			
		||||
 | 
			
		||||
#define MSGPACK_TYPE_MAP16	0xDE
 | 
			
		||||
#define MSGPACK_TYPE_MAP32	0xDF
 | 
			
		||||
 | 
			
		||||
class MsgPack {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	enum RecID {
 | 
			
		||||
		TestListA = 0,
 | 
			
		||||
		TestListB = 1,
 | 
			
		||||
		TestListC = 2,
 | 
			
		||||
		TestListD = 3,
 | 
			
		||||
		TestListE = 4
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Read
 | 
			
		||||
	bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, bool * value);
 | 
			
		||||
	bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, uint8_t * value);
 | 
			
		||||
	bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, int64_t * value);
 | 
			
		||||
	bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, std::string& value);
 | 
			
		||||
	
 | 
			
		||||
	// Write
 | 
			
		||||
	void msgpack_init(const void * buffer, size_t * ptr);
 | 
			
		||||
	void msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, bool value);
 | 
			
		||||
	void msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, uint8_t value);
 | 
			
		||||
	void msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, int64_t value);
 | 
			
		||||
	bool msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, std::string value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool get_raw_byte(const void * buffer, const bool inc, uint8_t * byte);
 | 
			
		||||
	bool get_raw_word(const void * buffer, const bool inc, uint16_t * word);
 | 
			
		||||
	bool get_bool(const void * buffer, const bool inc, bool * value);
 | 
			
		||||
	bool get_u8(const void * buffer, const bool inc, uint8_t * value);
 | 
			
		||||
	bool get_u16(const void * buffer, const bool inc, uint16_t * value);
 | 
			
		||||
	bool get_s32(const void * buffer, const bool inc, int32_t * value);
 | 
			
		||||
	bool get_string(const void * buffer, const bool inc, std::string& value);
 | 
			
		||||
	
 | 
			
		||||
	void add_key(const void * buffer, size_t * ptr, const RecID record_id);
 | 
			
		||||
	
 | 
			
		||||
	bool init_search(const void * buffer, const size_t size);
 | 
			
		||||
	bool search_key(const void * buffer, const RecID record_id);
 | 
			
		||||
	bool skip(const void * buffer);
 | 
			
		||||
	
 | 
			
		||||
	size_t seek_ptr = 0;
 | 
			
		||||
	size_t buffer_size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										42
									
								
								Software/portapack-mayhem/firmware/common/optional.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								Software/portapack-mayhem/firmware/common/optional.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __OPTIONAL_H__
 | 
			
		||||
#define __OPTIONAL_H__
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
class Optional {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr Optional() : value_ { }, valid_ { false } { };
 | 
			
		||||
	constexpr Optional(const T& value) : value_ { value }, valid_ { true } { };
 | 
			
		||||
	constexpr Optional(T&& value) : value_ { std::move(value) }, valid_ { true } { };
 | 
			
		||||
 | 
			
		||||
	bool is_valid() const { return valid_; };
 | 
			
		||||
	T value() const { return value_; };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	T value_;
 | 
			
		||||
	bool valid_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__OPTIONAL_H__*/
 | 
			
		||||
							
								
								
									
										233
									
								
								Software/portapack-mayhem/firmware/common/pins.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								Software/portapack-mayhem/firmware/common/pins.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,233 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of PortaPack.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
 * the Free Software Foundation, Inc., 51 Franklin Street,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PINS_H__
 | 
			
		||||
#define __PINS_H__
 | 
			
		||||
 | 
			
		||||
#include "gpio.hpp"
 | 
			
		||||
 | 
			
		||||
namespace lpc43xx {
 | 
			
		||||
 | 
			
		||||
enum Pins {
 | 
			
		||||
	P0_0, P0_1,
 | 
			
		||||
	P1_0, P1_1, P1_2, P1_3, P1_4, P1_5, P1_6, P1_7, P1_8, P1_9, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15, P1_16, P1_17, P1_18, P1_19, P1_20,
 | 
			
		||||
	P2_0, P2_1, P2_2, P2_3, P2_4, P2_5, P2_6, P2_7, P2_8, P2_9, P2_10, P2_11, P2_12, P2_13,
 | 
			
		||||
	P3_0, P3_1, P3_2,
 | 
			
		||||
	P4_0, P4_1, P4_2, P4_3, P4_4, P4_5, P4_6, P4_7, P4_8, P4_9, P4_10,
 | 
			
		||||
	P5_0, P5_1, P5_2, P5_3, P5_4, P5_5, P5_6, P5_7,
 | 
			
		||||
	P6_0, P6_1, P6_2, P6_3, P6_4, P6_5, P6_6, P6_7, P6_8, P6_9, P6_10, P6_11, P6_12,
 | 
			
		||||
	P7_0, P7_1, P7_2, P7_3, P7_4, P7_5, P7_6, P7_7,
 | 
			
		||||
	P9_5, P9_6,
 | 
			
		||||
	PF_4,
 | 
			
		||||
	CLK0, CLK2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr Pin pins[] = {
 | 
			
		||||
	[P0_0]  = {  0,  0, PinConfig::sgpio_inout_fast(3) }, /* SGPIO0/P75/BANK2F3M3: CPLD.89/HOST_DATA0(IO) */
 | 
			
		||||
	[P0_1]  = {  0,  1, PinConfig::sgpio_inout_fast(3) }, /* SGPIO1/BANK2F3M5: CPLD.79/HOST_DATA1(IO) */
 | 
			
		||||
	[P1_0]  = {  1,  0, PinConfig::sgpio_inout_fast(6) }, /* SGPIO7/P76/BANK2F3M7: CPLD.77/HOST_DATA7(IO) */
 | 
			
		||||
	[P1_1]  = {  1,  1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P1_1/P74: 10K PU, BOOT0 */
 | 
			
		||||
	[P1_2]  = {  1,  2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P1_2/P73: 10K PD, BOOT1 */
 | 
			
		||||
	[P1_3]  = {  1,  3, { .mode=5, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* SSP1_MISO/P41: MAX2837.DOUT(O) */
 | 
			
		||||
	[P1_4]  = {  1,  4, { .mode=5, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_MOSI/P40: MAX2837.DIN(I), MAX5864.DIN(I) */
 | 
			
		||||
	[P1_5]  = {  1,  5, { .mode=0, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* SD_POW: PortaPack CPLD.TDO(O) */
 | 
			
		||||
	[P1_6]  = {  1,  6, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_CMD: PortaPack SD.CMD(IO)  */
 | 
			
		||||
	[P1_7]  = {  1,  7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !MIX_BYPASS/P35: U1.VCTL1(I), U11.VCTL2(I), U9.V2(I) */
 | 
			
		||||
	[P1_8]  = {  1,  8, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* SD_VOLT0: PortaPack CPLD.TMS(I) */
 | 
			
		||||
	[P1_9]  = {  1,  9, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT0: PortaPack SD.DAT0(IO) */
 | 
			
		||||
	[P1_10] = {  1, 10, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT1: PortaPack SD.DAT1(IO) */
 | 
			
		||||
	[P1_11] = {  1, 11, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT2: PortaPack SD.DAT2(IO) */
 | 
			
		||||
	[P1_12] = {  1, 12, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT3: PortaPack SD.DAT3(IO) */
 | 
			
		||||
	[P1_13] = {  1, 13, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* SD_CD: PortaPack SD.CD(O) */
 | 
			
		||||
	[P1_14] = {  1, 14, PinConfig::sgpio_out_fast_with_pullup(6) }, /* SGPIO10/P78/BANK2F3M8: CPLD.76/HOST_DISABLE(I) */
 | 
			
		||||
	[P1_15] = {  1, 15, PinConfig::sgpio_inout_fast(2) }, /* SGPIO2/BANK2F3M9: CPLD.74/HOST_DATA2(IO) */
 | 
			
		||||
	[P1_16] = {  1, 16, PinConfig::sgpio_inout_fast(2) }, /* SGPIO3/BANK2F3M10: CPLD.72/HOST_DATA3(IO) */
 | 
			
		||||
	[P1_17] = {  1, 17, PinConfig::sgpio_out_fast_with_pullup(6) }, /* SGPIO11/P79/BANK2F3M11: CPLD.71/HOST_DIRECTION(I) */
 | 
			
		||||
	[P1_18] = {  1, 18, PinConfig::gpio_out_with_pulldown(0) }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_INVERT(I) */
 | 
			
		||||
	[P1_19] = {  1, 19, { .mode=1, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */
 | 
			
		||||
	[P1_20] = {  1, 20, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CS_XCVR/P53: MAX2837.CS(I) */
 | 
			
		||||
	[P2_0]  = {  2,  0, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* U0_TXD: PortaPack P2_0/IO_STBX */
 | 
			
		||||
	[P2_1]  = {  2,  1, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* U0_RXD: PortaPack P2_1/ADDR */
 | 
			
		||||
	[P2_2]  = {  2,  2, PinConfig::sgpio_inout_fast(0) }, /* SGPIO6/BANK2F3M16: CPLD.61/HOST_DATA6(IO) */
 | 
			
		||||
	[P2_3]  = {  2,  3, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* I2C1_SDA: PortaPack P2_3/LCD_TE */
 | 
			
		||||
	[P2_4]  = {  2,  4, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* I2C1_SCL: PortaPack P2_4/LCD_RDX */
 | 
			
		||||
	[P2_5]  = {  2,  5, { .mode=4, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* RX/P43: U7.VCTL1(I), U10.VCTL1(I), U2.VCTL1(I) */
 | 
			
		||||
	[P2_6]  = {  2,  6, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_SCLK/P31: 33pF, RFFC5072.SCLK(I) */
 | 
			
		||||
	[P2_7]  = {  2,  7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* ISP: 10K PU, Unused */
 | 
			
		||||
	[P2_8]  = {  2,  8, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P2_8: 10K PD, BOOT2, DFU switch, PortaPack P2_8/<unused> */
 | 
			
		||||
	[P2_9]  = {  2,  9, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P2_9: 10K PD, BOOT3, PortaPack P2_9/LCD_WRX */
 | 
			
		||||
	[P2_10] = {  2, 10, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */
 | 
			
		||||
	[P2_11] = {  2, 11, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RX_AMP/P49: U12.V1(I), U14.V3(I) */
 | 
			
		||||
	[P2_12] = {  2, 12, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !RX_AMP_PWR/P52: 10K PU, Q1.G(I), power to U13 (RX amp) */
 | 
			
		||||
	[P2_13] = {  2, 13, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P2_13: PortaPack P2_13/DIR */
 | 
			
		||||
	[P3_0]  = {  3,  0, { .mode=2, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* I2S0_TX_SCK: PortaPack I2S0_TX_SCK(I) */
 | 
			
		||||
	[P3_1]  = {  3,  1, { .mode=0, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* I2S0_RX_WS: PortaPack I2S0_TX_WS(I). Input enabled to fold back into RX. */
 | 
			
		||||
	[P3_2]  = {  3,  2, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_SDA: PortaPack I2S0_TX_SDA(I) */
 | 
			
		||||
	[P4_0]  = {  4,  0, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* HP/P44: U6.VCTL1(I), U5.VCTL2(I) */
 | 
			
		||||
	[P4_1]  = {  4,  1, PinConfig::gpio_led(0) }, /* LED1: LED1.A(I) */
 | 
			
		||||
	[P4_2]  = {  4,  2, PinConfig::gpio_led(0) }, /* LED2: LED2.A(I) */
 | 
			
		||||
	[P4_3]  = {  4,  3, PinConfig::sgpio_in_fast(7) }, /* SGPIO9/P77/BANK2F3M1: CPLD.91/HOST_CAPTURE(O) */
 | 
			
		||||
	[P4_4]  = {  4,  4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TXENABLE/P55: MAX2837.TXENABLE(I) */
 | 
			
		||||
	[P4_5]  = {  4,  5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RXENABLE/P56: MAX2837.RXENABLE(I) */
 | 
			
		||||
	[P4_6]  = {  4,  6, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* XCVR_EN: 10K PD, MAX2837.ENABLE(I) */
 | 
			
		||||
	[P4_7]  = {  4,  7, { .mode=1, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=0 } }, /* GP_CLKIN/P72/MCU_CLK: SI5351C.CLK7(O) */
 | 
			
		||||
	[P4_8]  = {  4,  8, PinConfig::floating_input_with_pull(0, 4) }, /* SGPIO13/BANK2F3M2: CPLD.90/HOST_SYNC_EN(I) */
 | 
			
		||||
	[P4_9]  = {  4,  9, PinConfig::floating_input(4) }, /* SGPIO14/BANK2F3M4: CPLD.81(I) */
 | 
			
		||||
	[P4_10] = {  4, 10, PinConfig::floating_input(4) }, /* SGPIO15/BANK2F3M6: CPLD.78(I) */
 | 
			
		||||
	[P5_0]  = {  5,  0, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !VAA_ENABLE: 10K PU, Q3.G(I), power to VAA */
 | 
			
		||||
	[P5_1]  = {  5,  1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* LP/P45: U6.VCTL2(I), U5.VCTL1(I) */
 | 
			
		||||
	[P5_2]  = {  5,  2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_MIX_BP/P46: U9.V1(I) */
 | 
			
		||||
	[P5_3]  = {  5,  3, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RX_MIX_BP/P47: U9.V3(I) */
 | 
			
		||||
	[P5_4]  = {  5,  4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_ENX/P32: 10K PU, 33pF, RFFC5072.ENX(I) */
 | 
			
		||||
	[P5_5]  = {  5,  5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_RESETX/P33: 10K PU, 33pF, RFFC5072.RESETX(I) */
 | 
			
		||||
	[P5_6]  = {  5,  6, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_AMP/P48: U12.V3(I), U14.V1(I) */
 | 
			
		||||
	[P5_7]  = {  5,  7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CS_AD/P54: MAX5864.CS(I) */
 | 
			
		||||
	[P6_0]  = {  6,  0, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_MCLK: Unused */
 | 
			
		||||
	[P6_1]  = {  6,  1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TCK: CPLD.TCK(I), PortaPack CPLD.TCK(I) */
 | 
			
		||||
	[P6_2]  = {  6,  2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDI: CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) */
 | 
			
		||||
	[P6_3]  = {  6,  3, PinConfig::sgpio_inout_fast(2) }, /* SGPIO4/BANK2F3M14: CPLD.67/HOST_DATA4(IO) */
 | 
			
		||||
	[P6_4]  = {  6,  4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* MIXER_SDATA/P27: 33pF, RFFC5072.SDATA(IO) */
 | 
			
		||||
	[P6_5]  = {  6,  5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TMS: CPLD.TMS(I) */
 | 
			
		||||
	[P6_6]  = {  6,  6, PinConfig::sgpio_inout_fast(2) }, /* SGPIO5/BANK2F3M15: CPLD.64/HOST_DATA5(IO) */
 | 
			
		||||
	[P6_7]  = {  6,  7, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX/P42: U7.VCTL2(I), U10.VCTL2(I), U2.VCTL2(I) */
 | 
			
		||||
	[P6_8]  = {  6,  8, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIX_BYPASS/P34: U1.VCTL2(I), U11.VCTL1(I) */
 | 
			
		||||
	[P6_9]  = {  6,  9, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !TX_AMP_PWR/P51: 10K PU, Q2.G(I), power to U25 (TX amp) */
 | 
			
		||||
	[P6_10] = {  6, 10, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* EN1V8/P70: 10K PD, TPS62410.EN2(I), 1V8LED.A(I) */
 | 
			
		||||
	[P6_11] = {  6, 11, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* VREGMODE/P69: TPS62410.MODE/DATA(I) */
 | 
			
		||||
	[P6_12] = {  6, 12, PinConfig::gpio_led(0) }, /* LED3: LED3.A(I) */
 | 
			
		||||
	[P7_0]  = {  7,  0, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_8: PortaPack GPIO3_8(IO) */
 | 
			
		||||
	[P7_1]  = {  7,  1, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_9: PortaPack GPIO3_9(IO) */
 | 
			
		||||
	[P7_2]  = {  7,  2, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_10: PortaPack GPIO3_10(IO) */
 | 
			
		||||
	[P7_3]  = {  7,  3, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_11: PortaPack GPIO3_11(IO) */
 | 
			
		||||
	[P7_4]  = {  7,  4, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_12: PortaPack GPIO3_12(IO) */
 | 
			
		||||
	[P7_5]  = {  7,  5, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_13: PortaPack GPIO3_13(IO) */
 | 
			
		||||
	[P7_6]  = {  7,  6, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_14: PortaPack GPIO3_14(IO) */
 | 
			
		||||
	[P7_7]  = {  7,  7, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_15: PortaPack GPIO3_15(IO) */
 | 
			
		||||
	[P9_5]  = {  9,  5, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDO: CPLD.TDO(O) */
 | 
			
		||||
	[P9_6]  = {  9,  6, PinConfig::sgpio_in_fast(6) }, /* SGPIO8/SGPIO_CLK/P60: SI5351C.CLK2(O) */
 | 
			
		||||
	[PF_4]  = { 15,  4, { .mode=7, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_SCK: Unused */
 | 
			
		||||
	[CLK0]  = { 24,  0, { .mode=4, .pd=1, .pu=0, .fast=0, .input=1, .ifilt=0 } }, /* SD_CLK: PortaPack SD.CLK, enable input buffer for timing feedback? */
 | 
			
		||||
	[CLK2]  = { 24,  2, { .mode=6, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_TX_CLK: PortaPack I2S0_TX_MCLK */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum GPIOs {
 | 
			
		||||
	GPIO0_0, GPIO0_1, GPIO0_2, GPIO0_3, GPIO0_4, GPIO0_5, /*GPIO0_6,*/ GPIO0_7, GPIO0_8, GPIO0_9, GPIO0_10, GPIO0_11, GPIO0_12, GPIO0_13, GPIO0_14, GPIO0_15,
 | 
			
		||||
	GPIO1_0, GPIO1_1, GPIO1_2, GPIO1_3, GPIO1_4, GPIO1_5, GPIO1_6, GPIO1_7, GPIO1_8, GPIO1_9, GPIO1_10, GPIO1_11, GPIO1_12, GPIO1_13, /*GPIO1_14, GPIO1_15,*/
 | 
			
		||||
	GPIO2_0, GPIO2_1, GPIO2_2, GPIO2_3, GPIO2_4, GPIO2_5, GPIO2_6, GPIO2_7, GPIO2_8, GPIO2_9, GPIO2_10, GPIO2_11, GPIO2_12, GPIO2_13, GPIO2_14, GPIO2_15,
 | 
			
		||||
	GPIO3_0, GPIO3_1, GPIO3_2, GPIO3_3, GPIO3_4, GPIO3_5, GPIO3_6, GPIO3_7, GPIO3_8, GPIO3_9, GPIO3_10, GPIO3_11, GPIO3_12, GPIO3_13, GPIO3_14, GPIO3_15,
 | 
			
		||||
	GPIO4_11,
 | 
			
		||||
	GPIO5_0, GPIO5_1, GPIO5_2, GPIO5_3, GPIO5_4, GPIO5_5, GPIO5_6, GPIO5_7, GPIO5_8, GPIO5_9, /*GPIO5_10, GPIO5_11,*/ GPIO5_12, GPIO5_13, GPIO5_14, GPIO5_15, GPIO5_16, GPIO5_18,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr GPIO gpio[] = {
 | 
			
		||||
	[GPIO0_0]  = { pins[P0_0],  0,  0, 0 },
 | 
			
		||||
	[GPIO0_1]  = { pins[P0_1],  0,  1, 0 },
 | 
			
		||||
	[GPIO0_2]  = { pins[P1_15], 0,  2, 0 },
 | 
			
		||||
	[GPIO0_3]  = { pins[P1_16], 0,  3, 0 },
 | 
			
		||||
	[GPIO0_4]  = { pins[P1_0],  0,  4, 0 },
 | 
			
		||||
	[GPIO0_5]  = { pins[P6_6],  0,  5, 0 },
 | 
			
		||||
	//[GPIO0_6]  = { pins[P3_6],  0,  6, 0 },
 | 
			
		||||
	[GPIO0_7]  = { pins[P2_7],  0,  7, 0 },
 | 
			
		||||
	[GPIO0_8]  = { pins[P1_1],  0,  8, 0 },
 | 
			
		||||
	[GPIO0_9]  = { pins[P1_2],  0,  9, 0 },
 | 
			
		||||
	[GPIO0_10] = { pins[P1_3],  0, 10, 0 },
 | 
			
		||||
	[GPIO0_11] = { pins[P1_4],  0, 11, 0 },
 | 
			
		||||
	[GPIO0_12] = { pins[P1_17], 0, 12, 0 },
 | 
			
		||||
	[GPIO0_13] = { pins[P1_18], 0, 13, 0 },
 | 
			
		||||
	[GPIO0_14] = { pins[P2_10], 0, 14, 0 },
 | 
			
		||||
	[GPIO0_15] = { pins[P1_20], 0, 15, 0 },
 | 
			
		||||
 | 
			
		||||
	[GPIO1_0]  = { pins[P1_7],  1,  0, 0 },
 | 
			
		||||
	[GPIO1_1]  = { pins[P1_8],  1,  1, 0 },
 | 
			
		||||
	[GPIO1_2]  = { pins[P1_9],  1,  2, 0 },
 | 
			
		||||
	[GPIO1_3]  = { pins[P1_10], 1,  3, 0 },
 | 
			
		||||
	[GPIO1_4]  = { pins[P1_11], 1,  4, 0 },
 | 
			
		||||
	[GPIO1_5]  = { pins[P1_12], 1,  5, 0 },
 | 
			
		||||
	[GPIO1_6]  = { pins[P1_13], 1,  6, 0 },
 | 
			
		||||
	[GPIO1_7]  = { pins[P1_14], 1,  7, 0 },
 | 
			
		||||
	[GPIO1_8]  = { pins[P1_5],  1,  8, 0 },
 | 
			
		||||
	[GPIO1_9]  = { pins[P1_6],  1,  9, 0 },
 | 
			
		||||
	[GPIO1_10] = { pins[P2_9],  1, 10, 0 },
 | 
			
		||||
	[GPIO1_11] = { pins[P2_11], 1, 11, 0 },
 | 
			
		||||
	[GPIO1_12] = { pins[P2_12], 1, 12, 0 },
 | 
			
		||||
	[GPIO1_13] = { pins[P2_13], 1, 13, 0 },
 | 
			
		||||
	//[GPIO1_14] = { pins[P3_4],  1, 14, 0 },
 | 
			
		||||
	//[GPIO1_15] = { pins[P3_5],  1, 15, 0 },
 | 
			
		||||
 | 
			
		||||
	[GPIO2_0]  = { pins[P4_0],  2,  0, 0 },
 | 
			
		||||
	[GPIO2_1]  = { pins[P4_1],  2,  1, 0 },
 | 
			
		||||
	[GPIO2_2]  = { pins[P4_2],  2,  2, 0 },
 | 
			
		||||
	[GPIO2_3]  = { pins[P4_3],  2,  3, 0 },
 | 
			
		||||
	[GPIO2_4]  = { pins[P4_4],  2,  4, 0 },
 | 
			
		||||
	[GPIO2_5]  = { pins[P4_5],  2,  5, 0 },
 | 
			
		||||
	[GPIO2_6]  = { pins[P4_6],  2,  6, 0 },
 | 
			
		||||
	[GPIO2_7]  = { pins[P5_7],  2,  7, 0 },
 | 
			
		||||
	[GPIO2_8]  = { pins[P6_12], 2,  8, 0 },
 | 
			
		||||
	[GPIO2_9]  = { pins[P5_0],  2,  9, 0 },
 | 
			
		||||
	[GPIO2_10] = { pins[P5_1],  2, 10, 0 },
 | 
			
		||||
	[GPIO2_11] = { pins[P5_2],  2, 11, 0 },
 | 
			
		||||
	[GPIO2_12] = { pins[P5_3],  2, 12, 0 },
 | 
			
		||||
	[GPIO2_13] = { pins[P5_4],  2, 13, 0 },
 | 
			
		||||
	[GPIO2_14] = { pins[P5_5],  2, 14, 0 },
 | 
			
		||||
	[GPIO2_15] = { pins[P5_6],  2, 15, 0 },
 | 
			
		||||
 | 
			
		||||
	[GPIO3_0]  = { pins[P6_1],  3,  0, 0 },
 | 
			
		||||
	[GPIO3_1]  = { pins[P6_2],  3,  1, 0 },
 | 
			
		||||
	[GPIO3_2]  = { pins[P6_3],  3,  2, 0 },
 | 
			
		||||
	[GPIO3_3]  = { pins[P6_4],  3,  3, 0 },
 | 
			
		||||
	[GPIO3_4]  = { pins[P6_5],  3,  4, 0 },
 | 
			
		||||
	[GPIO3_5]  = { pins[P6_9],  3,  5, 0 },
 | 
			
		||||
	[GPIO3_6]  = { pins[P6_10], 3,  6, 0 },
 | 
			
		||||
	[GPIO3_7]  = { pins[P6_11], 3,  7, 0 },
 | 
			
		||||
	[GPIO3_8]  = { pins[P7_0],  3,  8, 0 },
 | 
			
		||||
	[GPIO3_9]  = { pins[P7_1],  3,  9, 0 },
 | 
			
		||||
	[GPIO3_10] = { pins[P7_2],  3, 10, 0 },
 | 
			
		||||
	[GPIO3_11] = { pins[P7_3],  3, 11, 0 },
 | 
			
		||||
	[GPIO3_12] = { pins[P7_4],  3, 12, 0 },
 | 
			
		||||
	[GPIO3_13] = { pins[P7_5],  3, 13, 0 },
 | 
			
		||||
	[GPIO3_14] = { pins[P7_6],  3, 14, 0 },
 | 
			
		||||
	[GPIO3_15] = { pins[P7_7],  3, 15, 0 },
 | 
			
		||||
 | 
			
		||||
	[GPIO4_11] = { pins[P9_6],  4, 11, 0 },
 | 
			
		||||
 | 
			
		||||
	[GPIO5_0]  = { pins[P2_0],  5,  0, 4 },
 | 
			
		||||
	[GPIO5_1]  = { pins[P2_1],  5,  1, 4 },
 | 
			
		||||
	[GPIO5_2]  = { pins[P2_2],  5,  2, 4 },
 | 
			
		||||
	[GPIO5_3]  = { pins[P2_3],  5,  3, 4 },
 | 
			
		||||
	[GPIO5_4]  = { pins[P2_4],  5,  4, 4 },
 | 
			
		||||
	[GPIO5_5]  = { pins[P2_5],  5,  5, 4 },
 | 
			
		||||
	[GPIO5_6]  = { pins[P2_6],  5,  6, 4 },
 | 
			
		||||
	[GPIO5_7]  = { pins[P2_8],  5,  7, 4 },
 | 
			
		||||
	[GPIO5_8]  = { pins[P3_1],  5,  8, 4 },
 | 
			
		||||
	[GPIO5_9]  = { pins[P3_2],  5,  9, 4 },
 | 
			
		||||
	//[GPIO5_10] = { pins[P3_7],  5, 10, 4 },
 | 
			
		||||
	//[GPIO5_11] = { pins[P3_8],  5, 11, 4 },
 | 
			
		||||
	[GPIO5_12] = { pins[P4_8],  5, 12, 4 },
 | 
			
		||||
	[GPIO5_13] = { pins[P4_9],  5, 13, 4 },
 | 
			
		||||
	[GPIO5_14] = { pins[P4_10], 5, 14, 4 },
 | 
			
		||||
	[GPIO5_15] = { pins[P6_7],  5, 15, 4 },
 | 
			
		||||
	[GPIO5_16] = { pins[P6_8],  5, 16, 4 },
 | 
			
		||||
	[GPIO5_18] = { pins[P9_5],  5, 18, 4 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif/*__PINS_H__*/
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user