mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-14 10:39:30 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e95288c1f | |||
| cad70d6e39 | |||
| 84e7f517ba | |||
| 0840756c0e | |||
| 6dadefe86f | |||
| ea40e3a46d | |||
| 86584feb16 | |||
| 47c94dbf26 |
@@ -59,7 +59,7 @@ void DfuMenu::paint(Painter& painter) {
|
||||
text_info_line_7.set(to_string_dec_uint(shared_memory.m4_stack_usage, 6));
|
||||
text_info_line_8.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
|
||||
text_info_line_9.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
|
||||
text_info_line_10.set(to_string_dec_uint(chTimeNow() / 1000, 6));
|
||||
text_info_line_10.set(to_string_dec_uint(chTimeNow() / CH_FREQUENCY, 6));
|
||||
|
||||
constexpr auto margin = 5;
|
||||
|
||||
|
||||
@@ -362,7 +362,6 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
&toggle_bias_tee,
|
||||
&toggle_clock,
|
||||
&toggle_mute,
|
||||
&toggle_fake_brightness,
|
||||
&toggle_sd_card,
|
||||
&button_save,
|
||||
&button_cancel});
|
||||
@@ -399,7 +398,6 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
toggle_clock.set_value(!pmem::ui_hide_clock());
|
||||
toggle_speaker.set_value(!pmem::ui_hide_speaker());
|
||||
toggle_mute.set_value(!pmem::ui_hide_mute());
|
||||
toggle_fake_brightness.set_value(!pmem::ui_hide_fake_brightness());
|
||||
toggle_battery_icon.set_value(!pmem::ui_hide_battery_icon());
|
||||
toggle_battery_text.set_value(!pmem::ui_hide_numeric_battery());
|
||||
toggle_sd_card.set_value(!pmem::ui_hide_sd_card());
|
||||
@@ -427,7 +425,6 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
pmem::set_ui_hide_clock(!toggle_clock.value());
|
||||
pmem::set_ui_hide_speaker(!toggle_speaker.value());
|
||||
pmem::set_ui_hide_mute(!toggle_mute.value());
|
||||
pmem::set_ui_hide_fake_brightness(!toggle_fake_brightness.value());
|
||||
pmem::set_ui_hide_battery_icon(!toggle_battery_icon.value());
|
||||
pmem::set_ui_hide_numeric_battery(!toggle_battery_text.value());
|
||||
pmem::set_ui_hide_sd_card(!toggle_sd_card.value());
|
||||
@@ -921,22 +918,16 @@ void SetConfigModeView::focus() {
|
||||
|
||||
SetDisplayView::SetDisplayView(NavigationView& nav) {
|
||||
add_children({&labels,
|
||||
&field_fake_brightness,
|
||||
&button_save,
|
||||
&button_cancel,
|
||||
&checkbox_brightness_switch});
|
||||
&button_cancel});
|
||||
|
||||
if (portapack::device_type == portapack::DeviceType::DEV_PORTAPACK) {
|
||||
add_child(&checkbox_ips_screen_switch);
|
||||
}
|
||||
|
||||
field_fake_brightness.set_by_value(pmem::fake_brightness_level());
|
||||
checkbox_brightness_switch.set_value(pmem::apply_fake_brightness());
|
||||
checkbox_ips_screen_switch.set_value(pmem::config_lcd_normally_black());
|
||||
|
||||
button_save.on_select = [&nav, this](Button&) {
|
||||
pmem::set_apply_fake_brightness(checkbox_brightness_switch.value());
|
||||
pmem::set_fake_brightness_level(field_fake_brightness.selected_index_value());
|
||||
if (checkbox_ips_screen_switch.value() != pmem::config_lcd_normally_black()) {
|
||||
pmem::set_lcd_normally_black(checkbox_ips_screen_switch.value());
|
||||
}
|
||||
@@ -944,14 +935,6 @@ SetDisplayView::SetDisplayView(NavigationView& nav) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
// only enable invert OR fake brightness
|
||||
checkbox_ips_screen_switch.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) checkbox_brightness_switch.set_value(false);
|
||||
};
|
||||
checkbox_brightness_switch.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) checkbox_ips_screen_switch.set_value(false);
|
||||
};
|
||||
|
||||
button_cancel.on_select = [&nav, this](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
@@ -1029,10 +1012,17 @@ void SetTouchscreenThresholdView::focus() {
|
||||
|
||||
void SetTouchscreenThresholdView::on_frame_sync() {
|
||||
if (!in_auto_detect) return;
|
||||
|
||||
uint32_t time_now = chTimeNow();
|
||||
int32_t time_diff = time_now - time_start_auto_detect;
|
||||
text_wait_timer.set("ETA " + to_string_dec_uint((10 - time_diff / 1000) <= 0 ? 0 : 10 - time_diff / 1000) + "s");
|
||||
if (time_diff >= 10001 && !auto_detect_succeed_consumed) { // 10s
|
||||
|
||||
// Calculate elapsed seconds using CH_FREQUENCY
|
||||
uint32_t elapsed_seconds = time_diff / CH_FREQUENCY;
|
||||
int32_t remaining_seconds = 10 - (int32_t)elapsed_seconds;
|
||||
if (remaining_seconds < 0) remaining_seconds = 0;
|
||||
|
||||
text_wait_timer.set("ETA " + to_string_dec_uint(remaining_seconds) + "s");
|
||||
if (elapsed_seconds >= 10 && !auto_detect_succeed_consumed) { // 10s
|
||||
in_auto_detect = false;
|
||||
text_wait_timer.hidden(true);
|
||||
text_hint.set("OK, press save and reboot");
|
||||
|
||||
@@ -404,12 +404,8 @@ class SetUIView : public View {
|
||||
{19 * 8, 12 * 16 + 2, 16, 16},
|
||||
&bitmap_icon_batt_text};
|
||||
|
||||
ImageToggle toggle_fake_brightness{
|
||||
{21 * 8, 12 * 16 + 2, 16, 16},
|
||||
&bitmap_icon_brightness};
|
||||
|
||||
ImageToggle toggle_sd_card{
|
||||
{23 * 8, 12 * 16 + 2, 16, 16},
|
||||
{21 * 8, 12 * 16 + 2, 16, 16},
|
||||
&bitmap_sd_card_ok};
|
||||
|
||||
Button button_save{
|
||||
@@ -811,7 +807,6 @@ class SetConfigModeView : public View {
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
using portapack::persistent_memory::fake_brightness_level_options;
|
||||
|
||||
class SetDisplayView : public View {
|
||||
public:
|
||||
@@ -823,26 +818,9 @@ class SetDisplayView : public View {
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{1 * 8, 1 * 16}, "Limits screen brightness", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 2 * 16}, "(has a small performance", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 3 * 16}, "impact when enabled).", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 8 * 16}, "Brightness:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 10 * 16}, "REBOOT TO APPLY SCREEN TYPE", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
};
|
||||
|
||||
OptionsField field_fake_brightness{
|
||||
{20 * 8, 8 * 16},
|
||||
6,
|
||||
{{"12.5%", fake_brightness_level_options::BRIGHTNESS_12p5},
|
||||
{"25%", fake_brightness_level_options::BRIGHTNESS_25},
|
||||
{"50%", fake_brightness_level_options::BRIGHTNESS_50}}};
|
||||
|
||||
Checkbox checkbox_brightness_switch{
|
||||
{1 * 8, 5 * 16},
|
||||
16,
|
||||
"Enable brightness adjust"};
|
||||
|
||||
Checkbox checkbox_ips_screen_switch{
|
||||
{1 * 8, 12 * 16},
|
||||
23,
|
||||
|
||||
@@ -74,7 +74,7 @@ void SubGhzDRecentEntryDetailView::update_data() {
|
||||
console.writeln("Action: 0x" + to_string_hex(func_code));
|
||||
}
|
||||
|
||||
if (entry_.sensorType == FPS_KEELOQ) {
|
||||
if (entry_.sensorType == FPS_KEELOQ || entry_.sensorType == FPS_SUPERROLLO) {
|
||||
console.writeln("Fix: " + to_string_hex(fix));
|
||||
console.writeln("Encrypted: " + to_string_hex(encrypted));
|
||||
console.writeln("Manufacturer: " + mf_name);
|
||||
@@ -243,6 +243,8 @@ const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) {
|
||||
return "Ido 11x";
|
||||
case FPS_INTERTECHNOV3:
|
||||
return "InterTehcno v3";
|
||||
case FPS_SUPERROLLO:
|
||||
return "Superrollo";
|
||||
case FPS_KEELOQ:
|
||||
return "KeeLoq";
|
||||
case FPS_KINGGATESSTYLO4K:
|
||||
@@ -671,7 +673,7 @@ void SubGhzDRecentEntryDetailView::parseProtocol() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry_.sensorType == FPS_KEELOQ) {
|
||||
if (entry_.sensorType == FPS_KEELOQ || entry_.sensorType == FPS_SUPERROLLO) {
|
||||
uint64_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data, 64);
|
||||
|
||||
btn = data_rev >> 60;
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
|
||||
#include "core_control.hpp"
|
||||
|
||||
/* Set true to enable additional checks to ensure
|
||||
* M4 and M0 are synchronized before passing messages. */
|
||||
static constexpr bool enforce_core_sync = true;
|
||||
|
||||
/* Set true to enable check for baseband messages getting stuck.
|
||||
* This implies the baseband thread is not dequeuing and has probably stalled.
|
||||
* NB: This check adds a small amout of overhead to the message sending code
|
||||
@@ -474,7 +470,7 @@ bool is_image_running() {
|
||||
return baseband_image_running;
|
||||
}
|
||||
|
||||
void run_image(const spi_flash::image_tag_t image_tag) {
|
||||
void run_image(const spi_flash::image_tag_t image_tag, bool enforce_core_sync) {
|
||||
if (baseband_image_running) {
|
||||
chDbgPanic("BBRunning");
|
||||
}
|
||||
@@ -487,7 +483,7 @@ void run_image(const spi_flash::image_tag_t image_tag) {
|
||||
|
||||
creg::m4txevent::enable();
|
||||
|
||||
if constexpr (enforce_core_sync) {
|
||||
if (enforce_core_sync) {
|
||||
// Wait up to 3 seconds for baseband to start handling events.
|
||||
auto count = 3'000u;
|
||||
while (!shared_memory.baseband_ready && --count)
|
||||
@@ -498,7 +494,7 @@ void run_image(const spi_flash::image_tag_t image_tag) {
|
||||
}
|
||||
}
|
||||
|
||||
void run_prepared_image(const uint32_t m4_code) {
|
||||
void run_prepared_image(const uint32_t m4_code, bool enforce_core_sync) {
|
||||
if (baseband_image_running) {
|
||||
chDbgPanic("BBRunning");
|
||||
}
|
||||
@@ -511,7 +507,7 @@ void run_prepared_image(const uint32_t m4_code) {
|
||||
|
||||
creg::m4txevent::enable();
|
||||
|
||||
if constexpr (enforce_core_sync) {
|
||||
if (enforce_core_sync) {
|
||||
// Wait up to 3 seconds for baseband to start handling events.
|
||||
auto count = 3'000u;
|
||||
while (!shared_memory.baseband_ready && --count)
|
||||
|
||||
@@ -131,8 +131,8 @@ void request_beep_stop();
|
||||
void request_audio_beep(uint32_t freq, uint32_t sample_rate, uint32_t duration_ms);
|
||||
|
||||
bool is_image_running();
|
||||
void run_image(const portapack::spi_flash::image_tag_t image_tag);
|
||||
void run_prepared_image(const uint32_t m4_code);
|
||||
void run_image(const portapack::spi_flash::image_tag_t image_tag, bool enforce_core_sync = true);
|
||||
void run_prepared_image(const uint32_t m4_code, bool enforce_core_sync = true);
|
||||
void shutdown();
|
||||
|
||||
void spectrum_streaming_start();
|
||||
|
||||
@@ -428,7 +428,7 @@ void ClockManager::portapack_tcxo_enable() {
|
||||
|
||||
/* Delay >10ms at 96MHz clock speed for reference oscillator to start. */
|
||||
/* Delay an additional 1ms (arbitrary) for the clock generator to detect a signal. */
|
||||
volatile uint32_t delay = 240000 + 24000;
|
||||
volatile uint32_t delay = 2400000 + 24000;
|
||||
while (delay--);
|
||||
}
|
||||
|
||||
@@ -668,37 +668,37 @@ ClockManager::ReferenceSource ClockManager::detect_reference_source() {
|
||||
}
|
||||
|
||||
ClockManager::Reference ClockManager::choose_reference() {
|
||||
#ifdef PRALINE
|
||||
const auto detected_reference = detect_reference_source();
|
||||
|
||||
if ((detected_reference == ReferenceSource::External) ||
|
||||
(detected_reference == ReferenceSource::PortaPack)) {
|
||||
const auto frequency = measure_gp_clkin_frequency();
|
||||
if ((frequency >= 9850000) && (frequency <= 10150000)) {
|
||||
return {detected_reference, 10000000};
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifndef PRALINE
|
||||
if (hackrf_r9) {
|
||||
gpio_control::r9_clkin_en.setActive();
|
||||
volatile uint32_t delay = 240000 + 24000;
|
||||
// Allow extra time for slower TCXOs on clone boards to stabilize before measurement
|
||||
volatile uint32_t delay = 240000 + 240000;
|
||||
while (delay--);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Determine reference source (respects user config and Si5351 loss-of-signal)
|
||||
const auto detected_reference = detect_reference_source();
|
||||
|
||||
// If an external or PortaPack source is detected, verify its actual frequency
|
||||
if ((detected_reference == ReferenceSource::External) ||
|
||||
(detected_reference == ReferenceSource::PortaPack)) {
|
||||
const auto frequency = measure_gp_clkin_frequency();
|
||||
|
||||
// Check if the measured frequency is within the valid 10 MHz range
|
||||
if ((frequency >= 9850000) && (frequency <= 10150000)) {
|
||||
return {detected_reference, 10000000};
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRALINE
|
||||
if (hackrf_r9) {
|
||||
// Disable r9 clock input if the 10 MHz validation failed
|
||||
gpio_control::r9_clkin_en.setInactive();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fallback: Disable PortaPack TCXO and default to the HackRF 25 MHz crystal
|
||||
portapack_tcxo_disable();
|
||||
return {ReferenceSource::Xtal, 25000000};
|
||||
}
|
||||
|
||||
@@ -89,7 +89,6 @@ bool DebugDumpView::debug_dump_func() {
|
||||
pmem_dump_file.write_line("encoder_dial_direction: " + to_string_dec_uint(encoder_dial_direction())); // 0 = normal, 1 = reverse
|
||||
pmem_dump_file.write_line("config_mode_storage: 0x" + to_string_hex(config_mode_storage_direct(), 8));
|
||||
pmem_dump_file.write_line("dst_config: 0x" + to_string_hex((uint32_t)config_dst().v, 8));
|
||||
pmem_dump_file.write_line("fake_brightness_level: " + to_string_dec_uint(fake_brightness_level()));
|
||||
pmem_dump_file.write_line("menu_color: 0x" + to_string_hex(menu_color().v, 4));
|
||||
pmem_dump_file.write_line("touchscreen_threshold: " + to_string_dec_uint(touchscreen_threshold()));
|
||||
|
||||
@@ -105,7 +104,6 @@ bool DebugDumpView::debug_dump_func() {
|
||||
pmem_dump_file.write_line("ui_config hide_clock: " + to_string_dec_uint(hide_clock()));
|
||||
pmem_dump_file.write_line("ui_config clock_with_date: " + to_string_dec_uint(clock_with_date()));
|
||||
pmem_dump_file.write_line("ui_config clkout_enabled: " + to_string_dec_uint(clkout_enabled()));
|
||||
pmem_dump_file.write_line("ui_config apply_fake_brightness: " + to_string_dec_uint(apply_fake_brightness()));
|
||||
pmem_dump_file.write_line("ui_config stealth_mode: " + to_string_dec_uint(stealth_mode()));
|
||||
pmem_dump_file.write_line("ui_config config_login: " + to_string_dec_uint(config_login()));
|
||||
pmem_dump_file.write_line("ui_config config_splash: " + to_string_dec_uint(config_splash()));
|
||||
@@ -120,7 +118,6 @@ bool DebugDumpView::debug_dump_func() {
|
||||
pmem_dump_file.write_line("ui_config2 hide_clock: " + to_string_dec_uint(ui_hide_clock()));
|
||||
pmem_dump_file.write_line("ui_config2 hide_sd_card: " + to_string_dec_uint(ui_hide_sd_card()));
|
||||
pmem_dump_file.write_line("ui_config2 hide_mute: " + to_string_dec_uint(ui_hide_mute()));
|
||||
pmem_dump_file.write_line("ui_config2 hide_fake_brightness: " + to_string_dec_uint(ui_hide_fake_brightness()));
|
||||
pmem_dump_file.write_line("ui_config2 hide_battery_icon: " + to_string_dec_uint(ui_hide_battery_icon()));
|
||||
pmem_dump_file.write_line("ui_config2 hide_numeric_battery: " + to_string_dec_uint(ui_hide_numeric_battery()));
|
||||
pmem_dump_file.write_line("ui_config2 theme_id: " + to_string_dec_uint(ui_theme_id()));
|
||||
|
||||
+5
-9
@@ -407,6 +407,10 @@ set(EXTCPPSRC
|
||||
external/aprs_tx/main.cpp
|
||||
external/aprs_tx/ui_aprs_tx.cpp
|
||||
|
||||
#sd over usb
|
||||
external/sdusb/main.cpp
|
||||
external/sdusb/ui_sd_over_usb.cpp
|
||||
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -505,13 +509,5 @@ set(EXTAPPLIST
|
||||
ais_rx
|
||||
aprs_rx
|
||||
aprs_tx
|
||||
sdusb
|
||||
)
|
||||
|
||||
# sdusb has type conflicts with PRALINE (HackRF Pro) - add only for non-PRALINE builds
|
||||
if(NOT BOARD STREQUAL "PRALINE")
|
||||
list(APPEND EXTCPPSRC
|
||||
external/sdusb/main.cpp
|
||||
external/sdusb/ui_sd_over_usb.cpp
|
||||
)
|
||||
list(APPEND EXTAPPLIST sdusb)
|
||||
endif()
|
||||
|
||||
+38
-2
@@ -34,7 +34,7 @@ void KeeloqTXView::update_hop() {
|
||||
|
||||
hop = data.btn << 28 | (apri_serial & 0xFFF) << 16 | data.counter;
|
||||
} else if (
|
||||
data.mf_name == "DTM_Neo" || data.mf_name == "FAAC_RC,XT" || data.mf_name == "Mutanco_Mutancode" || data.mf_name == "Came_Space" || data.mf_name == "Genius_Bravo" || data.mf_name == "GSN" || data.mf_name == "Rosh" || data.mf_name == "Rossi" || data.mf_name == "Peccinin" || data.mf_name == "Steelmate" || data.mf_name == "Cardin_S449") {
|
||||
data.mf_name == "DTM_Neo" || data.mf_name == "FAAC_RC,XT" || data.mf_name == "Mutanco_Mutancode" || data.mf_name == "Came_Space" || data.mf_name == "Genius_Bravo" || data.mf_name == "GSN" || data.mf_name == "Rosh" || data.mf_name == "Rossi" || data.mf_name == "Peccinin" || data.mf_name == "Steelmate" || data.mf_name == "Cardin_S449" || data.mf_name == "Superrollo") {
|
||||
hop = data.btn << 28 | (data.serial & 0xFFF) << 16 | data.counter;
|
||||
} else if (
|
||||
data.mf_name == "NICE_Smilo" || data.mf_name == "NICE_MHOUSE" || data.mf_name == "JCM_Tech") {
|
||||
@@ -75,6 +75,12 @@ void KeeloqTXView::update_payload() {
|
||||
}
|
||||
}
|
||||
|
||||
if (data.mf_name == "Superrollo") {
|
||||
text_payload.set(to_string_hex((uint64_t)(uint32_t)encrypt));
|
||||
encode_data_gw60((uint32_t)encrypt);
|
||||
return;
|
||||
}
|
||||
|
||||
payload = (uint64_t)fix << 32 | encrypt;
|
||||
|
||||
uint64_t preview_payload = FProtoGeneral::subghz_protocol_blocks_reverse_key(payload, 64);
|
||||
@@ -83,6 +89,34 @@ void KeeloqTXView::update_payload() {
|
||||
encode_data();
|
||||
}
|
||||
|
||||
// Superrollo GW60 (HCS361) 67-bit OOK frame at Te=450us.
|
||||
void KeeloqTXView::encode_data_gw60(uint32_t hop_enc) {
|
||||
int bits[67];
|
||||
for (uint32_t i = 0; i < 32; i++) bits[i] = (hop_enc >> i) & 1;
|
||||
for (uint32_t i = 0; i < 28; i++) bits[32 + i] = (data.serial >> i) & 1;
|
||||
for (uint32_t i = 0; i < 4; i++) bits[60 + i] = (data.btn >> i) & 1;
|
||||
bits[64] = 1;
|
||||
|
||||
int crc0 = 0, crc1 = 0;
|
||||
for (uint32_t i = 0; i < 65; i++) {
|
||||
int new_crc1 = crc0 ^ bits[i];
|
||||
int new_crc0 = new_crc1 ^ crc1;
|
||||
crc0 = new_crc0 & 1;
|
||||
crc1 = new_crc1 & 1;
|
||||
}
|
||||
bits[65] = crc0;
|
||||
bits[66] = crc1;
|
||||
|
||||
std::string s{};
|
||||
for (int i = 0; i < 9; i++) s += "100";
|
||||
s += "11111111110000000000";
|
||||
for (int i = 0; i < 67; i++) s += keeloq_fragments[bits[i]];
|
||||
for (int i = 0; i < 18; i++) s += "0";
|
||||
|
||||
encoded_data = s;
|
||||
pause_duration = 0;
|
||||
}
|
||||
|
||||
void KeeloqTXView::encode_data() {
|
||||
std::string fragments{};
|
||||
|
||||
@@ -206,9 +240,11 @@ void KeeloqTXView::start_tx() {
|
||||
|
||||
transmitter_model.enable();
|
||||
|
||||
const double te_us = (data.mf_name == "Superrollo") ? 450.0 : 400.0;
|
||||
|
||||
baseband::set_ook_data(
|
||||
bitstream_length,
|
||||
OOK_SAMPLERATE * (400.0 / 1000000.0),
|
||||
OOK_SAMPLERATE * (te_us / 1000000.0),
|
||||
repeat,
|
||||
pause_duration);
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ class KeeloqTXView : public View {
|
||||
std::string encoded_data{};
|
||||
|
||||
void encode_data();
|
||||
void encode_data_gw60(uint32_t hop_enc);
|
||||
|
||||
uint32_t repeat = 4;
|
||||
uint32_t pause_duration = 0;
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ SdOverUsbView::SdOverUsbView(NavigationView& nav)
|
||||
sdcStop(&SDCD1);
|
||||
|
||||
portapack::shutdown(true, false);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base(), false);
|
||||
m0_halt();
|
||||
/* will not return*/
|
||||
};
|
||||
|
||||
@@ -359,15 +359,6 @@ SystemStatusView::SystemStatusView(
|
||||
this->on_bias_tee();
|
||||
};
|
||||
|
||||
button_fake_brightness.on_select = [this](ImageButton&) {
|
||||
set_dirty();
|
||||
pmem::toggle_fake_brightness_level();
|
||||
refresh();
|
||||
if (nullptr != parent()) {
|
||||
parent()->set_dirty(); // The parent of NavigationView shal be the SystemView
|
||||
}
|
||||
};
|
||||
|
||||
button_camera.on_select = [this](ImageButton&) {
|
||||
this->on_camera();
|
||||
};
|
||||
@@ -460,7 +451,6 @@ void SystemStatusView::refresh() {
|
||||
// Display "Disable speaker" icon only if AK4951 Codec which has separate speaker/headphone control
|
||||
if (audio::speaker_disable_supported() && !pmem::ui_hide_speaker()) status_icons.add(&toggle_speaker);
|
||||
|
||||
if (!pmem::ui_hide_fake_brightness()) status_icons.add(&button_fake_brightness);
|
||||
if (battery::BatteryManagement::isDetected()) {
|
||||
batt_was_inited = true;
|
||||
if (!pmem::ui_hide_battery_icon()) {
|
||||
@@ -493,9 +483,6 @@ void SystemStatusView::refresh() {
|
||||
button_converter.set_bitmap(pmem::config_updown_converter() ? &bitmap_icon_downconvert : &bitmap_icon_upconvert);
|
||||
button_converter.set_foreground(pmem::config_converter() ? Theme::getInstance()->fg_red->foreground : Theme::getInstance()->fg_light->foreground);
|
||||
|
||||
// Fake Brightness
|
||||
button_fake_brightness.set_foreground(pmem::apply_fake_brightness() ? *Theme::getInstance()->status_active : Theme::getInstance()->fg_light->foreground);
|
||||
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
@@ -1143,13 +1130,18 @@ void SystemView::toggle_overlay() {
|
||||
}
|
||||
|
||||
void SystemView::paint_overlay() {
|
||||
static bool last_paint_state = false;
|
||||
// Static variable to store the timestamp of the last update
|
||||
static systime_t last_update_time = 0;
|
||||
|
||||
if (overlay_active) {
|
||||
// paint background only every other second
|
||||
if ((((chTimeNow() >> 10) & 0x01) == 0x01) == last_paint_state)
|
||||
// Update exactly once per second (CH_FREQUENCY equals 1 second of ticks)
|
||||
// This replaces the old hardcoded bit-shift logic for better portability
|
||||
if ((chTimeNow() - last_update_time) < CH_FREQUENCY)
|
||||
return;
|
||||
|
||||
last_paint_state = !last_paint_state;
|
||||
// One second has passed, save the new timestamp
|
||||
last_update_time = chTimeNow();
|
||||
|
||||
if (overlay_active == 1 && overlay)
|
||||
overlay->set_dirty();
|
||||
else if (overlay_active == 2 && overlay2)
|
||||
|
||||
@@ -307,12 +307,6 @@ class SystemStatusView : public View {
|
||||
Theme::getInstance()->fg_light->foreground,
|
||||
Theme::getInstance()->bg_dark->background};
|
||||
|
||||
ImageButton button_fake_brightness{
|
||||
{0, 0, 2 * 8, 1 * 16},
|
||||
&bitmap_icon_brightness,
|
||||
*Theme::getInstance()->status_active,
|
||||
Theme::getInstance()->bg_dark->background};
|
||||
|
||||
SDCardStatusView sd_card_status_view{
|
||||
{0, UI_POS_Y(0), 2 * 8, 1 * 16}};
|
||||
|
||||
|
||||
@@ -1180,7 +1180,7 @@ static void cmd_sysinfo(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
"M4 stack: " + to_string_dec_uint(shared_memory.m4_stack_usage) + "\r\n" +
|
||||
"M0 cpu%: " + to_string_dec_uint(shared_memory.m4_performance_counter) + "\r\n" +
|
||||
"M4 miss: " + to_string_dec_uint(shared_memory.m4_buffer_missed) + "\r\n" +
|
||||
"uptime: " + to_string_dec_uint(chTimeNow() / 1000) + "\r\n";
|
||||
"uptime: " + to_string_dec_uint(chTimeNow() / CH_FREQUENCY) + "\r\n";
|
||||
|
||||
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)info.c_str(), info.length());
|
||||
return;
|
||||
|
||||
@@ -748,13 +748,6 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PRTT rtty_tx)
|
||||
|
||||
### SD over USB
|
||||
|
||||
set(MODE_INCDIR
|
||||
${HACKRF_PATH}/firmware
|
||||
${HACKRF_PATH}/firmware/common
|
||||
${HACKRF_PATH}/firmware/libopencm3/include
|
||||
)
|
||||
|
||||
### Morse TX
|
||||
|
||||
@@ -794,6 +787,15 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PTET tetra_rx)
|
||||
|
||||
### SD over USB
|
||||
|
||||
set(MODE_INCDIR
|
||||
${HACKRF_PATH}/firmware
|
||||
${HACKRF_PATH}/firmware/common
|
||||
${HACKRF_PATH}/firmware/libopencm3/include
|
||||
${HACKRF_PATH}/firmware/hackrf_usb
|
||||
sd_over_usb/
|
||||
)
|
||||
|
||||
set(MODE_CPPSRC
|
||||
sd_over_usb/proc_sd_over_usb.cpp
|
||||
@@ -802,7 +804,9 @@ set(MODE_CPPSRC
|
||||
sd_over_usb/diskio.c
|
||||
sd_over_usb/sd_over_usb.c
|
||||
sd_over_usb/usb_descriptor.c
|
||||
sd_over_usb/hackrf_core.c
|
||||
sd_over_usb/usb_api_transceiver.c
|
||||
sd_over_usb/cpu_clock.c
|
||||
sd_over_usb/pins.c
|
||||
|
||||
${HACKRF_PATH}/firmware/common/adc.c
|
||||
${HACKRF_PATH}/firmware/common/selftest.c
|
||||
@@ -829,6 +833,15 @@ set(MODE_CPPSRC
|
||||
${HACKRF_PATH}/firmware/common/rffc5071_spi.c
|
||||
${HACKRF_PATH}/firmware/common/rffc5071.c
|
||||
${HACKRF_PATH}/firmware/common/gpdma.c
|
||||
${HACKRF_PATH}/firmware/common/clock_gen.c
|
||||
${HACKRF_PATH}/firmware/common/cpld_jtag.c
|
||||
${HACKRF_PATH}/firmware/common/leds.c
|
||||
${HACKRF_PATH}/firmware/common/power.c
|
||||
${HACKRF_PATH}/firmware/common/clock_io.c
|
||||
${HACKRF_PATH}/firmware/common/rom_iap.c
|
||||
${HACKRF_PATH}/firmware/common/w25q80bv.c
|
||||
${HACKRF_PATH}/firmware/common/w25q80bv_target.c
|
||||
|
||||
|
||||
${HACKRF_PATH}/firmware/libopencm3/lib/cm3/nvic.c
|
||||
${HACKRF_PATH}/firmware/libopencm3/lib/cm3/sync.c
|
||||
@@ -836,10 +849,7 @@ set(MODE_CPPSRC
|
||||
${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/timer.c
|
||||
${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/i2c.c
|
||||
)
|
||||
# sd_over_usb has type conflicts with PRALINE (HackRF Pro) - disable for now
|
||||
if(NOT BOARD STREQUAL "PRALINE")
|
||||
DeclareTargets(PUSB sd_over_usb)
|
||||
endif()
|
||||
|
||||
|
||||
### HackRF "factory" firmware
|
||||
|
||||
@@ -125,15 +125,18 @@ void update_performance_counters() {
|
||||
if (performance_counter_active == 0x00)
|
||||
return;
|
||||
|
||||
static bool last_paint_state = false;
|
||||
if ((((chTimeNow() >> 10) & 0x01) == 0x01) == last_paint_state)
|
||||
static systime_t last_update_time = 0;
|
||||
|
||||
// The MS2ST(1000) guarantees that this is exactly 1 second, regardless of the system clock setting.
|
||||
if ((chTimeNow() - last_update_time) < MS2ST(1000))
|
||||
return;
|
||||
|
||||
// Idle thread state is sometimes unuseable
|
||||
if (chThdGetTicks(chSysGetIdleThread()) > 0x10000000)
|
||||
return;
|
||||
|
||||
last_paint_state = !last_paint_state;
|
||||
// Update the last update time
|
||||
last_update_time = chTimeNow();
|
||||
|
||||
if (performance_counter_active == 0x01) {
|
||||
auto utilisation = get_cpu_utilisation_in_percent();
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
|
||||
#ifndef __FPROTO_SUPERROLLO_H__
|
||||
#define __FPROTO_SUPERROLLO_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
// Superrollo GW60 (HCS361) 67-bit OOK decoder. Reports FPS_SUPERROLLO; SubGhzD
|
||||
// treats FPS_SUPERROLLO like KeeLoq for decrypt/display (see ui_subghzd.cpp), so
|
||||
// the "Superrollo" keystore key decrypts it while it stays identifiable in logs.
|
||||
|
||||
typedef enum : uint8_t {
|
||||
SuperrolloStepReset = 0,
|
||||
SuperrolloStepPreambleLow,
|
||||
SuperrolloStepSyncLow,
|
||||
SuperrolloStepSaveDuration,
|
||||
SuperrolloStepCheckDuration,
|
||||
} SuperrolloDecoderStep;
|
||||
|
||||
class FProtoSubGhzDSuperrollo : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDSuperrollo() {
|
||||
sensorType = FPS_SUPERROLLO;
|
||||
te_short = 450;
|
||||
te_long = 900;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 64;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case SuperrolloStepReset:
|
||||
if (level) {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
header_count++;
|
||||
parser_step = SuperrolloStepPreambleLow;
|
||||
} else if (
|
||||
(header_count >= 4) &&
|
||||
(DURATION_DIFF(duration, te_short * 10) < te_delta * 10)) {
|
||||
parser_step = SuperrolloStepSyncLow;
|
||||
} else {
|
||||
header_count = 0;
|
||||
}
|
||||
} else {
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepPreambleLow:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
parser_step = SuperrolloStepReset;
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepSyncLow:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 10)) {
|
||||
parser_step = SuperrolloStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = SuperrolloStepCheckDuration;
|
||||
} else if (duration >= te_short * 12) {
|
||||
endFrame();
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
if (decode_count_bit < min_count_bit_for_found)
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
else
|
||||
decode_count_bit++;
|
||||
parser_step = SuperrolloStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
if (decode_count_bit < min_count_bit_for_found)
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
else
|
||||
decode_count_bit++;
|
||||
parser_step = SuperrolloStepSaveDuration;
|
||||
} else if (duration >= te_short * 12) {
|
||||
endFrame();
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t header_count = 0;
|
||||
|
||||
private:
|
||||
void endFrame() {
|
||||
if ((decode_count_bit >= min_count_bit_for_found) &&
|
||||
(decode_count_bit <= min_count_bit_for_found + 3)) {
|
||||
data_count_bit = min_count_bit_for_found;
|
||||
if (callback) callback(this);
|
||||
}
|
||||
parser_step = SuperrolloStepReset;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
header_count = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -29,6 +29,7 @@ So include here the .hpp, and add a new element to the protos vector in the cons
|
||||
#include "s-ido.hpp"
|
||||
#include "s-intertechnov3.hpp"
|
||||
#include "s-keeloq.hpp"
|
||||
#include "s-superrollo.hpp"
|
||||
#include "s-kinggates_stylo_4k.hpp"
|
||||
#include "s-linear.hpp"
|
||||
#include "s-linear_delta3.hpp"
|
||||
@@ -85,6 +86,7 @@ class SubGhzDProtos : public FProtoListGeneral {
|
||||
protos[FPS_IDO] = new FProtoSubGhzDIdo();
|
||||
protos[FPS_INTERTECHNOV3] = new FProtoSubGhzDIntertechnoV3();
|
||||
protos[FPS_KEELOQ] = new FProtoSubGhzDKeeLoq();
|
||||
protos[FPS_SUPERROLLO] = new FProtoSubGhzDSuperrollo();
|
||||
protos[FPS_KINGGATESSTYLO4K] = new FProtoSubGhzDKinggatesStylo4K();
|
||||
protos[FPS_LINEAR] = new FProtoSubGhzDLinear();
|
||||
protos[FPS_LINEARDELTA3] = new FProtoSubGhzDLinearDelta3();
|
||||
|
||||
@@ -60,6 +60,7 @@ enum FPROTO_SUBGHZD_SENSOR : uint8_t {
|
||||
FPS_MARANTEC24,
|
||||
FPS_HOLTEKHT6P20B,
|
||||
FPS_RESTAURANT_PAGER,
|
||||
FPS_SUPERROLLO,
|
||||
FPS_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "cpu_clock.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/cgu.h>
|
||||
#if defined(IS_JAWBREAKER) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE)
|
||||
#include <libopencm3/lpc43xx/ccu.h>
|
||||
#endif
|
||||
|
||||
#include "delay.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "i2c_lpc.h"
|
||||
#include "si5351c.h"
|
||||
|
||||
/* We start with the CPU clock at 96MHz */
|
||||
unsigned int cpu_clock_mhz = 96;
|
||||
|
||||
/*
|
||||
Configure PLL1 (Main MCU Clock) to max speed (204MHz).
|
||||
Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1.
|
||||
This function shall be called after cpu_clock_init().
|
||||
*/
|
||||
static void cpu_clock_pll1_max_speed(void) {
|
||||
uint32_t reg_val;
|
||||
|
||||
/* This function implements the sequence recommended in:
|
||||
* UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */
|
||||
|
||||
/* 1. Select the IRC as BASE_M4_CLK source. */
|
||||
reg_val = CGU_BASE_M4_CLK;
|
||||
reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK;
|
||||
reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) | CGU_BASE_M4_CLK_AUTOBLOCK(1);
|
||||
CGU_BASE_M4_CLK = reg_val;
|
||||
|
||||
/* CPU is now at 12MHz */
|
||||
cpu_clock_mhz = 12;
|
||||
|
||||
/* 2. Enable the crystal oscillator. */
|
||||
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK;
|
||||
|
||||
/* 3. Wait 250us. */
|
||||
delay_us(250);
|
||||
|
||||
/* 4. Set the AUTOBLOCK bit. */
|
||||
CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1);
|
||||
|
||||
/* 5. Reconfigure PLL1 to produce the final output frequency, with the
|
||||
* crystal oscillator as clock source. */
|
||||
reg_val = CGU_PLL1_CTRL;
|
||||
// clang-format off
|
||||
reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK |
|
||||
CGU_PLL1_CTRL_PD_MASK |
|
||||
CGU_PLL1_CTRL_FBSEL_MASK |
|
||||
CGU_PLL1_CTRL_BYPASS_MASK |
|
||||
CGU_PLL1_CTRL_DIRECT_MASK |
|
||||
CGU_PLL1_CTRL_PSEL_MASK |
|
||||
CGU_PLL1_CTRL_MSEL_MASK |
|
||||
CGU_PLL1_CTRL_NSEL_MASK );
|
||||
/* Set PLL1 up to 12MHz * 17 = 204MHz.
|
||||
* Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */
|
||||
reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) |
|
||||
CGU_PLL1_CTRL_PSEL(0) |
|
||||
CGU_PLL1_CTRL_NSEL(0) |
|
||||
CGU_PLL1_CTRL_MSEL(16) |
|
||||
CGU_PLL1_CTRL_FBSEL(0) |
|
||||
CGU_PLL1_CTRL_DIRECT(1);
|
||||
// clang-format on
|
||||
CGU_PLL1_CTRL = reg_val;
|
||||
|
||||
/* 6. Wait for PLL1 to lock. */
|
||||
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK)) {
|
||||
}
|
||||
|
||||
/* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */
|
||||
CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK;
|
||||
|
||||
/* 8. Select PLL1 as BASE_M4_CLK source. */
|
||||
reg_val = CGU_BASE_M4_CLK;
|
||||
reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK;
|
||||
reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
CGU_BASE_M4_CLK = reg_val;
|
||||
|
||||
/* CPU is now at 102MHz */
|
||||
cpu_clock_mhz = 102;
|
||||
|
||||
/* 9. Wait 50us. */
|
||||
delay_us(50);
|
||||
|
||||
/* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */
|
||||
CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK;
|
||||
|
||||
/* CPU is now at 204MHz */
|
||||
cpu_clock_mhz = 204;
|
||||
}
|
||||
|
||||
/* clock startup for LPC4320 configure PLL1 to max speed (204MHz).
|
||||
Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */
|
||||
void cpu_clock_init(void) {
|
||||
/* use IRC as clock source for APB1 (including I2C0) */
|
||||
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC);
|
||||
|
||||
/* use IRC as clock source for APB3 */
|
||||
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC);
|
||||
|
||||
// FIXME disable I2C
|
||||
/* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */
|
||||
i2c_bus_start(si5351c.bus, &i2c_config_fast_clock);
|
||||
|
||||
/*
|
||||
* 12MHz clock is entering LPC XTAL1/OSC input now.
|
||||
* On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC.
|
||||
* Set up PLL1 to run from XTAL1 input.
|
||||
*/
|
||||
|
||||
// FIXME a lot of the details here should be in a CGU driver
|
||||
|
||||
/* set xtal oscillator to low frequency mode */
|
||||
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK;
|
||||
|
||||
cpu_clock_pll1_max_speed();
|
||||
|
||||
/* use XTAL_OSC as clock source for APB1 */
|
||||
CGU_BASE_APB1_CLK =
|
||||
CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL);
|
||||
|
||||
/* use XTAL_OSC as clock source for APB3 */
|
||||
CGU_BASE_APB3_CLK =
|
||||
CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL);
|
||||
|
||||
/* use XTAL_OSC as clock source for PLL0USB */
|
||||
CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_AUTOBLOCK(1) |
|
||||
CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL);
|
||||
while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK) {
|
||||
}
|
||||
|
||||
/* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */
|
||||
/* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */
|
||||
CGU_PLL0USB_MDIV = 0x06167FFA;
|
||||
CGU_PLL0USB_NP_DIV = 0x00302062;
|
||||
CGU_PLL0USB_CTRL |=
|
||||
(CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_DIRECTI(1) |
|
||||
CGU_PLL0USB_CTRL_DIRECTO(1) | CGU_PLL0USB_CTRL_CLKEN(1));
|
||||
|
||||
/* power on PLL0USB and wait until stable */
|
||||
CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK;
|
||||
while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK)) {
|
||||
}
|
||||
|
||||
/* use PLL0USB as clock source for USB0 */
|
||||
CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1) |
|
||||
CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB);
|
||||
|
||||
/* Switch peripheral clock over to use PLL1 (204MHz) */
|
||||
CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1) |
|
||||
CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
/* Switch APB1 clock over to use PLL1 (204MHz) */
|
||||
CGU_BASE_APB1_CLK =
|
||||
CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
/* Switch APB3 clock over to use PLL1 (204MHz) */
|
||||
CGU_BASE_APB3_CLK =
|
||||
CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
CGU_BASE_SSP0_CLK =
|
||||
CGU_BASE_SSP0_CLK_AUTOBLOCK(1) | CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
CGU_BASE_SSP1_CLK =
|
||||
CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
/* Disable unused clocks */
|
||||
/* Start with PLLs */
|
||||
CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1);
|
||||
|
||||
/* Dividers */
|
||||
CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1);
|
||||
CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1);
|
||||
CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1);
|
||||
CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1);
|
||||
CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1);
|
||||
|
||||
/* Base clocks */
|
||||
CGU_BASE_SPIFI_CLK =
|
||||
CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */
|
||||
CGU_BASE_USB1_CLK =
|
||||
CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */
|
||||
CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1);
|
||||
CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1);
|
||||
CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1);
|
||||
CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1);
|
||||
CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(0) | CGU_BASE_SDIO_CLK_AUTOBLOCK(1) | CGU_BASE_SDIO_CLK_CLK_SEL(0x09);
|
||||
CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1);
|
||||
CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1);
|
||||
CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1);
|
||||
CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1);
|
||||
CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1);
|
||||
CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1);
|
||||
CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1);
|
||||
CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1);
|
||||
|
||||
/* Disable unused peripheral clocks */
|
||||
CCU1_CLK_APB1_CAN1_CFG = 0;
|
||||
CCU1_CLK_APB1_I2S_CFG = 0;
|
||||
CCU1_CLK_APB1_MOTOCONPWM_CFG = 0;
|
||||
// CCU1_CLK_APB3_ADC0_CFG = 0;
|
||||
CCU1_CLK_APB3_ADC1_CFG = 0;
|
||||
CCU1_CLK_APB3_CAN0_CFG = 0;
|
||||
CCU1_CLK_APB3_DAC_CFG = 0;
|
||||
// CCU1_CLK_M4_DMA_CFG = 0;
|
||||
CCU1_CLK_M4_EMC_CFG = 0;
|
||||
CCU1_CLK_M4_EMCDIV_CFG = 0;
|
||||
CCU1_CLK_M4_ETHERNET_CFG = 0;
|
||||
CCU1_CLK_M4_LCD_CFG = 0;
|
||||
CCU1_CLK_M4_QEI_CFG = 0;
|
||||
CCU1_CLK_M4_RITIMER_CFG = 0;
|
||||
// CCU1_CLK_M4_SCT_CFG = 0;
|
||||
// CCU1_CLK_M4_SDIO_CFG = 1;
|
||||
CCU1_CLK_M4_SPIFI_CFG = 0;
|
||||
CCU1_CLK_M4_TIMER0_CFG = 0;
|
||||
// CCU1_CLK_M4_TIMER1_CFG = 0;
|
||||
// CCU1_CLK_M4_TIMER2_CFG = 0;
|
||||
CCU1_CLK_M4_TIMER3_CFG = 0;
|
||||
CCU1_CLK_M4_UART1_CFG = 0;
|
||||
CCU1_CLK_M4_USART0_CFG = 0;
|
||||
CCU1_CLK_M4_USART2_CFG = 0;
|
||||
CCU1_CLK_M4_USART3_CFG = 0;
|
||||
CCU1_CLK_M4_USB1_CFG = 0;
|
||||
CCU1_CLK_M4_VADC_CFG = 0;
|
||||
// CCU1_CLK_SPIFI_CFG = 0;
|
||||
// CCU1_CLK_USB1_CFG = 0;
|
||||
// CCU1_CLK_VADC_CFG = 0;
|
||||
// CCU2_CLK_APB0_UART1_CFG = 0;
|
||||
// CCU2_CLK_APB0_USART0_CFG = 0;
|
||||
// CCU2_CLK_APB2_USART2_CFG = 0;
|
||||
// CCU2_CLK_APB2_USART3_CFG = 0;
|
||||
// CCU2_CLK_APLL_CFG = 0;
|
||||
// CCU2_CLK_SDIO_CFG = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#pragma once
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along 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 "pins.h"
|
||||
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
|
||||
#include "gpio.h"
|
||||
#include "leds.h"
|
||||
#include "platform_detect.h"
|
||||
#include "platform_gpio.h"
|
||||
#include "platform_scu.h"
|
||||
#include "power.h"
|
||||
#ifdef IS_PRALINE
|
||||
#include "clock_io.h"
|
||||
#endif
|
||||
|
||||
void pins_shutdown(void) {
|
||||
/* Configure all GPIO as Input (safe state) */
|
||||
// gpio_init();
|
||||
|
||||
/* Detect Platform */
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
const platform_scu_t* scu = platform_scu();
|
||||
|
||||
/* TDI and TMS pull-ups are required in all JTAG-compliant devices.
|
||||
*
|
||||
* The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS.
|
||||
*
|
||||
* The PortaPack may not be present, so pull up the PortaPack TMS pin from the
|
||||
* microcontroller.
|
||||
*
|
||||
* TCK is recommended to be held low, so use microcontroller pull-down.
|
||||
*
|
||||
* TDO is undriven except when in Shift-IR or Shift-DR phases.
|
||||
* Use the microcontroller to pull down to keep from floating.
|
||||
*
|
||||
* LPC43xx pull-up and pull-down resistors are approximately 53K.
|
||||
*/
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
scu_pinmux(scu->PINMUX_PP_TMS, SCU_GPIO_PUP | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->PINMUX_PP_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
}
|
||||
#endif
|
||||
scu_pinmux(scu->PINMUX_CPLD_TCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
scu_pinmux(scu->PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->PINMUX_CPLD_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure SCU Pin Mux as GPIO */
|
||||
scu_pinmux(scu->PINMUX_LED1, SCU_GPIO_NOPULL);
|
||||
scu_pinmux(scu->PINMUX_LED2, SCU_GPIO_NOPULL);
|
||||
scu_pinmux(scu->PINMUX_LED3, SCU_GPIO_NOPULL);
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
scu_pinmux(scu->PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
scu_pinmux(scu->PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure USB indicators */
|
||||
#ifdef IS_JAWBREAKER
|
||||
if (IS_JAWBREAKER) {
|
||||
scu_pinmux(scu->PINMUX_USB_LED0, SCU_CONF_FUNCTION3);
|
||||
scu_pinmux(scu->PINMUX_USB_LED1, SCU_CONF_FUNCTION3);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
// disable_1v2_power();
|
||||
// disable_3v3aux_power();
|
||||
// gpio_output(gpio->gpio_1v2_enable);
|
||||
// gpio_output(gpio->gpio_3v3aux_enable_n);
|
||||
// scu_pinmux(scu->PINMUX_EN1V2, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
// scu_pinmux(scu->PINMUX_EN3V3_AUX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
disable_1v8_power();
|
||||
#ifdef IS_H1_R9
|
||||
if (IS_H1_R9) {
|
||||
gpio_output(gpio->h1r9_1v8_enable);
|
||||
scu_pinmux(scu->H1R9_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_H1_R9
|
||||
if (IS_NOT_H1_R9) {
|
||||
gpio_output(gpio->gpio_1v8_enable);
|
||||
scu_pinmux(scu->PINMUX_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_H1_OR_PRALINE
|
||||
if (IS_H1_OR_PRALINE) {
|
||||
/* Safe state: start with VAA turned off: */
|
||||
disable_rf_power();
|
||||
|
||||
/* Configure RF power supply (VAA) switch control signal as output */
|
||||
#ifdef IS_H1_R9
|
||||
if (IS_H1_R9) {
|
||||
gpio_output(gpio->h1r9_vaa_disable);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_H1_R9
|
||||
if (IS_NOT_H1_R9) {
|
||||
gpio_output(gpio->vaa_disable);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
/* Safe state: start with VAA turned off: */
|
||||
disable_rf_power();
|
||||
|
||||
/* Configure RF power supply (VAA) switch control signal as output */
|
||||
gpio_output(gpio->vaa_enable);
|
||||
|
||||
/* Disable unused clock outputs. They generate noise. */
|
||||
scu_pinmux(CLK0, SCU_CLK_IN | SCU_CONF_FUNCTION7);
|
||||
scu_pinmux(CLK2, SCU_CLK_IN | SCU_CONF_FUNCTION7);
|
||||
|
||||
scu_pinmux(scu->PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
scu_pinmux(scu->P2_CTRL0, scu->P2_CTRL0_PINCFG);
|
||||
scu_pinmux(scu->P2_CTRL1, scu->P2_CTRL1_PINCFG);
|
||||
scu_pinmux(scu->P1_CTRL0, scu->P1_CTRL0_PINCFG);
|
||||
scu_pinmux(scu->P1_CTRL1, scu->P1_CTRL1_PINCFG);
|
||||
scu_pinmux(scu->P1_CTRL2, scu->P1_CTRL2_PINCFG);
|
||||
scu_pinmux(scu->CLKIN_CTRL, scu->CLKIN_CTRL_PINCFG);
|
||||
scu_pinmux(scu->AA_EN, scu->AA_EN_PINCFG);
|
||||
scu_pinmux(scu->TRIGGER_IN, scu->TRIGGER_IN_PINCFG);
|
||||
scu_pinmux(scu->TRIGGER_OUT, scu->TRIGGER_OUT_PINCFG);
|
||||
scu_pinmux(scu->PPS_OUT, scu->PPS_OUT_PINCFG);
|
||||
scu_pinmux(scu->SCT_CLK, scu->SCT_CLK_PINCFG);
|
||||
|
||||
scu_pinmux(scu->PINMUX_FPGA_CRESET, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->PINMUX_FPGA_CDONE, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
scu_pinmux(scu->PINMUX_FPGA_SPI_CS, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
|
||||
scu_pinmux(scu->SSP1_CIPO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->SSP1_COPI, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->SSP1_SCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION2);
|
||||
|
||||
scu_pinmux(scu->XCVR_ENABLE, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
scu_pinmux(scu->XCVR_RXENABLE, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
scu_pinmux(scu->XCVR_CS, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
scu_pinmux(scu->XCVR_RXHP, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
scu_pinmux(scu->XCVR_LD, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
|
||||
scu_pinmux(scu->MIXER_LD, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
scu_pinmux(scu->MIXER_SCLK, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
scu_pinmux(scu->MIXER_SDATA, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->MIXER_ENX, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->MIXER_RESETX, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(scu->MIXER_ENBL, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
|
||||
scu_pinmux(scu->AD_CS, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
|
||||
|
||||
p2_ctrl_set(P2_SIGNAL_CLK3);
|
||||
p1_ctrl_set(P1_SIGNAL_CLKIN);
|
||||
clkin_ctrl_set(CLKIN_SIGNAL_P1);
|
||||
|
||||
gpio_output(gpio->p2_ctrl0);
|
||||
gpio_output(gpio->p2_ctrl1);
|
||||
gpio_output(gpio->p1_ctrl0);
|
||||
gpio_output(gpio->p1_ctrl1);
|
||||
gpio_output(gpio->p1_ctrl2);
|
||||
gpio_output(gpio->clkin_ctrl);
|
||||
gpio_output(gpio->pps_out);
|
||||
gpio_input(gpio->trigger_in);
|
||||
gpio_input(gpio->trigger_out);
|
||||
gpio_clear(gpio->fpga_cfg_spi_cs);
|
||||
gpio_output(gpio->fpga_cfg_spi_cs);
|
||||
gpio_clear(gpio->fpga_cfg_creset);
|
||||
gpio_output(gpio->fpga_cfg_creset);
|
||||
gpio_input(gpio->fpga_cfg_cdone);
|
||||
gpio_input(gpio->max5864_select);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* enable input on SCL and SDA pins */
|
||||
SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
|
||||
}
|
||||
|
||||
/* Run after pins_shutdown() and prior to enabling power supplies. */
|
||||
void pins_setup(void) {
|
||||
/* Detect Platform */
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
const platform_scu_t* scu = platform_scu();
|
||||
|
||||
/* Configure LEDs */
|
||||
led_off(0);
|
||||
led_off(1);
|
||||
led_off(2);
|
||||
#ifdef IS_FOUR_LEDS
|
||||
if (IS_FOUR_LEDS) {
|
||||
led_off(3);
|
||||
}
|
||||
#endif
|
||||
|
||||
gpio_output(gpio->led[0]);
|
||||
gpio_output(gpio->led[1]);
|
||||
gpio_output(gpio->led[2]);
|
||||
|
||||
#ifdef IS_FOUR_LEDS
|
||||
if (IS_FOUR_LEDS) {
|
||||
gpio_output(gpio->led[3]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure external clock in */
|
||||
scu_pinmux(scu->PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1);
|
||||
}
|
||||
@@ -44,11 +44,11 @@ CH_IRQ_HANDLER(Vector60) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
start_usb();
|
||||
|
||||
sdcStart(&SDCD1, nullptr);
|
||||
if (sdcConnect(&SDCD1) == CH_FAILED) chDbgPanic("no sd card #1");
|
||||
|
||||
start_usb();
|
||||
|
||||
while (true) {
|
||||
usb_transfer();
|
||||
}
|
||||
|
||||
@@ -23,14 +23,35 @@
|
||||
#include "scsi.h"
|
||||
#include "diskio.h"
|
||||
#include "gpio_lpc.h"
|
||||
#include "delay.h"
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
#include <libopencm3/lpc43xx/rgu.h>
|
||||
#include <libopencm3/lpc43xx/wwdt.h>
|
||||
#include "string.h"
|
||||
|
||||
/* Maximum number of 512-byte blocks transferred per SD command / USB bulk
|
||||
* transfer. The data region of usb_bulk_buffer is 16 KiB (0x0000..0x3FFF),
|
||||
* so this must be <= 32. It is split into two equal halves for double
|
||||
* buffering. */
|
||||
#define MAX_BLOCKS_PER_TRANSFER 32
|
||||
#define HALF_BLOCKS (MAX_BLOCKS_PER_TRANSFER / 2)
|
||||
|
||||
volatile bool usb_bulk_block_done = false;
|
||||
|
||||
void delay(uint32_t duration);
|
||||
/* Per-buffer-half completion flags for the asynchronous (double-buffered)
|
||||
* bulk transfers. Index 0 = usb_bulk_buffer[0], index 1 = second half. */
|
||||
volatile bool usb_bulk_block_done_async[2] = {false, false};
|
||||
|
||||
static uint32_t usb_bulk_buffer_index(const void* const data) {
|
||||
return (data == &usb_bulk_buffer[HALF_BLOCKS * 512]) ? 1 : 0;
|
||||
}
|
||||
|
||||
void usb_bulk_block_cb_async(void* user_data, unsigned int bytes_transferred) {
|
||||
const uint32_t idx = (uint32_t)(uintptr_t)user_data;
|
||||
usb_bulk_block_done_async[idx] = true;
|
||||
|
||||
(void)bytes_transferred;
|
||||
}
|
||||
|
||||
void usb_bulk_block_cb(void* user_data, unsigned int bytes_transferred) {
|
||||
usb_bulk_block_done = true;
|
||||
@@ -65,6 +86,49 @@ void usb_receive_bulk(void* const data, const uint32_t maximum_length) {
|
||||
while (!usb_bulk_block_done);
|
||||
}
|
||||
|
||||
/* Schedule a bulk IN transfer without waiting for it to complete. The caller
|
||||
* must later call usb_send_bulk_wait_finish() with the same buffer before
|
||||
* reusing it. */
|
||||
void usb_send_bulk_start(void* const data, const uint32_t maximum_length) {
|
||||
const uint32_t idx = usb_bulk_buffer_index(data);
|
||||
usb_bulk_block_done_async[idx] = false;
|
||||
|
||||
usb_transfer_schedule_block(
|
||||
&usb_endpoint_bulk_in,
|
||||
data,
|
||||
maximum_length,
|
||||
usb_bulk_block_cb_async,
|
||||
(void*)(uintptr_t)idx);
|
||||
}
|
||||
|
||||
/* Wait for a bulk IN transfer scheduled by usb_send_bulk_start() to finish. */
|
||||
void usb_send_bulk_wait_finish(void* const data) {
|
||||
const uint32_t idx = usb_bulk_buffer_index(data);
|
||||
while (!usb_bulk_block_done_async[idx]);
|
||||
}
|
||||
|
||||
/* Schedule a bulk OUT transfer without waiting for it to complete. The caller
|
||||
* must later call usb_receive_bulk_finish() with the same buffer before
|
||||
* reading from it. */
|
||||
void usb_receive_bulk_start(void* const data, const uint32_t maximum_length) {
|
||||
const uint32_t idx = usb_bulk_buffer_index(data);
|
||||
usb_bulk_block_done_async[idx] = false;
|
||||
|
||||
usb_transfer_schedule_block(
|
||||
&usb_endpoint_bulk_out,
|
||||
data,
|
||||
maximum_length,
|
||||
usb_bulk_block_cb_async,
|
||||
(void*)(uintptr_t)idx);
|
||||
}
|
||||
|
||||
/* Wait for a bulk OUT transfer scheduled by usb_receive_bulk_start() to
|
||||
* finish. */
|
||||
void usb_receive_bulk_finish(void* const data) {
|
||||
const uint32_t idx = usb_bulk_buffer_index(data);
|
||||
while (!usb_bulk_block_done_async[idx]);
|
||||
}
|
||||
|
||||
void usb_send_csw(msd_cbw_t* msd_cbw_data, uint8_t status) {
|
||||
msd_csw_t csw = {
|
||||
.signature = MSD_CSW_SIGNATURE,
|
||||
@@ -213,22 +277,95 @@ static data_request_t decode_data_request(const uint8_t* cmd) {
|
||||
uint8_t data_read10(msd_cbw_t* msd_cbw_data) {
|
||||
data_request_t req = decode_data_request(msd_cbw_data->cmd_data);
|
||||
|
||||
for (size_t block_index = 0; block_index < req.blk_cnt; block_index++) {
|
||||
read_block(req.first_lba + block_index, &usb_bulk_buffer[0], 1 /* n blocks */);
|
||||
usb_send_bulk(&usb_bulk_buffer[0], 512);
|
||||
uint32_t lba = req.first_lba;
|
||||
uint32_t remaining = req.blk_cnt;
|
||||
uint8_t* buf[2] = {&usb_bulk_buffer[0], &usb_bulk_buffer[HALF_BLOCKS * 512]};
|
||||
uint32_t buf_idx = 0;
|
||||
uint8_t* in_flight = NULL;
|
||||
|
||||
if (remaining == 0)
|
||||
return 0;
|
||||
|
||||
/* Read the first chunk and start sending it. */
|
||||
uint32_t n = (remaining > HALF_BLOCKS) ? HALF_BLOCKS : remaining;
|
||||
if (read_block(lba, buf[0], n))
|
||||
return 1;
|
||||
usb_send_bulk_start(buf[0], n * 512);
|
||||
in_flight = buf[0];
|
||||
lba += n;
|
||||
remaining -= n;
|
||||
|
||||
/* While USB sends the previous chunk, read the next one into the other
|
||||
* half of the buffer. */
|
||||
while (remaining > 0) {
|
||||
buf_idx ^= 1;
|
||||
n = (remaining > HALF_BLOCKS) ? HALF_BLOCKS : remaining;
|
||||
|
||||
if (read_block(lba, buf[buf_idx], n)) {
|
||||
usb_send_bulk_wait_finish(in_flight);
|
||||
return 1;
|
||||
}
|
||||
|
||||
usb_send_bulk_wait_finish(in_flight);
|
||||
usb_send_bulk_start(buf[buf_idx], n * 512);
|
||||
in_flight = buf[buf_idx];
|
||||
|
||||
lba += n;
|
||||
remaining -= n;
|
||||
}
|
||||
|
||||
usb_send_bulk_wait_finish(in_flight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t data_write10(msd_cbw_t* msd_cbw_data) {
|
||||
data_request_t req = decode_data_request(msd_cbw_data->cmd_data);
|
||||
|
||||
for (size_t block_index = 0; block_index < req.blk_cnt; block_index++) {
|
||||
usb_receive_bulk(&usb_bulk_buffer[0], 512);
|
||||
write_block(req.first_lba + block_index, &usb_bulk_buffer[0], 1 /* n blocks */);
|
||||
uint32_t lba = req.first_lba;
|
||||
uint32_t remaining = req.blk_cnt;
|
||||
uint8_t* buf[2] = {&usb_bulk_buffer[0], &usb_bulk_buffer[HALF_BLOCKS * 512]};
|
||||
uint32_t buf_idx = 0;
|
||||
uint8_t* pending_buf = NULL;
|
||||
uint32_t pending_lba = 0;
|
||||
uint32_t pending_n = 0;
|
||||
|
||||
if (remaining == 0)
|
||||
return 0;
|
||||
|
||||
/* Start receiving the first chunk. */
|
||||
uint32_t n = (remaining > HALF_BLOCKS) ? HALF_BLOCKS : remaining;
|
||||
usb_receive_bulk_start(buf[0], n * 512);
|
||||
pending_buf = buf[0];
|
||||
pending_lba = lba;
|
||||
pending_n = n;
|
||||
lba += n;
|
||||
remaining -= n;
|
||||
|
||||
/* While USB receives the next chunk, write the previous one to the SD
|
||||
* card. */
|
||||
while (remaining > 0) {
|
||||
buf_idx ^= 1;
|
||||
n = (remaining > HALF_BLOCKS) ? HALF_BLOCKS : remaining;
|
||||
|
||||
usb_receive_bulk_start(buf[buf_idx], n * 512);
|
||||
|
||||
usb_receive_bulk_finish(pending_buf);
|
||||
if (write_block(pending_lba, pending_buf, pending_n)) {
|
||||
usb_receive_bulk_finish(buf[buf_idx]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pending_buf = buf[buf_idx];
|
||||
pending_lba = lba;
|
||||
pending_n = n;
|
||||
lba += n;
|
||||
remaining -= n;
|
||||
}
|
||||
|
||||
usb_receive_bulk_finish(pending_buf);
|
||||
if (write_block(pending_lba, pending_buf, pending_n))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -293,7 +430,7 @@ void scsi_command(msd_cbw_t* msd_cbw_data) {
|
||||
gpio_output(&dfu);
|
||||
gpio_clear(&dfu);
|
||||
|
||||
delay(50 * 40800);
|
||||
delay_ms(50);
|
||||
|
||||
RESET_CTRL0 = (1 << 0);
|
||||
break;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "sd_over_usb.h"
|
||||
#include "scsi.h"
|
||||
#include "usb_descriptor.h"
|
||||
#include <rom_iap.h>
|
||||
#include "delay.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -36,8 +38,14 @@
|
||||
extern usb_configuration_t* usb_configurations[];
|
||||
|
||||
static const usb_device_t usb_device_sd_over_usb = {
|
||||
.descriptor = usb_descriptor_device,
|
||||
.descriptor_strings = usb_descriptor_strings,
|
||||
#ifdef IS_NOT_PRALINE
|
||||
.descriptor = usb_descriptor_device_hackrf,
|
||||
.descriptor_strings = usb_descriptor_strings_hackrf_one,
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
.descriptor = usb_descriptor_device_hackrf,
|
||||
.descriptor_strings = usb_descriptor_strings_praline,
|
||||
#endif
|
||||
.qualifier_descriptor = usb_descriptor_device_qualifier,
|
||||
.configurations = &usb_configurations,
|
||||
.configuration = 0,
|
||||
@@ -91,16 +99,83 @@ void usb_configuration_changed(usb_device_t* const device) {
|
||||
usb_endpoint_init(&usb_endpoint_bulk_out, false);
|
||||
}
|
||||
|
||||
void usb_set_descriptor_by_serial_number(void) {
|
||||
iap_cmd_res_t iap_cmd_res;
|
||||
|
||||
/* Read IAP Serial Number Identification */
|
||||
iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_SERIAL_NO;
|
||||
iap_cmd_call(&iap_cmd_res);
|
||||
|
||||
if (iap_cmd_res.status_res.status_ret == CMD_SUCCESS) {
|
||||
usb_descriptor_string_serial_number[0] =
|
||||
USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN;
|
||||
usb_descriptor_string_serial_number[1] = USB_DESCRIPTOR_TYPE_STRING;
|
||||
|
||||
/* 32 characters of serial number, convert to UTF-16LE */
|
||||
for (size_t i = 0; i < USB_DESCRIPTOR_STRING_SERIAL_LEN; i++) {
|
||||
const uint_fast8_t nibble =
|
||||
(iap_cmd_res.status_res.iap_result[i >> 3] >>
|
||||
(28 - (i & 7) * 4)) &
|
||||
0xf;
|
||||
const char c =
|
||||
(nibble > 9) ? ('a' + nibble - 10) : ('0' + nibble);
|
||||
usb_descriptor_string_serial_number[2 + i * 2] = c;
|
||||
usb_descriptor_string_serial_number[3 + i * 2] = 0x00;
|
||||
}
|
||||
} else {
|
||||
usb_descriptor_string_serial_number[0] = 2;
|
||||
usb_descriptor_string_serial_number[1] = USB_DESCRIPTOR_TYPE_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
void start_usb(void) {
|
||||
// Detect hardware platform before we do anything else.
|
||||
detect_hardware_platform();
|
||||
pin_setup();
|
||||
board_id_t board_id = detected_platform();
|
||||
|
||||
pins_shutdown();
|
||||
sgpio_pin_shutdown(&sgpio_config);
|
||||
rf_path_pin_shutdown();
|
||||
if (board_id != BOARD_ID_RAD1O) {
|
||||
clock_gen_shutdown();
|
||||
}
|
||||
delay_ms(10);
|
||||
pins_setup();
|
||||
cpld_jtag_pin_setup();
|
||||
|
||||
cpu_clock_init();
|
||||
|
||||
memcpy(&usb_device, &usb_device_sd_over_usb, sizeof(usb_device_sd_over_usb));
|
||||
#ifndef DFU_MODE
|
||||
usb_set_descriptor_by_serial_number();
|
||||
#endif
|
||||
|
||||
usb_set_configuration_changed_cb(usb_configuration_changed);
|
||||
usb_peripheral_reset();
|
||||
|
||||
#ifdef IS_HACKRF_ONE
|
||||
if (IS_HACKRF_ONE) {
|
||||
memcpy(&usb_device,
|
||||
&usb_device_sd_over_usb,
|
||||
sizeof(usb_device_sd_over_usb));
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_JAWBREAKER
|
||||
if (IS_JAWBREAKER) {
|
||||
memcpy(&usb_device,
|
||||
&usb_device_jawbreaker,
|
||||
sizeof(usb_device_jawbreaker));
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
memcpy(&usb_device, &usb_device_rad1o, sizeof(usb_device_rad1o));
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
memcpy(&usb_device, &usb_device_sd_over_usb, sizeof(usb_device_sd_over_usb));
|
||||
}
|
||||
#endif
|
||||
usb_device_init(0, &usb_device);
|
||||
|
||||
usb_queue_init(&usb_endpoint_control_out_queue);
|
||||
@@ -109,9 +184,6 @@ void start_usb(void) {
|
||||
usb_queue_init(&usb_endpoint_bulk_in_queue);
|
||||
|
||||
usb_endpoint_init(&usb_endpoint_control_out, false);
|
||||
/* Match the new usb_endpoint_init() contract introduced upstream by
|
||||
* db73ecbf, control IN needs ZLP for transfers whose length is a
|
||||
* multiple of the EP0 max packet size, otherwise the host hangs. */
|
||||
usb_endpoint_init(&usb_endpoint_control_in, true);
|
||||
|
||||
nvic_set_priority(NVIC_USB0_IRQ, 255);
|
||||
|
||||
@@ -0,0 +1,766 @@
|
||||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Jared Boone
|
||||
* Copyright 2013 Benjamin Vernoux
|
||||
* Copyright 2024 Bernd Herzog
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along 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 "usb_api_transceiver.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencm3/lpc43xx/gpdma.h>
|
||||
#include <libopencm3/lpc43xx/usb.h>
|
||||
|
||||
#include <clock_gen.h>
|
||||
#include <fixed_point.h>
|
||||
#include <gpdma.h>
|
||||
#include <hackrf_ui.h>
|
||||
#include <leds.h>
|
||||
#include <m0_state.h>
|
||||
#include <operacake_sctimer.h>
|
||||
#include <platform_detect.h>
|
||||
#include <radio.h>
|
||||
#include <sgpio.h>
|
||||
#include <streaming.h>
|
||||
#include <transceiver_mode.h>
|
||||
#include "common/usb.h"
|
||||
#include <usb_queue.h>
|
||||
#include <usb_request.h>
|
||||
#include <usb_type.h>
|
||||
|
||||
#include "usb_buffer.h"
|
||||
#include "usb_endpoint.h"
|
||||
|
||||
#define USB_TRANSFER_SIZE 0x4000
|
||||
#define DMA_TRANSFER_SIZE 0x2000
|
||||
|
||||
#define BUF_HALF_MASK (USB_SAMP_BUFFER_SIZE >> 1)
|
||||
|
||||
// Unless we know the host knows our buffer size, we'll avoid leaving TX
|
||||
// until we've transmitted all bytes sent by the host. This flag is cleared
|
||||
// when the host requests our buffer size.
|
||||
bool auto_tx_flush = true;
|
||||
|
||||
volatile uint32_t dma_started, dma_pending, usb_started, usb_completed;
|
||||
|
||||
typedef struct {
|
||||
uint32_t freq_mhz;
|
||||
uint32_t freq_hz;
|
||||
} set_freq_params_t;
|
||||
|
||||
set_freq_params_t set_freq_params;
|
||||
|
||||
struct set_freq_explicit_params {
|
||||
uint64_t if_freq_hz; /* intermediate frequency */
|
||||
uint64_t lo_freq_hz; /* front-end local oscillator frequency */
|
||||
uint8_t path; /* image rejection filter path */
|
||||
};
|
||||
|
||||
struct set_freq_explicit_params explicit_params;
|
||||
|
||||
typedef struct {
|
||||
uint32_t freq_hz;
|
||||
uint32_t divider;
|
||||
} set_sample_r_params_t;
|
||||
|
||||
set_sample_r_params_t set_sample_r_params;
|
||||
|
||||
void transceiver_dma_setup(void);
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
const uint32_t bandwidth =
|
||||
(endpoint->setup.index << 16) | endpoint->setup.value;
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_BB_BANDWIDTH_TX,
|
||||
bandwidth);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_BB_BANDWIDTH_RX,
|
||||
bandwidth);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_freq(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->out,
|
||||
&set_freq_params,
|
||||
sizeof(set_freq_params_t),
|
||||
NULL,
|
||||
NULL);
|
||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||
const uint64_t freq =
|
||||
set_freq_params.freq_mhz * 1000000ULL + set_freq_params.freq_hz;
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_FREQUENCY_RF,
|
||||
freq * FP_ONE_HZ);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_FREQUENCY_IF,
|
||||
RADIO_UNSET);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_FREQUENCY_LO,
|
||||
RADIO_UNSET);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_IMAGE_REJECT,
|
||||
RADIO_UNSET);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_freq_explicit(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->out,
|
||||
&explicit_params,
|
||||
sizeof(struct set_freq_explicit_params),
|
||||
NULL,
|
||||
NULL);
|
||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_FREQUENCY_IF,
|
||||
explicit_params.if_freq_hz * FP_ONE_HZ);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_FREQUENCY_LO,
|
||||
explicit_params.lo_freq_hz * FP_ONE_HZ);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_IMAGE_REJECT,
|
||||
explicit_params.path);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert fractional sample rate to units of 1/(2**36) Hz.
|
||||
*/
|
||||
static inline fp_28_36_t round_sample_rate(uint64_t num, uint32_t denom) {
|
||||
uint64_t q1, r1, q2, r2, q3;
|
||||
|
||||
if (denom == 0) {
|
||||
denom = 1;
|
||||
}
|
||||
|
||||
q1 = num / denom;
|
||||
r1 = num % denom;
|
||||
|
||||
q2 = (r1 << 32) / denom;
|
||||
r2 = (r1 << 32) % denom;
|
||||
|
||||
q3 = ((r2 << 4) + (denom >> 1)) / denom;
|
||||
|
||||
return (q1 << 36) + (q2 << 4) + q3;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_sample_rate_frac(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->out,
|
||||
&set_sample_r_params,
|
||||
sizeof(set_sample_r_params_t),
|
||||
NULL,
|
||||
NULL);
|
||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||
uint32_t numerator = set_sample_r_params.freq_hz;
|
||||
uint32_t denominator = set_sample_r_params.divider;
|
||||
uint64_t value = round_sample_rate(numerator, denominator);
|
||||
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_SAMPLE_RATE, value);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_amp_enable(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_GAIN_TX_RF,
|
||||
endpoint->setup.value);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_GAIN_RX_RF,
|
||||
endpoint->setup.value);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_lna_gain(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
uint8_t gain = endpoint->setup.index;
|
||||
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_RX_IF, gain);
|
||||
endpoint->buffer[0] = RADIO_OK;
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->in,
|
||||
&endpoint->buffer,
|
||||
1,
|
||||
NULL,
|
||||
NULL);
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_vga_gain(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
uint8_t gain = endpoint->setup.index;
|
||||
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_RX_BB, gain);
|
||||
endpoint->buffer[0] = RADIO_OK;
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->in,
|
||||
&endpoint->buffer,
|
||||
1,
|
||||
NULL,
|
||||
NULL);
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_txvga_gain(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
uint8_t gain = endpoint->setup.index;
|
||||
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_TX_IF, gain);
|
||||
endpoint->buffer[0] = RADIO_OK;
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->in,
|
||||
&endpoint->buffer,
|
||||
1,
|
||||
NULL,
|
||||
NULL);
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_antenna_enable(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
switch (detected_platform()) {
|
||||
case BOARD_ID_HACKRF1_OG:
|
||||
case BOARD_ID_HACKRF1_R9:
|
||||
case BOARD_ID_PRALINE:
|
||||
// supported
|
||||
break;
|
||||
default:
|
||||
return USB_REQUEST_STATUS_STALL;
|
||||
}
|
||||
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_BIAS_TEE,
|
||||
endpoint->setup.value);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
static volatile uint32_t _tx_underrun_limit;
|
||||
static volatile uint32_t _rx_overrun_limit;
|
||||
|
||||
volatile transceiver_request_t transceiver_request = {
|
||||
.mode = TRANSCEIVER_MODE_OFF,
|
||||
.seq = 0,
|
||||
};
|
||||
|
||||
void transceiver_usb_setup_complete(usb_endpoint_t* const endpoint) {
|
||||
if (transceiver_request.mode == TRANSCEIVER_MODE_TX &&
|
||||
endpoint->setup.request == 1 && auto_tx_flush) {
|
||||
// This is a request to leave TX mode. Do so but NAK for now.
|
||||
request_transceiver_mode(endpoint->setup.value);
|
||||
} else {
|
||||
usb_setup_complete(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
// Must be called from an atomic context (normally USB ISR)
|
||||
void request_transceiver_mode(transceiver_mode_t mode) {
|
||||
usb_endpoint_flush(&usb_endpoint_bulk_in);
|
||||
usb_endpoint_flush(&usb_endpoint_bulk_out);
|
||||
|
||||
transceiver_request.mode = mode;
|
||||
transceiver_request.seq++;
|
||||
}
|
||||
|
||||
void transceiver_shutdown(void) {
|
||||
baseband_streaming_disable(&sgpio_config);
|
||||
operacake_sctimer_reset_state();
|
||||
|
||||
usb_endpoint_flush(&usb_endpoint_bulk_in);
|
||||
usb_endpoint_flush(&usb_endpoint_bulk_out);
|
||||
|
||||
led_off(LED2);
|
||||
led_off(LED3);
|
||||
radio_switch_opmode(&radio, TRANSCEIVER_MODE_OFF);
|
||||
m0_set_mode(M0_MODE_IDLE);
|
||||
}
|
||||
|
||||
void transceiver_startup(const transceiver_mode_t mode) {
|
||||
dma_started = 0;
|
||||
dma_pending = 0;
|
||||
usb_started = 0;
|
||||
usb_completed = 0;
|
||||
|
||||
transceiver_dma_setup();
|
||||
|
||||
radio_switch_opmode(&radio, mode);
|
||||
|
||||
switch (mode) {
|
||||
case TRANSCEIVER_MODE_RX_SWEEP:
|
||||
case TRANSCEIVER_MODE_RX:
|
||||
led_off(LED3);
|
||||
led_on(LED2);
|
||||
m0_set_mode(M0_MODE_RX);
|
||||
m0_state.shortfall_limit = _rx_overrun_limit;
|
||||
break;
|
||||
case TRANSCEIVER_MODE_TX:
|
||||
led_off(LED2);
|
||||
led_on(LED3);
|
||||
m0_set_mode(M0_MODE_TX_START);
|
||||
m0_state.shortfall_limit = _tx_underrun_limit;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
activate_best_clock_source();
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_transceiver_mode(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
switch (endpoint->setup.value) {
|
||||
case TRANSCEIVER_MODE_OFF:
|
||||
case TRANSCEIVER_MODE_RX:
|
||||
case TRANSCEIVER_MODE_TX:
|
||||
case TRANSCEIVER_MODE_RX_SWEEP:
|
||||
case TRANSCEIVER_MODE_CPLD_UPDATE:
|
||||
request_transceiver_mode(endpoint->setup.value);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
default:
|
||||
return USB_REQUEST_STATUS_STALL;
|
||||
}
|
||||
} else {
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_hw_sync_mode(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_REQUESTED,
|
||||
RADIO_TRIGGER,
|
||||
endpoint->setup.value);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_tx_underrun_limit(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
uint32_t value = (endpoint->setup.index << 16) + endpoint->setup.value;
|
||||
_tx_underrun_limit = value;
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_rx_overrun_limit(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
uint32_t value = (endpoint->setup.index << 16) + endpoint->setup.value;
|
||||
_rx_overrun_limit = value;
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_get_buffer_size(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
uint32_t value = USB_SAMP_BUFFER_SIZE + USB_BULK_BUFFER_SIZE;
|
||||
endpoint->buffer[0] = value & 0xff;
|
||||
endpoint->buffer[1] = (value & 0xff00) >> 8;
|
||||
endpoint->buffer[2] = (value & 0xff0000) >> 16;
|
||||
endpoint->buffer[3] = (value & 0xff000000) >> 24;
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->in,
|
||||
&endpoint->buffer,
|
||||
4,
|
||||
NULL,
|
||||
NULL);
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
|
||||
// We now know the host is aware of our buffer size, so it
|
||||
// can make its own decisions about flushing the buffer.
|
||||
auto_tx_flush = false;
|
||||
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
// Which GPDMA channel to use.
|
||||
const uint32_t DMA_CHANNEL = 1;
|
||||
|
||||
// GPDMA CCONFIG register setting.
|
||||
const uint32_t DMA_CONFIG =
|
||||
GPDMA_CCONFIG_FLOWCNTRL(0) // memory-to-memory
|
||||
| GPDMA_CCONFIG_IE(0) // no error interrupt
|
||||
| GPDMA_CCONFIG_ITC(1) // terminal count interrupt
|
||||
| GPDMA_CCONFIG_L(0) // do not lock
|
||||
| GPDMA_CCONFIG_H(0); // do not halt
|
||||
|
||||
// GPDMA CCONTROL register setting (excluding TRANSFERSIZE field).
|
||||
const uint32_t DMA_CONTROL =
|
||||
GPDMA_CCONTROL_SBSIZE(7) // 256-transfer src bursts
|
||||
| GPDMA_CCONTROL_DBSIZE(7) // 256-transfer dst bursts
|
||||
| GPDMA_CCONTROL_SWIDTH(2) // 32-bit src transfers
|
||||
| GPDMA_CCONTROL_DWIDTH(2) // 32-bit dst transfers
|
||||
| GPDMA_CCONTROL_S(0) // AHB Master 0
|
||||
| GPDMA_CCONTROL_D(1) // AHB Master 1
|
||||
| GPDMA_CCONTROL_SI(1) // increment source
|
||||
| GPDMA_CCONTROL_DI(1) // increment destination
|
||||
| GPDMA_CCONTROL_PROT1(0) // user mode
|
||||
| GPDMA_CCONTROL_PROT2(0) // not bufferable
|
||||
| GPDMA_CCONTROL_PROT3(0) // not cacheable
|
||||
| GPDMA_CCONTROL_I(1); // interrupt enabled
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
// Called before any sequence of DMA transfers.
|
||||
void transceiver_dma_setup(void) {
|
||||
gpdma_controller_enable();
|
||||
GPDMA_CCONFIG(DMA_CHANNEL) = DMA_CONFIG;
|
||||
GPDMA_CCONTROL(DMA_CHANNEL) = DMA_CONTROL;
|
||||
GPDMA_CLLI(DMA_CHANNEL) = 0;
|
||||
GPDMA_INTTCCLEAR = (1 << DMA_CHANNEL);
|
||||
nvic_enable_irq(NVIC_DMA_IRQ);
|
||||
}
|
||||
|
||||
// Called to start each DMA transfer.
|
||||
void transceiver_start_dma(void* src, void* dest, size_t size) {
|
||||
uint32_t num_transfers = size >> 2;
|
||||
GPDMA_CCONTROL(DMA_CHANNEL) = DMA_CONTROL | num_transfers;
|
||||
GPDMA_CSRCADDR(DMA_CHANNEL) = (uint32_t)src;
|
||||
GPDMA_CDESTADDR(DMA_CHANNEL) = (uint32_t)dest;
|
||||
dma_pending = size;
|
||||
gpdma_channel_enable(DMA_CHANNEL);
|
||||
}
|
||||
|
||||
// Called when a DMA transfer completes.
|
||||
void dma_isr(void) {
|
||||
gpdma_channel_disable(DMA_CHANNEL);
|
||||
GPDMA_INTTCCLEAR = (1 << DMA_CHANNEL);
|
||||
m0_state.m4_count += dma_pending;
|
||||
dma_pending = 0;
|
||||
}
|
||||
|
||||
void transceiver_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred) {
|
||||
(void)user_data;
|
||||
usb_completed += bytes_transferred;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
DIRECTION_RX,
|
||||
DIRECTION_TX,
|
||||
} direction_t;
|
||||
|
||||
void start_dma_if_possible(direction_t direction, size_t size) {
|
||||
if (dma_pending) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t sampling_completed = m0_state.m0_count;
|
||||
uint32_t dma_completed = m0_state.m4_count;
|
||||
uint32_t samp_offset = dma_started & USB_SAMP_BUFFER_MASK;
|
||||
uint32_t bulk_offset = dma_started & USB_BULK_BUFFER_MASK;
|
||||
uint32_t data_available, space_in_use, space_available, samp_buf_margin;
|
||||
uint8_t *dest, *src;
|
||||
|
||||
if (direction == DIRECTION_RX) {
|
||||
data_available = sampling_completed - dma_started;
|
||||
space_in_use = usb_completed - dma_completed;
|
||||
space_available = USB_BULK_BUFFER_SIZE - space_in_use;
|
||||
samp_buf_margin = USB_SAMP_BUFFER_SIZE - data_available;
|
||||
src = &usb_samp_buffer[samp_offset];
|
||||
dest = &usb_bulk_buffer[bulk_offset];
|
||||
} else {
|
||||
data_available = usb_completed - dma_started;
|
||||
space_in_use = dma_completed - sampling_completed;
|
||||
space_available = USB_SAMP_BUFFER_SIZE - space_in_use;
|
||||
samp_buf_margin = space_in_use;
|
||||
src = &usb_bulk_buffer[bulk_offset];
|
||||
dest = &usb_samp_buffer[samp_offset];
|
||||
}
|
||||
|
||||
if (data_available < size || size > space_available) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t m0_buf_half = sampling_completed & BUF_HALF_MASK;
|
||||
uint32_t dma_buf_half = dma_started & BUF_HALF_MASK;
|
||||
bool same_buf_half = m0_buf_half == dma_buf_half;
|
||||
|
||||
if (same_buf_half && samp_buf_margin >= (USB_SAMP_BUFFER_SIZE / 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
transceiver_start_dma(src, dest, size);
|
||||
|
||||
dma_started += size;
|
||||
}
|
||||
|
||||
void start_usb_if_possible(direction_t direction) {
|
||||
uint32_t bulk_offset = usb_started & USB_BULK_BUFFER_MASK;
|
||||
uint32_t dma_completed = m0_state.m4_count;
|
||||
uint32_t bytes_available;
|
||||
usb_endpoint_t* usb_endpoint;
|
||||
|
||||
if (direction == DIRECTION_RX) {
|
||||
bytes_available = dma_completed - usb_started;
|
||||
usb_endpoint = &usb_endpoint_bulk_in;
|
||||
} else {
|
||||
uint32_t space_used = usb_started - dma_completed;
|
||||
bytes_available = USB_BULK_BUFFER_SIZE - space_used;
|
||||
usb_endpoint = &usb_endpoint_bulk_out;
|
||||
}
|
||||
|
||||
if (bytes_available < USB_TRANSFER_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
usb_transfer_schedule_block(
|
||||
usb_endpoint,
|
||||
&usb_bulk_buffer[bulk_offset],
|
||||
USB_TRANSFER_SIZE,
|
||||
transceiver_bulk_transfer_complete,
|
||||
NULL);
|
||||
|
||||
usb_started += USB_TRANSFER_SIZE;
|
||||
}
|
||||
|
||||
int8_t saturation_buffer = 0;
|
||||
uint64_t saturation_buffer_time = 0;
|
||||
volatile uint64_t systick_counter = 0;
|
||||
|
||||
void sys_tick_handler(void) {
|
||||
systick_counter++;
|
||||
}
|
||||
|
||||
void rx_mode(uint32_t seq) {
|
||||
transceiver_startup(TRANSCEIVER_MODE_RX);
|
||||
|
||||
baseband_streaming_enable(&sgpio_config);
|
||||
|
||||
while (transceiver_request.seq == seq) {
|
||||
start_dma_if_possible(DIRECTION_RX, DMA_TRANSFER_SIZE);
|
||||
start_usb_if_possible(DIRECTION_RX);
|
||||
|
||||
int8_t sample_value = *(
|
||||
int8_t*)&usb_samp_buffer[m0_state.m0_count & USB_SAMP_BUFFER_MASK];
|
||||
|
||||
if (sample_value > saturation_buffer)
|
||||
saturation_buffer = sample_value;
|
||||
|
||||
if (-sample_value > saturation_buffer)
|
||||
saturation_buffer = -sample_value;
|
||||
|
||||
if (saturation_buffer_time + 4 < systick_counter) {
|
||||
saturation_buffer_time = systick_counter;
|
||||
hackrf_ui()->set_saturation(saturation_buffer);
|
||||
saturation_buffer = 0;
|
||||
}
|
||||
|
||||
radio_update(&radio);
|
||||
}
|
||||
|
||||
transceiver_shutdown();
|
||||
}
|
||||
|
||||
void tx_mode(uint32_t seq) {
|
||||
transceiver_startup(TRANSCEIVER_MODE_TX);
|
||||
|
||||
// First, make transfers directly into the sample buffer to fill it.
|
||||
for (int i = 0; i < (USB_SAMP_BUFFER_SIZE / USB_TRANSFER_SIZE); i++) {
|
||||
// Set up transfer.
|
||||
usb_transfer_schedule_block(
|
||||
&usb_endpoint_bulk_out,
|
||||
&usb_samp_buffer[usb_started],
|
||||
USB_TRANSFER_SIZE,
|
||||
transceiver_bulk_transfer_complete,
|
||||
NULL);
|
||||
usb_started += USB_TRANSFER_SIZE;
|
||||
|
||||
// Wait for the transfer to complete.
|
||||
while (usb_completed < usb_started) {
|
||||
// Handle the host switching modes before filling the buffer.
|
||||
if (transceiver_request.seq != seq) {
|
||||
transceiver_shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
radio_update(&radio);
|
||||
}
|
||||
}
|
||||
|
||||
// Sample buffer is now full. Update DMA counters accordingly.
|
||||
dma_started = USB_SAMP_BUFFER_SIZE;
|
||||
m0_state.m4_count = USB_SAMP_BUFFER_SIZE;
|
||||
|
||||
// Start transmitting samples.
|
||||
baseband_streaming_enable(&sgpio_config);
|
||||
|
||||
// Continue feeding samples to the sample buffer.
|
||||
while (transceiver_request.seq == seq) {
|
||||
start_dma_if_possible(DIRECTION_TX, DMA_TRANSFER_SIZE);
|
||||
start_usb_if_possible(DIRECTION_TX);
|
||||
radio_update(&radio);
|
||||
}
|
||||
|
||||
// Host has now requested to stop TX. If we're not auto-flushing, we
|
||||
// should now stop TX immediately.
|
||||
|
||||
if (!auto_tx_flush) {
|
||||
transceiver_shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we should now ensure all bytes sent by the host are
|
||||
// transmitted before we leave TX. First, we should make sure all data
|
||||
// currently in the USB bulk buffer reaches the sample buffer.
|
||||
|
||||
if ((usb_started - usb_completed) > 0) {
|
||||
// We were part way through a 16KB firmware-side transfer when
|
||||
// the transceiver mode change request to stop TX was received.
|
||||
//
|
||||
// We want to include the contents of that partial transfer in
|
||||
// the data we move to the sample buffer.
|
||||
//
|
||||
// The transfer was already stopped by usb_endpoint_flush(),
|
||||
// which was called from request_transceiver_mode().
|
||||
//
|
||||
// We will not have had a callback, and the transfer descriptor
|
||||
// (dTD) will not have been updated, since the transfer did not
|
||||
// complete.
|
||||
//
|
||||
// However, as long as we haven't started a new transfer, we
|
||||
// can retrieve the partial byte count from the transfer
|
||||
// overlay in the endpoint queue head (dQH) (UM10503 25.9.1).
|
||||
|
||||
usb_queue_head_t* const qh =
|
||||
usb_queue_head(usb_endpoint_bulk_out.address);
|
||||
unsigned int bytes_remaining =
|
||||
(qh->total_bytes & USB_TD_DTD_TOKEN_TOTAL_BYTES_MASK) >>
|
||||
USB_TD_DTD_TOKEN_TOTAL_BYTES_SHIFT;
|
||||
unsigned int bytes_transferred = USB_TRANSFER_SIZE - bytes_remaining;
|
||||
usb_completed += bytes_transferred;
|
||||
}
|
||||
|
||||
// Feed the remaining data from the bulk buffer to the sample buffer.
|
||||
// At this point, we also need to handle the case where there is less data
|
||||
// to be transferred to the sample buffer than a full-sized DMA transfer.
|
||||
|
||||
// Any remainder of less than 4 bytes will be ignored; this is the chunk
|
||||
// size of our DMA transfers.
|
||||
while ((usb_completed - m0_state.m4_count) >= 4) {
|
||||
uint32_t data_available = usb_completed - dma_started;
|
||||
if (data_available > DMA_TRANSFER_SIZE) {
|
||||
start_dma_if_possible(DIRECTION_TX, DMA_TRANSFER_SIZE);
|
||||
} else {
|
||||
start_dma_if_possible(DIRECTION_TX, data_available);
|
||||
}
|
||||
radio_update(&radio);
|
||||
}
|
||||
|
||||
// Wait for the data in the sample buffer to be transmitted.
|
||||
|
||||
// Any remainder of less than 32 bytes will be ignored; this is
|
||||
// the chunk size used by the M0 core to transfer samples to SGPIO.
|
||||
while ((m0_state.m4_count - m0_state.m0_count) >= 32) {
|
||||
radio_update(&radio);
|
||||
}
|
||||
|
||||
// All data received from the host has now been transmitted.
|
||||
// Now we can ACK the control request that took us out of TX mode.
|
||||
usb_transfer_schedule_ack(usb_endpoint_control_in.in);
|
||||
|
||||
transceiver_shutdown();
|
||||
}
|
||||
|
||||
void off_mode(uint32_t seq) {
|
||||
while (transceiver_request.seq == seq) {
|
||||
radio_update(&radio);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Jared Boone
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
@@ -20,22 +20,13 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "usb_type.h"
|
||||
#include "usb_descriptor.h"
|
||||
|
||||
#define USB_VENDOR_ID (0x0781) /* SanDisk Corp. */
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef HACKRF_ONE
|
||||
#define USB_PRODUCT_ID (0xa7a8) /* SD card reader */
|
||||
#elif JAWBREAKER
|
||||
#define USB_PRODUCT_ID (0x604B)
|
||||
#elif RAD1O
|
||||
#define USB_PRODUCT_ID (0xCC15)
|
||||
#else
|
||||
#define USB_PRODUCT_ID (0xFFFF)
|
||||
#endif
|
||||
#include <usb_type.h>
|
||||
|
||||
#define USB_VENDOR_ID (0x0781) /* SanDisk Corp. */
|
||||
|
||||
#define USB_API_VERSION (0x0127) /* hardware revision */
|
||||
|
||||
@@ -50,7 +41,8 @@
|
||||
|
||||
#define USB_STRING_LANGID (0x0409)
|
||||
|
||||
uint8_t usb_descriptor_device[] = {
|
||||
#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE)
|
||||
uint8_t usb_descriptor_device_hackrf[] = {
|
||||
18, // bLength
|
||||
USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType
|
||||
USB_WORD(0x0200), // bcdUSB
|
||||
@@ -59,13 +51,50 @@ uint8_t usb_descriptor_device[] = {
|
||||
0x00, // bDeviceProtocol
|
||||
USB_MAX_PACKET0, // bMaxPacketSize0
|
||||
USB_WORD(USB_VENDOR_ID), // idVendor
|
||||
USB_WORD(USB_PRODUCT_ID), // idProduct
|
||||
USB_WORD(0xa7a8), // idProduct /* SD card reader */
|
||||
USB_WORD(USB_API_VERSION), // bcdDevice
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x04, // iSerialNumber
|
||||
0x01 // bNumConfigurations
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_JAWBREAKER
|
||||
uint8_t usb_descriptor_device_jawbreaker[] = {
|
||||
18, // bLength
|
||||
USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType
|
||||
USB_WORD(0x0200), // bcdUSB
|
||||
0x00, // bDeviceClass
|
||||
0x00, // bDeviceSubClass
|
||||
0x00, // bDeviceProtocol
|
||||
USB_MAX_PACKET0, // bMaxPacketSize0
|
||||
USB_WORD(USB_VENDOR_ID), // idVendor
|
||||
USB_WORD(0x604B), // idProduct
|
||||
USB_WORD(USB_API_VERSION), // bcdDevice
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x04, // iSerialNumber
|
||||
0x01 // bNumConfigurations
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_RAD1O
|
||||
uint8_t usb_descriptor_device_rad1o[] = {
|
||||
18, // bLength
|
||||
USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType
|
||||
USB_WORD(0x0200), // bcdUSB
|
||||
0x00, // bDeviceClass
|
||||
0x00, // bDeviceSubClass
|
||||
0x00, // bDeviceProtocol
|
||||
USB_MAX_PACKET0, // bMaxPacketSize0
|
||||
USB_WORD(USB_VENDOR_ID), // idVendor
|
||||
USB_WORD(0xCC15), // idProduct
|
||||
USB_WORD(USB_API_VERSION), // bcdDevice
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x04, // iSerialNumber
|
||||
0x01 // bNumConfigurations
|
||||
};
|
||||
#endif
|
||||
|
||||
uint8_t usb_descriptor_device_qualifier[] = {
|
||||
10, // bLength
|
||||
@@ -161,162 +190,213 @@ uint8_t usb_descriptor_string_languages[] = {
|
||||
|
||||
// clang-format off
|
||||
uint8_t usb_descriptor_string_manufacturer[] = {
|
||||
40, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'G', 0x00,
|
||||
'r', 0x00,
|
||||
'e', 0x00,
|
||||
'a', 0x00,
|
||||
't', 0x00,
|
||||
' ', 0x00,
|
||||
'S', 0x00,
|
||||
'c', 0x00,
|
||||
'o', 0x00,
|
||||
't', 0x00,
|
||||
't', 0x00,
|
||||
' ', 0x00,
|
||||
'G', 0x00,
|
||||
'a', 0x00,
|
||||
'd', 0x00,
|
||||
'g', 0x00,
|
||||
'e', 0x00,
|
||||
't', 0x00,
|
||||
's', 0x00,
|
||||
40, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'G', 0x00,
|
||||
'r', 0x00,
|
||||
'e', 0x00,
|
||||
'a', 0x00,
|
||||
't', 0x00,
|
||||
' ', 0x00,
|
||||
'S', 0x00,
|
||||
'c', 0x00,
|
||||
'o', 0x00,
|
||||
't', 0x00,
|
||||
't', 0x00,
|
||||
' ', 0x00,
|
||||
'G', 0x00,
|
||||
'a', 0x00,
|
||||
'd', 0x00,
|
||||
'g', 0x00,
|
||||
'e', 0x00,
|
||||
't', 0x00,
|
||||
's', 0x00,
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_string_product[] = {
|
||||
#ifdef HACKRF_ONE
|
||||
34, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'P', 0x00,
|
||||
'o', 0x00,
|
||||
'r', 0x00,
|
||||
't', 0x00,
|
||||
'a', 0x00,
|
||||
'P', 0x00,
|
||||
'a', 0x00,
|
||||
'c', 0x00,
|
||||
'k', 0x00,
|
||||
' ', 0x00,
|
||||
#ifdef IS_HACKRF_ONE
|
||||
uint8_t usb_descriptor_string_product_hackrf_one[] = {
|
||||
34, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'P', 0x00,
|
||||
'o', 0x00,
|
||||
'r', 0x00,
|
||||
't', 0x00,
|
||||
'a', 0x00,
|
||||
'P', 0x00,
|
||||
'a', 0x00,
|
||||
'c', 0x00,
|
||||
'k', 0x00,
|
||||
' ', 0x00,
|
||||
|
||||
'M', 0x00,
|
||||
'a', 0x00,
|
||||
'y', 0x00,
|
||||
'h', 0x00,
|
||||
'e', 0x00,
|
||||
'm', 0x00,
|
||||
|
||||
#elif JAWBREAKER
|
||||
36, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'H', 0x00,
|
||||
'a', 0x00,
|
||||
'c', 0x00,
|
||||
'k', 0x00,
|
||||
'R', 0x00,
|
||||
'F', 0x00,
|
||||
' ', 0x00,
|
||||
'J', 0x00,
|
||||
'a', 0x00,
|
||||
'w', 0x00,
|
||||
'b', 0x00,
|
||||
'r', 0x00,
|
||||
'e', 0x00,
|
||||
'a', 0x00,
|
||||
'k', 0x00,
|
||||
'e', 0x00,
|
||||
'r', 0x00,
|
||||
#elif RAD1O
|
||||
12, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'r', 0x00,
|
||||
'a', 0x00,
|
||||
'd', 0x00,
|
||||
'1', 0x00,
|
||||
'o', 0x00,
|
||||
#else
|
||||
14, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'H', 0x00,
|
||||
'a', 0x00,
|
||||
'c', 0x00,
|
||||
'k', 0x00,
|
||||
'R', 0x00,
|
||||
'F', 0x00,
|
||||
'M', 0x00,
|
||||
'a', 0x00,
|
||||
'y', 0x00,
|
||||
'h', 0x00,
|
||||
'e', 0x00,
|
||||
'm', 0x00,
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
uint8_t usb_descriptor_string_product_praline[] = {
|
||||
34, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'P', 0x00,
|
||||
'o', 0x00,
|
||||
'r', 0x00,
|
||||
't', 0x00,
|
||||
'a', 0x00,
|
||||
'P', 0x00,
|
||||
'a', 0x00,
|
||||
'c', 0x00,
|
||||
'k', 0x00,
|
||||
' ', 0x00,
|
||||
|
||||
'M', 0x00,
|
||||
'a', 0x00,
|
||||
'y', 0x00,
|
||||
'h', 0x00,
|
||||
'e', 0x00,
|
||||
'm', 0x00,
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_JAWBREAKER
|
||||
uint8_t usb_descriptor_string_product_jawbreaker[] = {
|
||||
36, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'H', 0x00,
|
||||
'a', 0x00,
|
||||
'c', 0x00,
|
||||
'k', 0x00,
|
||||
'R', 0x00,
|
||||
'F', 0x00,
|
||||
' ', 0x00,
|
||||
'J', 0x00,
|
||||
'a', 0x00,
|
||||
'w', 0x00,
|
||||
'b', 0x00,
|
||||
'r', 0x00,
|
||||
'e', 0x00,
|
||||
'a', 0x00,
|
||||
'k', 0x00,
|
||||
'e', 0x00,
|
||||
'r', 0x00,
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_RAD1O
|
||||
uint8_t usb_descriptor_string_product_rad1o[] = {
|
||||
12, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'r', 0x00,
|
||||
'a', 0x00,
|
||||
'd', 0x00,
|
||||
'1', 0x00,
|
||||
'o', 0x00,
|
||||
};
|
||||
#endif
|
||||
|
||||
uint8_t usb_descriptor_string_config_description[] = {
|
||||
24, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'T', 0x00,
|
||||
'r', 0x00,
|
||||
'a', 0x00,
|
||||
'n', 0x00,
|
||||
's', 0x00,
|
||||
'c', 0x00,
|
||||
'e', 0x00,
|
||||
'i', 0x00,
|
||||
'v', 0x00,
|
||||
'e', 0x00,
|
||||
'r', 0x00,
|
||||
24, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'T', 0x00,
|
||||
'r', 0x00,
|
||||
'a', 0x00,
|
||||
'n', 0x00,
|
||||
's', 0x00,
|
||||
'c', 0x00,
|
||||
'e', 0x00,
|
||||
'i', 0x00,
|
||||
'v', 0x00,
|
||||
'e', 0x00,
|
||||
'r', 0x00,
|
||||
};
|
||||
|
||||
#ifdef DFU_MODE
|
||||
uint8_t usb_descriptor_string_serial_number[] = {
|
||||
30, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'R', 0x00,
|
||||
'u', 0x00,
|
||||
'n', 0x00,
|
||||
'n', 0x00,
|
||||
'i', 0x00,
|
||||
'n', 0x00,
|
||||
'g', 0x00,
|
||||
'F', 0x00,
|
||||
'r', 0x00,
|
||||
'o', 0x00,
|
||||
'm', 0x00,
|
||||
'R', 0x00,
|
||||
'A', 0x00,
|
||||
'M', 0x00,
|
||||
30, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'R', 0x00,
|
||||
'u', 0x00,
|
||||
'n', 0x00,
|
||||
'n', 0x00,
|
||||
'i', 0x00,
|
||||
'n', 0x00,
|
||||
'g', 0x00,
|
||||
'F', 0x00,
|
||||
'r', 0x00,
|
||||
'o', 0x00,
|
||||
'm', 0x00,
|
||||
'R', 0x00,
|
||||
'A', 0x00,
|
||||
'M', 0x00,
|
||||
};
|
||||
#else
|
||||
uint8_t usb_descriptor_string_serial_number[USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN];
|
||||
#endif
|
||||
|
||||
uint8_t* usb_descriptor_strings[] = {
|
||||
usb_descriptor_string_languages,
|
||||
usb_descriptor_string_manufacturer,
|
||||
usb_descriptor_string_product,
|
||||
usb_descriptor_string_config_description,
|
||||
usb_descriptor_string_serial_number,
|
||||
0, // TERMINATOR
|
||||
#ifdef IS_HACKRF_ONE
|
||||
uint8_t* usb_descriptor_strings_hackrf_one[] = {
|
||||
usb_descriptor_string_languages,
|
||||
usb_descriptor_string_manufacturer,
|
||||
usb_descriptor_string_product_hackrf_one,
|
||||
usb_descriptor_string_config_description,
|
||||
usb_descriptor_string_serial_number,
|
||||
0, // TERMINATOR
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
uint8_t* usb_descriptor_strings_praline[] = {
|
||||
usb_descriptor_string_languages,
|
||||
usb_descriptor_string_manufacturer,
|
||||
usb_descriptor_string_product_praline,
|
||||
usb_descriptor_string_config_description,
|
||||
usb_descriptor_string_serial_number,
|
||||
0, // TERMINATOR
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_JAWBREAKER
|
||||
uint8_t* usb_descriptor_strings_jawbreaker[] = {
|
||||
usb_descriptor_string_languages,
|
||||
usb_descriptor_string_manufacturer,
|
||||
usb_descriptor_string_product_jawbreaker,
|
||||
usb_descriptor_string_config_description,
|
||||
usb_descriptor_string_serial_number,
|
||||
0, // TERMINATOR
|
||||
};
|
||||
#endif
|
||||
#ifdef IS_RAD1O
|
||||
uint8_t* usb_descriptor_strings_rad1o[] = {
|
||||
usb_descriptor_string_languages,
|
||||
usb_descriptor_string_manufacturer,
|
||||
usb_descriptor_string_product_rad1o,
|
||||
usb_descriptor_string_config_description,
|
||||
usb_descriptor_string_serial_number,
|
||||
0, // TERMINATOR
|
||||
};
|
||||
#endif
|
||||
|
||||
uint8_t wcid_string_descriptor[] = {
|
||||
18, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'M', 0x00,
|
||||
'S', 0x00,
|
||||
'F', 0x00,
|
||||
'T', 0x00,
|
||||
'1', 0x00,
|
||||
'0', 0x00,
|
||||
'0', 0x00,
|
||||
USB_WCID_VENDOR_REQ, // vendor request code for further descriptor
|
||||
0x00
|
||||
18, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'M', 0x00,
|
||||
'S', 0x00,
|
||||
'F', 0x00,
|
||||
'T', 0x00,
|
||||
'1', 0x00,
|
||||
'0', 0x00,
|
||||
'0', 0x00,
|
||||
USB_WCID_VENDOR_REQ, // vendor request code for further descriptor
|
||||
0x00
|
||||
};
|
||||
|
||||
uint8_t wcid_feature_descriptor[] = {
|
||||
0x28, 0x00, 0x00, 0x00, // bLength
|
||||
USB_WORD(0x0100), // WCID version
|
||||
USB_WORD(0x0004), // WICD descriptor index
|
||||
0x01, // bNumSections
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Reserved
|
||||
0x00, // bInterfaceNumber
|
||||
0x01, // Reserved
|
||||
'W', 'I', 'N', 'U', 'S', 'B', 0x00,0x00, // Compatible ID, padded with zeros
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Sub-compatible ID
|
||||
0x00,0x00,0x00,0x00,0x00,0x00 // Reserved
|
||||
};
|
||||
0x28, 0x00, 0x00, 0x00, // bLength
|
||||
USB_WORD(0x0100), // WCID version
|
||||
USB_WORD(0x0004), // WICD descriptor index
|
||||
0x01, // bNumSections
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Reserved
|
||||
0x00, // bInterfaceNumber
|
||||
0x01, // Reserved
|
||||
'W', 'I', 'N', 'U', 'S', 'B', 0x00,0x00, // Compatible ID, padded with zeros
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Sub-compatible ID
|
||||
0x00,0x00,0x00,0x00,0x00,0x00 // Reserved
|
||||
};
|
||||
@@ -20,22 +20,46 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint8_t usb_descriptor_device[];
|
||||
#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE)
|
||||
extern uint8_t usb_descriptor_device_hackrf[];
|
||||
#endif
|
||||
#ifdef IS_JAWBREAKER
|
||||
extern uint8_t usb_descriptor_device_jawbreaker[];
|
||||
#endif
|
||||
#ifdef IS_RAD1O
|
||||
extern uint8_t usb_descriptor_device_rad1o[];
|
||||
#endif
|
||||
extern uint8_t usb_descriptor_device_qualifier[];
|
||||
extern uint8_t usb_descriptor_configuration_full_speed[];
|
||||
extern uint8_t usb_descriptor_configuration_high_speed[];
|
||||
extern uint8_t usb_descriptor_string_languages[];
|
||||
extern uint8_t usb_descriptor_string_manufacturer[];
|
||||
extern uint8_t usb_descriptor_string_product[];
|
||||
#ifdef IS_HACKRF_ONE
|
||||
extern uint8_t usb_descriptor_string_product_hackrf_one[];
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
extern uint8_t usb_descriptor_string_product_praline[];
|
||||
#endif
|
||||
#ifdef IS_JAWBREAKER
|
||||
extern uint8_t usb_descriptor_string_product_jawbreaker[];
|
||||
#endif
|
||||
#ifdef IS_RAD1O
|
||||
extern uint8_t usb_descriptor_string_product_rad1o[];
|
||||
#endif
|
||||
|
||||
#define USB_DESCRIPTOR_STRING_SERIAL_LEN 32
|
||||
#define USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN \
|
||||
(USB_DESCRIPTOR_STRING_SERIAL_LEN * 2 + 2) /* UTF-16LE */
|
||||
extern uint8_t usb_descriptor_string_serial_number[];
|
||||
|
||||
extern uint8_t* usb_descriptor_strings[];
|
||||
extern uint8_t* usb_descriptor_strings_hackrf_one[];
|
||||
extern uint8_t* usb_descriptor_strings_jawbreaker[];
|
||||
extern uint8_t* usb_descriptor_strings_rad1o[];
|
||||
extern uint8_t* usb_descriptor_strings_praline[];
|
||||
|
||||
#define USB_WCID_VENDOR_REQ 0x19
|
||||
extern uint8_t wcid_string_descriptor[];
|
||||
|
||||
+12
-12
@@ -251,36 +251,36 @@ struct GPIO {
|
||||
|
||||
// Physical Level Operations
|
||||
|
||||
void set() const {
|
||||
__attribute__((always_inline)) void set() const {
|
||||
palSetPad(_gpio_port, _gpio_pad);
|
||||
}
|
||||
|
||||
void clear() const {
|
||||
__attribute__((always_inline)) void clear() const {
|
||||
palClearPad(_gpio_port, _gpio_pad);
|
||||
}
|
||||
|
||||
void toggle() const {
|
||||
__attribute__((always_inline)) void toggle() const {
|
||||
palTogglePad(_gpio_port, _gpio_pad);
|
||||
}
|
||||
|
||||
void output() const {
|
||||
__attribute__((always_inline)) void output() const {
|
||||
palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
}
|
||||
|
||||
void input() const {
|
||||
__attribute__((always_inline)) void input() const {
|
||||
palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_INPUT);
|
||||
}
|
||||
|
||||
void write(const bool value) const {
|
||||
__attribute__((always_inline)) void write(const bool value) const {
|
||||
palWritePad(_gpio_port, _gpio_pad, value);
|
||||
}
|
||||
|
||||
bool read() const {
|
||||
__attribute__((always_inline)) bool read() const {
|
||||
return palReadPad(_gpio_port, _gpio_pad);
|
||||
}
|
||||
|
||||
// Turns the feature ON based on its polarity
|
||||
void setActive() const {
|
||||
__attribute__((always_inline)) void setActive() const {
|
||||
if (_polarity == Polarity::ActiveHigh) {
|
||||
set();
|
||||
} else {
|
||||
@@ -289,7 +289,7 @@ struct GPIO {
|
||||
}
|
||||
|
||||
// Turns the feature OFF based on its polarity
|
||||
void setInactive() const {
|
||||
__attribute__((always_inline)) void setInactive() const {
|
||||
if (_polarity == Polarity::ActiveHigh) {
|
||||
clear();
|
||||
} else {
|
||||
@@ -298,7 +298,7 @@ struct GPIO {
|
||||
}
|
||||
|
||||
// Sets the logical state of the feature
|
||||
void setState(const bool active) const {
|
||||
__attribute__((always_inline)) void setState(const bool active) const {
|
||||
if (active) {
|
||||
setActive();
|
||||
} else {
|
||||
@@ -307,12 +307,12 @@ struct GPIO {
|
||||
}
|
||||
|
||||
// Returns true if the feature is logically active/enabled
|
||||
bool isEnabled() const {
|
||||
__attribute__((always_inline)) bool isEnabled() const {
|
||||
const bool physical_state = read();
|
||||
return (_polarity == Polarity::ActiveHigh) ? physical_state : !physical_state;
|
||||
}
|
||||
|
||||
bool operator!=(const GPIO& other) const {
|
||||
__attribute__((always_inline)) bool operator!=(const GPIO& other) const {
|
||||
return (port() != other.port()) || (pad() != other.pad());
|
||||
}
|
||||
|
||||
|
||||
@@ -318,29 +318,33 @@ void I2CDevManager::create_thread() {
|
||||
msg_t I2CDevManager::timer_fn(void* arg) {
|
||||
(void)arg;
|
||||
uint16_t curr_timer = 0; // seconds since thread start
|
||||
|
||||
while (1) {
|
||||
systime_t start_time = chTimeNow();
|
||||
bool changed = false;
|
||||
// check if i2c scan needed
|
||||
|
||||
// Check if i2c scan is needed
|
||||
if (force_scan || (scan_interval != 0 && curr_timer % scan_interval == 0)) {
|
||||
changed = changed | scan();
|
||||
force_scan = false;
|
||||
}
|
||||
|
||||
// Update connected devices based on their own intervals
|
||||
for (size_t i = 0; i < devlist.size(); i++) {
|
||||
if (devlist[i].addr != 0 && devlist[i].dev && devlist[i].dev->query_interval != 0) {
|
||||
if ((curr_timer % devlist[i].dev->query_interval) == 0) { // only if it is device's interval
|
||||
devlist[i].dev->update(); // updates it's data, and broadcasts it. if there is any error it will handle in it, and later we can remove it
|
||||
if ((curr_timer % devlist[i].dev->query_interval) == 0) {
|
||||
devlist[i].dev->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove all unneeded items
|
||||
// Remove all unneeded items (dead devices or devices throwing too many errors)
|
||||
chMtxLock(&mutex_list);
|
||||
size_t cnt = devlist.size();
|
||||
devlist.erase(std::remove_if(devlist.begin(), devlist.end(), [](const I2DevListElement& x) {
|
||||
if (x.addr == 0) return true;
|
||||
if (x.dev && x.dev->need_del == true) return true; // self destruct on too many errors
|
||||
return false; // won't remove the unidentified ones, so we can list them, and not trying all the time with them
|
||||
if (x.dev && x.dev->need_del == true) return true;
|
||||
return false;
|
||||
}),
|
||||
devlist.end());
|
||||
chMtxUnlock();
|
||||
@@ -350,11 +354,24 @@ msg_t I2CDevManager::timer_fn(void* arg) {
|
||||
I2CDevListChangedMessage msg{};
|
||||
EventDispatcher::send_message(msg);
|
||||
}
|
||||
systime_t end_time = chTimeNow();
|
||||
systime_t delta = (end_time > start_time) ? end_time - start_time : 100; // wont calculate overflow, just guess.
|
||||
if (delta > 950) delta = 950; // ensure minimum 50 milli sleep
|
||||
|
||||
chThdSleepMilliseconds(1000 - delta); // 1sec timer
|
||||
systime_t end_time = chTimeNow();
|
||||
|
||||
// 1. Calculate elapsed ticks safely handling overflow
|
||||
uint32_t delta_ticks = end_time - start_time;
|
||||
|
||||
// 2. Keep EVERYTHING in ticks (No MS conversion!) to prevent truncation drift
|
||||
if (delta_ticks < CH_FREQUENCY) {
|
||||
// Calculate exactly how many ticks are missing to complete 1 full second
|
||||
uint32_t sleep_ticks = CH_FREQUENCY - delta_ticks;
|
||||
|
||||
// Sleep using native ticks instead of milliseconds
|
||||
chThdSleep(sleep_ticks);
|
||||
} else {
|
||||
// Safety fallback: if processing took longer than 1 second, sleep 50ms to yield CPU
|
||||
chThdSleepMilliseconds(50);
|
||||
}
|
||||
|
||||
++curr_timer;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -59,8 +59,10 @@ class JTAG {
|
||||
|
||||
void runtest_ms(const size_t count) {
|
||||
auto starttime = chTimeNow();
|
||||
// We convert the count in milliseconds to system ticks:
|
||||
auto duration_ticks = MS2ST(count) + 1;
|
||||
|
||||
while ((chTimeNow() - starttime) < (count + 1))
|
||||
while ((chTimeNow() - starttime) < duration_ticks)
|
||||
target.clock(0, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -294,7 +294,6 @@ void lcd_start_ram_write(
|
||||
lcd_caset(p.x(), p.x() + s.width() - 1);
|
||||
lcd_paset(p.y(), p.y() + s.height() - 1);
|
||||
lcd_ramwr_start();
|
||||
io.update_cached_values();
|
||||
}
|
||||
|
||||
void lcd_start_ram_read(
|
||||
|
||||
@@ -111,24 +111,6 @@ void IO::reference_oscillator(const bool enable) {
|
||||
io_write(1, io_reg);
|
||||
}
|
||||
|
||||
bool IO::get_dark_cover() {
|
||||
return portapack::persistent_memory::apply_fake_brightness();
|
||||
}
|
||||
|
||||
bool IO::get_is_normally_black() {
|
||||
return portapack::persistent_memory::config_lcd_normally_black();
|
||||
}
|
||||
|
||||
uint8_t IO::get_brightness() {
|
||||
return portapack::persistent_memory::fake_brightness_level();
|
||||
}
|
||||
|
||||
void IO::update_cached_values() {
|
||||
lcd_normally_black = get_is_normally_black();
|
||||
dark_cover_enabled = get_dark_cover();
|
||||
brightness = get_brightness();
|
||||
}
|
||||
|
||||
uint32_t IO::io_update(const TouchPinsConfig write_value) {
|
||||
/* Very touchy code to save context of PortaPack data bus while the
|
||||
* resistive touch pin drive is changed. Order of operations is
|
||||
|
||||
@@ -37,21 +37,6 @@
|
||||
|
||||
// #include "portapack_persistent_memory.hpp"
|
||||
|
||||
// Darkened pixel bit mask for each possible shift value.
|
||||
static const uint16_t darken_mask[4] = {
|
||||
0b1111111111111111, // RrrrrGgggggBbbbb
|
||||
0b0111101111101111, // 0Rrrr0Ggggg0Bbbb
|
||||
0b0011100111100111, // 00Rrr00Gggg00Bbb
|
||||
0b0001100011100011 // 000Rr000Ggg000Bb
|
||||
};
|
||||
|
||||
// To darken, dividing each color level R/G/B by 2^shift.
|
||||
#define DARKENED_PIXEL(pixel, shift) ((pixel >> shift) & darken_mask[shift])
|
||||
|
||||
// To un-darken, multiply each color level by 2^shift (might still be darker that before since some bits may have been lost above).
|
||||
// This function will only be called when the pixel has previously been darkened, so no masking is needed.
|
||||
#define UNDARKENED_PIXEL(pixel, shift) (pixel << shift)
|
||||
|
||||
namespace portapack {
|
||||
|
||||
enum DeviceType {
|
||||
@@ -197,9 +182,6 @@ class IO {
|
||||
}
|
||||
|
||||
void lcd_write_pixel(ui::Color pixel) {
|
||||
if (dark_cover_enabled) {
|
||||
pixel.v = DARKENED_PIXEL(pixel.v, brightness);
|
||||
}
|
||||
lcd_write_data(pixel.v);
|
||||
}
|
||||
|
||||
@@ -208,18 +190,12 @@ class IO {
|
||||
}
|
||||
|
||||
void lcd_write_pixels(ui::Color pixel, size_t n) {
|
||||
if (dark_cover_enabled) {
|
||||
pixel.v = DARKENED_PIXEL(pixel.v, brightness);
|
||||
}
|
||||
while (n--) {
|
||||
lcd_write_data(pixel.v);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_write_pixels_unrolled8(ui::Color pixel, size_t n) {
|
||||
if (dark_cover_enabled) {
|
||||
pixel.v = DARKENED_PIXEL(pixel.v, brightness);
|
||||
}
|
||||
auto v = pixel.v;
|
||||
n >>= 3;
|
||||
while (n--) {
|
||||
@@ -254,13 +230,6 @@ class IO {
|
||||
|
||||
return switches_raw;
|
||||
}
|
||||
bool lcd_normally_black = false;
|
||||
bool dark_cover_enabled = false;
|
||||
uint8_t brightness = 0;
|
||||
bool get_is_normally_black();
|
||||
bool get_dark_cover();
|
||||
uint8_t get_brightness();
|
||||
void update_cached_values();
|
||||
|
||||
uint32_t io_update(const TouchPinsConfig write_value);
|
||||
|
||||
@@ -432,14 +401,6 @@ class IO {
|
||||
halPolledDelay(71); // 90ns
|
||||
const auto value_low = data_read();
|
||||
uint32_t original_value = (value_high << 8) | value_low;
|
||||
|
||||
if (lcd_normally_black) return original_value;
|
||||
|
||||
if (dark_cover_enabled) {
|
||||
// this is read data, so if the fake brightness is enabled AKA get_dark_cover() == true,
|
||||
// then shift to back side AKA UNDARKENED_PIXEL, to prevent read shifted darkern info
|
||||
original_value = UNDARKENED_PIXEL(original_value, brightness);
|
||||
}
|
||||
return original_value;
|
||||
}
|
||||
const auto value_high = data_read();
|
||||
|
||||
@@ -109,7 +109,7 @@ struct ui_config_t {
|
||||
bool hide_clock : 1;
|
||||
bool clock_show_date : 1;
|
||||
bool clkout_enabled : 1;
|
||||
bool apply_fake_brightness : 1; // Fake brightness level, which eventually could be something along the lines of apply_pwm_brightness
|
||||
bool UNUSED_8 : 1; // Deprecated: was apply_fake_brightness
|
||||
bool stealth_mode : 1;
|
||||
bool config_login : 1;
|
||||
bool config_splash : 1;
|
||||
@@ -130,7 +130,7 @@ struct ui_config2_t {
|
||||
bool hide_sd_card : 1;
|
||||
|
||||
bool hide_mute : 1;
|
||||
bool hide_fake_brightness : 1;
|
||||
bool UNUSED_9 : 1; // Deprecated: was hide_fake_brightness
|
||||
bool hide_numeric_battery : 1;
|
||||
bool hide_battery_icon : 1;
|
||||
bool override_batt_calc : 1;
|
||||
@@ -225,8 +225,7 @@ struct data_t {
|
||||
// Rotary encoder dial sensitivity (encoder.cpp/hpp)
|
||||
uint16_t encoder_dial_sensitivity : 4;
|
||||
|
||||
// fake brightness level (not switch, switch is in another place)
|
||||
uint16_t fake_brightness_level : 4;
|
||||
uint16_t UNUSED_5 : 4; // Deprecated: was fake_brightness_level
|
||||
|
||||
// Encoder rotation rate multiplier for larger increments when rotated rapidly
|
||||
uint16_t encoder_rate_multiplier : 4;
|
||||
@@ -299,7 +298,7 @@ struct data_t {
|
||||
frequency_tx_correction(0),
|
||||
|
||||
encoder_dial_sensitivity(DIAL_SENSITIVITY_NORMAL),
|
||||
fake_brightness_level(BRIGHTNESS_50),
|
||||
UNUSED_5(0),
|
||||
encoder_rate_multiplier(1),
|
||||
UNUSED(0),
|
||||
|
||||
@@ -476,7 +475,6 @@ void init() {
|
||||
set_config_mode_storage_direct(config_mode_backup);
|
||||
|
||||
// Firmware upgrade handling - adjust newly defined fields where 0 is an invalid default
|
||||
if (fake_brightness_level() == 0) set_fake_brightness_level(BRIGHTNESS_50);
|
||||
if (menu_color().v == 0) set_menu_color(Color::grey());
|
||||
}
|
||||
|
||||
@@ -671,10 +669,6 @@ bool stealth_mode() {
|
||||
return data->ui_config.stealth_mode;
|
||||
}
|
||||
|
||||
bool apply_fake_brightness() {
|
||||
return data->ui_config.apply_fake_brightness;
|
||||
}
|
||||
|
||||
bool config_login() {
|
||||
return data->ui_config.config_login;
|
||||
}
|
||||
@@ -794,10 +788,6 @@ void set_config_backlight_timer(const backlight_config_t& new_value) {
|
||||
data->ui_config.enable_backlight_timeout = static_cast<uint8_t>(new_value.timeout_enabled());
|
||||
}
|
||||
|
||||
void set_apply_fake_brightness(const bool v) {
|
||||
data->ui_config.apply_fake_brightness = v;
|
||||
}
|
||||
|
||||
uint32_t pocsag_last_address() {
|
||||
return data->pocsag_last_address;
|
||||
}
|
||||
@@ -987,9 +977,6 @@ bool ui_hide_clock() {
|
||||
bool ui_hide_sd_card() {
|
||||
return data->ui_config2.hide_sd_card;
|
||||
}
|
||||
bool ui_hide_fake_brightness() {
|
||||
return data->ui_config2.hide_fake_brightness;
|
||||
}
|
||||
bool ui_hide_numeric_battery() {
|
||||
return data->ui_config2.hide_numeric_battery;
|
||||
}
|
||||
@@ -1044,9 +1031,6 @@ void set_ui_hide_clock(bool v) {
|
||||
void set_ui_hide_sd_card(bool v) {
|
||||
data->ui_config2.hide_sd_card = v;
|
||||
}
|
||||
void set_ui_hide_fake_brightness(bool v) {
|
||||
data->ui_config2.hide_fake_brightness = v;
|
||||
}
|
||||
void set_ui_hide_numeric_battery(bool v) {
|
||||
data->ui_config2.hide_numeric_battery = v;
|
||||
}
|
||||
@@ -1183,25 +1167,6 @@ void set_config_dst(dst_config_t v) {
|
||||
rtc_time::dst_init();
|
||||
}
|
||||
|
||||
// Fake brightness level (switch is in another place)
|
||||
uint8_t fake_brightness_level() {
|
||||
return data->fake_brightness_level;
|
||||
}
|
||||
void set_fake_brightness_level(uint8_t v) {
|
||||
data->fake_brightness_level = v;
|
||||
}
|
||||
|
||||
// Cycle through 4 brightness options: disabled -> enabled/50% -> enabled/25% -> enabled/12.5% -> disabled
|
||||
void toggle_fake_brightness_level() {
|
||||
bool fbe = apply_fake_brightness();
|
||||
if ((!fbe) || (data->fake_brightness_level >= BRIGHTNESS_12p5)) {
|
||||
set_apply_fake_brightness(!fbe);
|
||||
data->fake_brightness_level = BRIGHTNESS_50;
|
||||
} else {
|
||||
data->fake_brightness_level++;
|
||||
}
|
||||
}
|
||||
|
||||
// Menu Color Scheme
|
||||
Color menu_color() {
|
||||
return data->menu_color;
|
||||
|
||||
@@ -139,12 +139,6 @@ typedef union {
|
||||
} dst_config_t;
|
||||
static_assert(sizeof(dst_config_t) == sizeof(uint32_t));
|
||||
|
||||
enum fake_brightness_level_options {
|
||||
BRIGHTNESS_50 = 1,
|
||||
BRIGHTNESS_25 = 2,
|
||||
BRIGHTNESS_12p5 = 3, // 12p5 is 12.5
|
||||
};
|
||||
|
||||
namespace cache {
|
||||
|
||||
/* Set values in cache to sensible defaults. */
|
||||
@@ -289,15 +283,6 @@ uint16_t clkout_freq();
|
||||
dst_config_t config_dst();
|
||||
void set_config_dst(dst_config_t v);
|
||||
|
||||
/* Fake brightness */
|
||||
// switch (if do color change):
|
||||
bool apply_fake_brightness();
|
||||
void set_apply_fake_brightness(const bool v);
|
||||
// level (color change level):
|
||||
uint8_t fake_brightness_level();
|
||||
void set_fake_brightness_level(uint8_t v);
|
||||
void toggle_fake_brightness_level();
|
||||
|
||||
/* Touchscreen threshold */
|
||||
uint16_t touchscreen_threshold();
|
||||
void set_touchscreen_threshold(uint16_t v);
|
||||
@@ -351,7 +336,6 @@ bool ui_hide_camera();
|
||||
bool ui_hide_sleep();
|
||||
bool ui_hide_bias_tee();
|
||||
bool ui_hide_clock();
|
||||
bool ui_hide_fake_brightness();
|
||||
bool ui_hide_numeric_battery();
|
||||
bool ui_hide_battery_icon();
|
||||
bool ui_hide_sd_card();
|
||||
@@ -370,7 +354,6 @@ void set_ui_hide_camera(bool v);
|
||||
void set_ui_hide_sleep(bool v);
|
||||
void set_ui_hide_bias_tee(bool v);
|
||||
void set_ui_hide_clock(bool v);
|
||||
void set_ui_hide_fake_brightness(bool v);
|
||||
void set_ui_hide_numeric_battery(bool v);
|
||||
void set_ui_hide_battery_icon(bool v);
|
||||
void set_ui_hide_sd_card(bool v);
|
||||
|
||||
@@ -564,16 +564,14 @@ void LiveDateTime::set_seconds_enabled(bool new_value) {
|
||||
|
||||
/* BigFrequency **********************************************************/
|
||||
|
||||
BigFrequency::BigFrequency(
|
||||
Rect parent_rect,
|
||||
rf::Frequency frequency)
|
||||
: Widget{parent_rect},
|
||||
_frequency{frequency} {
|
||||
}
|
||||
BigFrequency::BigFrequency(Rect parent_rect, rf::Frequency frequency)
|
||||
: Widget{parent_rect}, _frequency{frequency} {}
|
||||
|
||||
void BigFrequency::set(const rf::Frequency frequency) {
|
||||
_frequency = frequency;
|
||||
set_dirty();
|
||||
if (_frequency != frequency) {
|
||||
_frequency = frequency;
|
||||
set_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void BigFrequency::paint(Painter& painter) {
|
||||
@@ -583,63 +581,59 @@ void BigFrequency::paint(Painter& painter) {
|
||||
Point digit_pos;
|
||||
ui::Color segment_color;
|
||||
|
||||
if (_frequency != _previous_frequency) {
|
||||
_previous_frequency = _frequency;
|
||||
rf::Frequency frequency{_frequency};
|
||||
const auto rect = screen_rect(); // why not use screen_rect() directly for width, ...? it may be too small, but ...
|
||||
|
||||
rf::Frequency frequency{_frequency};
|
||||
const auto rect = screen_rect(); // why not use screen_rect() directly for width, ...? it may be too small, but ...
|
||||
// Erase
|
||||
painter.fill_rectangle(
|
||||
{{0, rect.location().y()}, {screen_width, 52}},
|
||||
Theme::getInstance()->bg_darkest->background);
|
||||
|
||||
// Erase
|
||||
painter.fill_rectangle(
|
||||
{{0, rect.location().y()}, {screen_width, 52}},
|
||||
Theme::getInstance()->bg_darkest->background);
|
||||
// Prepare digits
|
||||
if (!frequency) {
|
||||
digits.fill(10); // ----.---
|
||||
digit_pos = {(screen_width - ((7 * digit_width) + 8)) / 2, rect.location().y()};
|
||||
} else {
|
||||
frequency /= 1000; // GMMM.KKK(uuu)
|
||||
|
||||
// Prepare digits
|
||||
if (!frequency) {
|
||||
digits.fill(10); // ----.---
|
||||
digit_pos = {(screen_width - ((7 * digit_width) + 8)) / 2, rect.location().y()};
|
||||
} else {
|
||||
frequency /= 1000; // GMMM.KKK(uuu)
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
digits[6 - i] = frequency % 10;
|
||||
frequency /= 10;
|
||||
}
|
||||
|
||||
// Remove leading zeros
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!digits[i])
|
||||
digits[i] = 16; // "Don't draw" code
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
digit_pos = {(Coord)(screen_width - ((7 * digit_width) + 8) - (i * digit_width)) / 2, rect.location().y()};
|
||||
for (i = 0; i < 7; i++) {
|
||||
digits[6 - i] = frequency % 10;
|
||||
frequency /= 10;
|
||||
}
|
||||
|
||||
segment_color = style().foreground;
|
||||
// Remove leading zeros
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!digits[i])
|
||||
digits[i] = 16; // "Don't draw" code
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw
|
||||
for (i = 0; i < 7; i++) {
|
||||
digit = digits[i];
|
||||
digit_pos = {(Coord)(screen_width - ((7 * digit_width) + 8) - (i * digit_width)) / 2, rect.location().y()};
|
||||
}
|
||||
|
||||
if (digit < 16) {
|
||||
digit_def = segment_font[(uint8_t)digit];
|
||||
segment_color = style().foreground;
|
||||
|
||||
for (size_t s = 0; s < 7; s++) {
|
||||
if (digit_def & 1)
|
||||
painter.fill_rectangle({digit_pos + segments[s].location(), segments[s].size()}, segment_color);
|
||||
digit_def >>= 1;
|
||||
}
|
||||
// Draw
|
||||
for (i = 0; i < 7; i++) {
|
||||
digit = digits[i];
|
||||
|
||||
if (digit < 16) {
|
||||
digit_def = segment_font[(uint8_t)digit];
|
||||
|
||||
for (size_t s = 0; s < 7; s++) {
|
||||
if (digit_def & 1)
|
||||
painter.fill_rectangle({digit_pos + segments[s].location(), segments[s].size()}, segment_color);
|
||||
digit_def >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 3) {
|
||||
// Dot
|
||||
painter.fill_rectangle({digit_pos + Point(34, 48), {4, 4}}, segment_color);
|
||||
digit_pos += {(digit_width + 8), 0};
|
||||
} else {
|
||||
digit_pos += {digit_width, 0};
|
||||
}
|
||||
if (i == 3) {
|
||||
// Dot
|
||||
painter.fill_rectangle({digit_pos + Point(34, 48), {4, 4}}, segment_color);
|
||||
digit_pos += {(digit_width + 8), 0};
|
||||
} else {
|
||||
digit_pos += {digit_width, 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,6 @@ class BigFrequency : public Widget {
|
||||
|
||||
private:
|
||||
rf::Frequency _frequency;
|
||||
rf::Frequency _previous_frequency{~0LL};
|
||||
|
||||
static constexpr Dim digit_width = 32;
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
The schematic files of H4M Pro are the same as H4M. The only difference is the use of an 18650 battery holder. If you have any questions about them, please feel free to contact me. Our email address is support@opensourcesdrlab.com
|
||||
@@ -0,0 +1,16 @@
|
||||
M48
|
||||
METRIC,LZ,000.000
|
||||
;FILE_FORMAT=3:3
|
||||
;TYPE=NON_PLATED
|
||||
;Layer: NPTH_Through
|
||||
;EasyEDA v6.5.46, 2026-07-24 11:31:18
|
||||
;10
|
||||
;Gerber Generator version 0.2
|
||||
;Holesize 1 = 2.400 mm
|
||||
T01C2.400
|
||||
%
|
||||
G05
|
||||
G90
|
||||
T01
|
||||
X-077153Y008000
|
||||
M30
|
||||
@@ -0,0 +1,497 @@
|
||||
M48
|
||||
METRIC,LZ,000.000
|
||||
;FILE_FORMAT=3:3
|
||||
;TYPE=PLATED
|
||||
;Layer: PTH_Through
|
||||
;EasyEDA v6.5.46, 2026-07-24 11:31:18
|
||||
;10
|
||||
;Gerber Generator version 0.2
|
||||
;Holesize 1 = 0.310 mm
|
||||
T01C0.310
|
||||
;Holesize 2 = 0.400 mm
|
||||
T02C0.400
|
||||
;Holesize 3 = 0.500 mm
|
||||
T03C0.500
|
||||
;Holesize 4 = 0.800 mm
|
||||
T04C0.800
|
||||
;Holesize 5 = 0.801 mm
|
||||
T05C0.801
|
||||
;Holesize 6 = 0.901 mm
|
||||
T06C0.901
|
||||
;Holesize 7 = 0.915 mm
|
||||
T07C0.915
|
||||
;Holesize 8 = 1.000 mm
|
||||
T08C1.000
|
||||
;Holesize 9 = 1.001 mm
|
||||
T09C1.001
|
||||
;Holesize 10 = 1.201 mm
|
||||
T10C1.201
|
||||
;Holesize 11 = 1.450 mm
|
||||
T11C1.450
|
||||
;Holesize 12 = 1.501 mm
|
||||
T12C1.501
|
||||
;Holesize 13 = 1.600 mm
|
||||
T13C1.600
|
||||
;Holesize 14 = 3.200 mm
|
||||
T14C3.200
|
||||
;Holesize 15 = 3.300 mm
|
||||
T15C3.300
|
||||
;Holesize 16 = 4.000 mm
|
||||
T16C4.000
|
||||
%
|
||||
G05
|
||||
G90
|
||||
T01
|
||||
X-088930Y002230
|
||||
X-088920Y001501
|
||||
T02
|
||||
X-065866Y-026064
|
||||
X-065866Y-024804
|
||||
X-064616Y-026064
|
||||
X-064616Y-024814
|
||||
X-103345Y-058046
|
||||
X-101770Y-058694
|
||||
X-104895Y-058681
|
||||
X-105606Y-060307
|
||||
X-101148Y-060256
|
||||
X-104895Y-061780
|
||||
X-103345Y-062440
|
||||
X-101783Y-061793
|
||||
X008643Y-057983
|
||||
X010218Y-058630
|
||||
X007094Y-058618
|
||||
X006383Y-060243
|
||||
X010840Y-060192
|
||||
X007094Y-061716
|
||||
X008643Y-062377
|
||||
X010205Y-061729
|
||||
X008605Y009124
|
||||
X010180Y008476
|
||||
X007056Y008489
|
||||
X006345Y006864
|
||||
X010802Y006914
|
||||
X007056Y005390
|
||||
X008605Y004730
|
||||
X010167Y005378
|
||||
X-103485Y008896
|
||||
X-101910Y008248
|
||||
X-105034Y008261
|
||||
X-105746Y006635
|
||||
X-101288Y006686
|
||||
X-105034Y005162
|
||||
X-103485Y004501
|
||||
X-101923Y005149
|
||||
X-052607Y-060457
|
||||
X-053627Y-060447
|
||||
X-088017Y-013997
|
||||
X-089057Y-014837
|
||||
X-069077Y-011847
|
||||
X-068037Y-011857
|
||||
X-066897Y-011867
|
||||
X-065667Y-011887
|
||||
X-064587Y-011877
|
||||
X-078267Y-047197
|
||||
X-071547Y-036317
|
||||
X-020277Y-018847
|
||||
X-020277Y004343
|
||||
X-040397Y-025987
|
||||
X-040575Y-032758
|
||||
X-029717Y-041107
|
||||
X-020287Y-034967
|
||||
X-021067Y-026607
|
||||
X-028927Y-018647
|
||||
X-030457Y-018647
|
||||
X-065667Y-021107
|
||||
X-057456Y-024088
|
||||
X-060737Y-024377
|
||||
X-059917Y-008637
|
||||
X-059927Y-023877
|
||||
X-104564Y-055198
|
||||
X-106453Y-018834
|
||||
X-100174Y-013237
|
||||
X-099374Y-013237
|
||||
X-099374Y-012368
|
||||
X-100174Y-012368
|
||||
X-103054Y-010817
|
||||
X-103044Y-010018
|
||||
X011536Y-051637
|
||||
X011536Y-050037
|
||||
X011536Y-048617
|
||||
X-012464Y-041857
|
||||
X-010964Y-041857
|
||||
X-009464Y-041857
|
||||
X-007964Y-041857
|
||||
X-006464Y-041857
|
||||
X-050564Y009283
|
||||
X-052064Y009283
|
||||
X-049064Y009283
|
||||
X-059564Y009283
|
||||
X-047564Y009283
|
||||
X-053564Y009283
|
||||
X-055064Y009283
|
||||
X-046064Y009283
|
||||
X-081967Y010163
|
||||
X-080467Y010163
|
||||
X011536Y-047217
|
||||
X011536Y-046017
|
||||
X011516Y-044857
|
||||
X011536Y-043527
|
||||
X011366Y-055957
|
||||
X011356Y-057457
|
||||
X005536Y-062948
|
||||
X004036Y-062937
|
||||
X002536Y-062927
|
||||
X001036Y-062937
|
||||
X-000464Y-062937
|
||||
X-001964Y-062948
|
||||
X-003464Y-062957
|
||||
X-004964Y-062948
|
||||
X-006464Y-062948
|
||||
X-007964Y-062957
|
||||
X-009464Y-062957
|
||||
X-010964Y-062957
|
||||
X-012464Y-062957
|
||||
X-013964Y-062957
|
||||
X-015464Y-062957
|
||||
X-016964Y-062967
|
||||
X-103064Y-056187
|
||||
X-101564Y-057307
|
||||
X-100364Y-058458
|
||||
X-106444Y-055358
|
||||
X-106464Y-053857
|
||||
X-106464Y-052358
|
||||
X-106464Y-050857
|
||||
X-106464Y-049358
|
||||
X-106464Y-047857
|
||||
X-104664Y001342
|
||||
X-106164Y001342
|
||||
X-027764Y009298
|
||||
X-030577Y009273
|
||||
X-032564Y009288
|
||||
X-035564Y009298
|
||||
X-022364Y-019708
|
||||
X-004964Y-041857
|
||||
X-001964Y-041857
|
||||
X-000464Y-041857
|
||||
X001036Y-041857
|
||||
X011536Y-041857
|
||||
X010036Y-041857
|
||||
X008536Y-041857
|
||||
X004036Y-041857
|
||||
X002536Y-041857
|
||||
X-102264Y001342
|
||||
X-100564Y001342
|
||||
X-098864Y001342
|
||||
X-106164Y002843
|
||||
X-104664Y002843
|
||||
X-102464Y003243
|
||||
X-100664Y004243
|
||||
X-099664Y005843
|
||||
X-099464Y007442
|
||||
X-106464Y-031358
|
||||
X-106464Y-032857
|
||||
X-106464Y-034358
|
||||
X-106464Y-035857
|
||||
X-106464Y-037358
|
||||
X-106464Y-038857
|
||||
X-106464Y-040358
|
||||
X-106464Y-041857
|
||||
X-106464Y-043358
|
||||
X-106464Y-044857
|
||||
X-106464Y-046358
|
||||
X-106364Y-056657
|
||||
X-106364Y-057957
|
||||
X-099164Y-059557
|
||||
X-098264Y-060557
|
||||
X-097364Y-061457
|
||||
X-096464Y-062358
|
||||
X-100964Y-063358
|
||||
X-099464Y-063358
|
||||
X-097964Y-063358
|
||||
X-096464Y-063358
|
||||
X-094964Y-063358
|
||||
X-093464Y-063358
|
||||
X-091964Y-063358
|
||||
X-090464Y-063358
|
||||
X-088964Y-063358
|
||||
X-087464Y-063358
|
||||
X-085964Y-063358
|
||||
X-084464Y-063358
|
||||
X-082964Y-063358
|
||||
X-081464Y-063358
|
||||
X-079964Y-063358
|
||||
X-078464Y-063358
|
||||
X-076964Y-063358
|
||||
X-075464Y-063358
|
||||
X-073964Y-063358
|
||||
X-072464Y-063358
|
||||
X-070964Y-063358
|
||||
X-069464Y-063358
|
||||
X-067964Y-063358
|
||||
X-066464Y-063358
|
||||
X-064964Y-063358
|
||||
X-063464Y-063358
|
||||
X-061964Y-063358
|
||||
X-060464Y-063358
|
||||
X-058964Y-063358
|
||||
X-057464Y-063358
|
||||
X-055964Y-063358
|
||||
X-054464Y-063358
|
||||
X-052964Y-063358
|
||||
X-051464Y-063358
|
||||
X-049964Y-063358
|
||||
X-048464Y-063358
|
||||
X-046964Y-063358
|
||||
X-045464Y-063358
|
||||
X-043964Y-063358
|
||||
X-042464Y-063358
|
||||
X-040964Y-063358
|
||||
X-039464Y-063358
|
||||
X-037964Y-063358
|
||||
X-036464Y-063358
|
||||
X-034957Y-063358
|
||||
X-033457Y-063358
|
||||
X-031957Y-063358
|
||||
X-030457Y-063358
|
||||
X-028957Y-063358
|
||||
X-027417Y-063359
|
||||
X-025847Y-063347
|
||||
X-024464Y-062957
|
||||
X-022964Y-062957
|
||||
X-021464Y-062957
|
||||
X-019964Y-062957
|
||||
X-018464Y-062957
|
||||
X-099467Y010163
|
||||
X-097967Y010163
|
||||
X-096467Y010163
|
||||
X-094967Y010163
|
||||
X-089467Y010163
|
||||
X-087967Y010163
|
||||
X-086467Y010163
|
||||
X-083467Y010163
|
||||
X-084967Y010163
|
||||
X-078967Y010163
|
||||
X-077387Y010143
|
||||
X-075927Y010133
|
||||
X-074687Y010153
|
||||
X-072967Y010163
|
||||
X-071467Y010163
|
||||
X-069967Y010163
|
||||
X-068467Y010163
|
||||
X-066967Y010163
|
||||
X-065467Y010163
|
||||
X-063967Y010163
|
||||
X-062467Y010163
|
||||
X-058064Y009283
|
||||
X-056564Y009283
|
||||
X-044564Y009283
|
||||
X-043064Y009288
|
||||
X-041564Y009288
|
||||
X-040064Y009288
|
||||
X-038564Y009288
|
||||
X-037064Y009288
|
||||
X-025247Y009323
|
||||
X-022664Y009288
|
||||
X-021164Y009288
|
||||
X-019364Y009288
|
||||
X-017864Y009288
|
||||
X-016364Y009288
|
||||
X-014864Y009288
|
||||
X-013364Y009288
|
||||
X-011864Y009288
|
||||
X-010364Y009288
|
||||
X-008864Y009288
|
||||
X-007364Y009288
|
||||
X-005864Y009288
|
||||
X-004364Y009288
|
||||
X-002864Y009288
|
||||
X-001364Y009288
|
||||
X000136Y009288
|
||||
X001636Y009288
|
||||
X003136Y009288
|
||||
X004636Y009288
|
||||
X-025866Y-018414
|
||||
X-025786Y-017264
|
||||
X-026606Y-016524
|
||||
X-027546Y-015804
|
||||
X-024636Y-018204
|
||||
X-106464Y-029857
|
||||
X-106464Y-028358
|
||||
X-106464Y-026358
|
||||
X-106464Y-024857
|
||||
X-106363Y-013064
|
||||
X-106443Y-018144
|
||||
X-106553Y-013824
|
||||
X-099553Y-007464
|
||||
X-104963Y-016144
|
||||
X-038810Y-022149
|
||||
X-094086Y-032454
|
||||
X-040996Y-022914
|
||||
X-104146Y-032414
|
||||
X-041796Y-023694
|
||||
X-104186Y-035004
|
||||
X-042626Y-024474
|
||||
X-094056Y-035014
|
||||
X-043422Y-025258
|
||||
X-094056Y-037584
|
||||
X-042626Y-025944
|
||||
X-104186Y-037524
|
||||
X-041946Y-026694
|
||||
X-043396Y-027454
|
||||
X-104176Y-040064
|
||||
X-044216Y-028244
|
||||
X-093676Y-040754
|
||||
X-044956Y-029034
|
||||
X-044186Y-029774
|
||||
X-043506Y-030644
|
||||
X-045006Y-031364
|
||||
X-090186Y-058954
|
||||
X-092766Y-053544
|
||||
X-091236Y-051324
|
||||
X-044166Y-032034
|
||||
X-072396Y-059084
|
||||
X-043496Y-032834
|
||||
X-071326Y-051254
|
||||
X-042726Y-033604
|
||||
X-067296Y-048904
|
||||
X-094086Y-029934
|
||||
X-094086Y-027394
|
||||
X-094056Y-024894
|
||||
X-094086Y-022334
|
||||
X-045776Y-034984
|
||||
X-037596Y-021174
|
||||
X-045768Y-037527
|
||||
X-035266Y-018514
|
||||
X-036386Y-019584
|
||||
X-036936Y-018674
|
||||
X-033856Y-015154
|
||||
X-087186Y-018554
|
||||
X-033236Y-014554
|
||||
X-079606Y-013464
|
||||
X-032576Y-013954
|
||||
X-031966Y-013294
|
||||
X-099466Y-018304
|
||||
X-031376Y-012654
|
||||
X-056086Y-036104
|
||||
X-005239Y-047337
|
||||
X-005236Y-048444
|
||||
X-050366Y-042604
|
||||
X-005215Y-049535
|
||||
X-007606Y-052754
|
||||
X-005196Y-053934
|
||||
X-005189Y-055027
|
||||
X-045756Y-040054
|
||||
X-005166Y-056124
|
||||
X-051616Y-040034
|
||||
X-053656Y-035944
|
||||
X-056726Y-037524
|
||||
X-056006Y-042604
|
||||
X-050846Y-021284
|
||||
X-074966Y-049034
|
||||
X-069826Y-045014
|
||||
X-026706Y-044984
|
||||
X-068656Y-045694
|
||||
X-025966Y-045694
|
||||
X-072126Y-024584
|
||||
X-072116Y-026684
|
||||
X-075176Y-025914
|
||||
X-073566Y-031704
|
||||
X-091667Y-005777
|
||||
X-091667Y-003097
|
||||
X-088187Y003323
|
||||
X-087527Y003303
|
||||
X-088947Y000733
|
||||
X-088957Y000103
|
||||
X-072057Y-006757
|
||||
X-074327Y-006797
|
||||
X-074327Y-005817
|
||||
X-074327Y-004707
|
||||
X-074327Y-003647
|
||||
X-072067Y-005837
|
||||
X-072067Y-004707
|
||||
X-072077Y-003627
|
||||
X-072047Y-002657
|
||||
X-074327Y-002667
|
||||
X-102637Y-012197
|
||||
X-089997Y-006867
|
||||
X-098257Y-008057
|
||||
X-104077Y-007837
|
||||
X-104027Y-047287
|
||||
X-009987Y-058887
|
||||
X-026457Y-058877
|
||||
X-064777Y-058807
|
||||
X-017597Y-057937
|
||||
X-066337Y-056797
|
||||
X-015047Y-057287
|
||||
X-060747Y-007997
|
||||
X-014017Y-045807
|
||||
X-015837Y-050907
|
||||
X-015837Y-008637
|
||||
X-014007Y-007987
|
||||
X-058897Y-023907
|
||||
X-011707Y-050947
|
||||
X-019397Y-055467
|
||||
T03
|
||||
X-082557Y-047197
|
||||
X-052360Y-048694
|
||||
X-062517Y-048777
|
||||
X-020310Y-043744
|
||||
X-020260Y-013224
|
||||
T04
|
||||
X-088447Y006673G85X-088447Y006673
|
||||
X-085907Y006673G85X-085907Y006673
|
||||
X-090987Y006673G85X-090987Y006673
|
||||
X-059166Y-060304G85X-059166Y-060304
|
||||
X-056626Y-060304G85X-056626Y-060304
|
||||
X-061706Y-060304G85X-061706Y-060304
|
||||
T05
|
||||
X-094757Y-018407
|
||||
T06
|
||||
X-004727Y-009287
|
||||
X-013657Y006183
|
||||
T07
|
||||
X-090816Y-048399
|
||||
X-088276Y-048399
|
||||
T08
|
||||
X-034027Y005743G85X-034027Y005743
|
||||
X-034027Y003203G85X-034027Y003203
|
||||
X-026407Y005743G85X-026407Y005743
|
||||
X-023867Y003203G85X-023867Y003203
|
||||
X-026407Y003203G85X-026407Y003203
|
||||
X-028947Y003203G85X-028947Y003203
|
||||
X-023867Y005743G85X-023867Y005743
|
||||
X-028947Y005743G85X-028947Y005743
|
||||
X-031487Y003203G85X-031487Y003203
|
||||
X-031487Y005743G85X-031487Y005743
|
||||
T09
|
||||
X-091456Y-017046
|
||||
T10
|
||||
X-091456Y-011787
|
||||
T11
|
||||
X-092556Y-020241G85X-092559Y-020237
|
||||
X-082587Y-010453G85X-082587Y-010453
|
||||
X-087304Y-027713G85X-087304Y-027713
|
||||
X-079606Y-020015G85X-079606Y-020015
|
||||
X-079830Y-032967G85X-079830Y-032967
|
||||
X-071083Y-034332G85X-071083Y-034332
|
||||
X-089800Y-042754G85X-089800Y-042754
|
||||
T12
|
||||
X-105088Y-004465G85X-105083Y-004465
|
||||
X-097976Y-004465G85X-097971Y-004465
|
||||
T13
|
||||
X-089376Y-023421
|
||||
X-083012Y-029785
|
||||
T14
|
||||
X-096800Y-015997
|
||||
X-096800Y-015997
|
||||
T15
|
||||
X-103310Y-060269G85X-103305Y-060269
|
||||
X008679Y-060205G85X008684Y-060205
|
||||
X008641Y006902G85X008646Y006902
|
||||
X-103449Y006673G85X-103444Y006673
|
||||
T16
|
||||
X-075587Y-015997
|
||||
X-075587Y-037210
|
||||
X-075587Y-015997
|
||||
X-075587Y-037210
|
||||
M30
|
||||
@@ -0,0 +1,448 @@
|
||||
M48
|
||||
METRIC,LZ,000.000
|
||||
;FILE_FORMAT=3:3
|
||||
;TYPE=PLATED
|
||||
;Layer: PTH_Through_Via
|
||||
;EasyEDA v6.5.46, 2026-07-24 11:31:18
|
||||
;10
|
||||
;Gerber Generator version 0.2
|
||||
;Holesize 1 = 0.310 mm
|
||||
T01C0.310
|
||||
;Holesize 2 = 0.400 mm
|
||||
T02C0.400
|
||||
;Holesize 3 = 0.500 mm
|
||||
T03C0.500
|
||||
;Holesize 4 = 0.801 mm
|
||||
T04C0.801
|
||||
;Holesize 5 = 0.901 mm
|
||||
T05C0.901
|
||||
;Holesize 6 = 1.001 mm
|
||||
T06C1.001
|
||||
;Holesize 7 = 1.201 mm
|
||||
T07C1.201
|
||||
;Holesize 8 = 1.600 mm
|
||||
T08C1.600
|
||||
;Holesize 9 = 3.200 mm
|
||||
T09C3.200
|
||||
;Holesize 10 = 4.000 mm
|
||||
T10C4.000
|
||||
%
|
||||
G05
|
||||
G90
|
||||
T01
|
||||
X-088930Y002230
|
||||
X-088920Y001501
|
||||
T02
|
||||
X-065866Y-026064
|
||||
X-065866Y-024804
|
||||
X-064616Y-026064
|
||||
X-064616Y-024814
|
||||
X-103345Y-058046
|
||||
X-101770Y-058694
|
||||
X-104895Y-058681
|
||||
X-105606Y-060307
|
||||
X-101148Y-060256
|
||||
X-104895Y-061780
|
||||
X-103345Y-062440
|
||||
X-101783Y-061793
|
||||
X008643Y-057983
|
||||
X010218Y-058630
|
||||
X007094Y-058618
|
||||
X006383Y-060243
|
||||
X010840Y-060192
|
||||
X007094Y-061716
|
||||
X008643Y-062377
|
||||
X010205Y-061729
|
||||
X008605Y009124
|
||||
X010180Y008476
|
||||
X007056Y008489
|
||||
X006345Y006864
|
||||
X010802Y006914
|
||||
X007056Y005390
|
||||
X008605Y004730
|
||||
X010167Y005378
|
||||
X-103485Y008896
|
||||
X-101910Y008248
|
||||
X-105034Y008261
|
||||
X-105746Y006635
|
||||
X-101288Y006686
|
||||
X-105034Y005162
|
||||
X-103485Y004501
|
||||
X-101923Y005149
|
||||
X-052607Y-060457
|
||||
X-053627Y-060447
|
||||
X-088017Y-013997
|
||||
X-089057Y-014837
|
||||
X-069077Y-011847
|
||||
X-068037Y-011857
|
||||
X-066897Y-011867
|
||||
X-065667Y-011887
|
||||
X-064587Y-011877
|
||||
X-078267Y-047197
|
||||
X-071547Y-036317
|
||||
X-020277Y-018847
|
||||
X-020277Y004343
|
||||
X-040397Y-025987
|
||||
X-040575Y-032758
|
||||
X-029717Y-041107
|
||||
X-020287Y-034967
|
||||
X-021067Y-026607
|
||||
X-028927Y-018647
|
||||
X-030457Y-018647
|
||||
X-065667Y-021107
|
||||
X-057456Y-024088
|
||||
X-060737Y-024377
|
||||
X-059917Y-008637
|
||||
X-059927Y-023877
|
||||
X-104564Y-055198
|
||||
X-106453Y-018834
|
||||
X-100174Y-013237
|
||||
X-099374Y-013237
|
||||
X-099374Y-012368
|
||||
X-100174Y-012368
|
||||
X-103054Y-010817
|
||||
X-103044Y-010018
|
||||
X011536Y-051637
|
||||
X011536Y-050037
|
||||
X011536Y-048617
|
||||
X-012464Y-041857
|
||||
X-010964Y-041857
|
||||
X-009464Y-041857
|
||||
X-007964Y-041857
|
||||
X-006464Y-041857
|
||||
X-050564Y009283
|
||||
X-052064Y009283
|
||||
X-049064Y009283
|
||||
X-059564Y009283
|
||||
X-047564Y009283
|
||||
X-053564Y009283
|
||||
X-055064Y009283
|
||||
X-046064Y009283
|
||||
X-081967Y010163
|
||||
X-080467Y010163
|
||||
X011536Y-047217
|
||||
X011536Y-046017
|
||||
X011516Y-044857
|
||||
X011536Y-043527
|
||||
X011366Y-055957
|
||||
X011356Y-057457
|
||||
X005536Y-062948
|
||||
X004036Y-062937
|
||||
X002536Y-062927
|
||||
X001036Y-062937
|
||||
X-000464Y-062937
|
||||
X-001964Y-062948
|
||||
X-003464Y-062957
|
||||
X-004964Y-062948
|
||||
X-006464Y-062948
|
||||
X-007964Y-062957
|
||||
X-009464Y-062957
|
||||
X-010964Y-062957
|
||||
X-012464Y-062957
|
||||
X-013964Y-062957
|
||||
X-015464Y-062957
|
||||
X-016964Y-062967
|
||||
X-103064Y-056187
|
||||
X-101564Y-057307
|
||||
X-100364Y-058458
|
||||
X-106444Y-055358
|
||||
X-106464Y-053857
|
||||
X-106464Y-052358
|
||||
X-106464Y-050857
|
||||
X-106464Y-049358
|
||||
X-106464Y-047857
|
||||
X-104664Y001342
|
||||
X-106164Y001342
|
||||
X-027764Y009298
|
||||
X-030577Y009273
|
||||
X-032564Y009288
|
||||
X-035564Y009298
|
||||
X-022364Y-019708
|
||||
X-004964Y-041857
|
||||
X-001964Y-041857
|
||||
X-000464Y-041857
|
||||
X001036Y-041857
|
||||
X011536Y-041857
|
||||
X010036Y-041857
|
||||
X008536Y-041857
|
||||
X004036Y-041857
|
||||
X002536Y-041857
|
||||
X-102264Y001342
|
||||
X-100564Y001342
|
||||
X-098864Y001342
|
||||
X-106164Y002843
|
||||
X-104664Y002843
|
||||
X-102464Y003243
|
||||
X-100664Y004243
|
||||
X-099664Y005843
|
||||
X-099464Y007442
|
||||
X-106464Y-031358
|
||||
X-106464Y-032857
|
||||
X-106464Y-034358
|
||||
X-106464Y-035857
|
||||
X-106464Y-037358
|
||||
X-106464Y-038857
|
||||
X-106464Y-040358
|
||||
X-106464Y-041857
|
||||
X-106464Y-043358
|
||||
X-106464Y-044857
|
||||
X-106464Y-046358
|
||||
X-106364Y-056657
|
||||
X-106364Y-057957
|
||||
X-099164Y-059557
|
||||
X-098264Y-060557
|
||||
X-097364Y-061457
|
||||
X-096464Y-062358
|
||||
X-100964Y-063358
|
||||
X-099464Y-063358
|
||||
X-097964Y-063358
|
||||
X-096464Y-063358
|
||||
X-094964Y-063358
|
||||
X-093464Y-063358
|
||||
X-091964Y-063358
|
||||
X-090464Y-063358
|
||||
X-088964Y-063358
|
||||
X-087464Y-063358
|
||||
X-085964Y-063358
|
||||
X-084464Y-063358
|
||||
X-082964Y-063358
|
||||
X-081464Y-063358
|
||||
X-079964Y-063358
|
||||
X-078464Y-063358
|
||||
X-076964Y-063358
|
||||
X-075464Y-063358
|
||||
X-073964Y-063358
|
||||
X-072464Y-063358
|
||||
X-070964Y-063358
|
||||
X-069464Y-063358
|
||||
X-067964Y-063358
|
||||
X-066464Y-063358
|
||||
X-064964Y-063358
|
||||
X-063464Y-063358
|
||||
X-061964Y-063358
|
||||
X-060464Y-063358
|
||||
X-058964Y-063358
|
||||
X-057464Y-063358
|
||||
X-055964Y-063358
|
||||
X-054464Y-063358
|
||||
X-052964Y-063358
|
||||
X-051464Y-063358
|
||||
X-049964Y-063358
|
||||
X-048464Y-063358
|
||||
X-046964Y-063358
|
||||
X-045464Y-063358
|
||||
X-043964Y-063358
|
||||
X-042464Y-063358
|
||||
X-040964Y-063358
|
||||
X-039464Y-063358
|
||||
X-037964Y-063358
|
||||
X-036464Y-063358
|
||||
X-034957Y-063358
|
||||
X-033457Y-063358
|
||||
X-031957Y-063358
|
||||
X-030457Y-063358
|
||||
X-028957Y-063358
|
||||
X-027417Y-063359
|
||||
X-025847Y-063347
|
||||
X-024464Y-062957
|
||||
X-022964Y-062957
|
||||
X-021464Y-062957
|
||||
X-019964Y-062957
|
||||
X-018464Y-062957
|
||||
X-099467Y010163
|
||||
X-097967Y010163
|
||||
X-096467Y010163
|
||||
X-094967Y010163
|
||||
X-089467Y010163
|
||||
X-087967Y010163
|
||||
X-086467Y010163
|
||||
X-083467Y010163
|
||||
X-084967Y010163
|
||||
X-078967Y010163
|
||||
X-077387Y010143
|
||||
X-075927Y010133
|
||||
X-074687Y010153
|
||||
X-072967Y010163
|
||||
X-071467Y010163
|
||||
X-069967Y010163
|
||||
X-068467Y010163
|
||||
X-066967Y010163
|
||||
X-065467Y010163
|
||||
X-063967Y010163
|
||||
X-062467Y010163
|
||||
X-058064Y009283
|
||||
X-056564Y009283
|
||||
X-044564Y009283
|
||||
X-043064Y009288
|
||||
X-041564Y009288
|
||||
X-040064Y009288
|
||||
X-038564Y009288
|
||||
X-037064Y009288
|
||||
X-025247Y009323
|
||||
X-022664Y009288
|
||||
X-021164Y009288
|
||||
X-019364Y009288
|
||||
X-017864Y009288
|
||||
X-016364Y009288
|
||||
X-014864Y009288
|
||||
X-013364Y009288
|
||||
X-011864Y009288
|
||||
X-010364Y009288
|
||||
X-008864Y009288
|
||||
X-007364Y009288
|
||||
X-005864Y009288
|
||||
X-004364Y009288
|
||||
X-002864Y009288
|
||||
X-001364Y009288
|
||||
X000136Y009288
|
||||
X001636Y009288
|
||||
X003136Y009288
|
||||
X004636Y009288
|
||||
X-025866Y-018414
|
||||
X-025786Y-017264
|
||||
X-026606Y-016524
|
||||
X-027546Y-015804
|
||||
X-024636Y-018204
|
||||
X-106464Y-029857
|
||||
X-106464Y-028358
|
||||
X-106464Y-026358
|
||||
X-106464Y-024857
|
||||
X-106363Y-013064
|
||||
X-106443Y-018144
|
||||
X-106553Y-013824
|
||||
X-099553Y-007464
|
||||
X-104963Y-016144
|
||||
X-038810Y-022149
|
||||
X-094086Y-032454
|
||||
X-040996Y-022914
|
||||
X-104146Y-032414
|
||||
X-041796Y-023694
|
||||
X-104186Y-035004
|
||||
X-042626Y-024474
|
||||
X-094056Y-035014
|
||||
X-043422Y-025258
|
||||
X-094056Y-037584
|
||||
X-042626Y-025944
|
||||
X-104186Y-037524
|
||||
X-041946Y-026694
|
||||
X-043396Y-027454
|
||||
X-104176Y-040064
|
||||
X-044216Y-028244
|
||||
X-093676Y-040754
|
||||
X-044956Y-029034
|
||||
X-044186Y-029774
|
||||
X-043506Y-030644
|
||||
X-045006Y-031364
|
||||
X-090186Y-058954
|
||||
X-092766Y-053544
|
||||
X-091236Y-051324
|
||||
X-044166Y-032034
|
||||
X-072396Y-059084
|
||||
X-043496Y-032834
|
||||
X-071326Y-051254
|
||||
X-042726Y-033604
|
||||
X-067296Y-048904
|
||||
X-094086Y-029934
|
||||
X-094086Y-027394
|
||||
X-094056Y-024894
|
||||
X-094086Y-022334
|
||||
X-045776Y-034984
|
||||
X-037596Y-021174
|
||||
X-045768Y-037527
|
||||
X-035266Y-018514
|
||||
X-036386Y-019584
|
||||
X-036936Y-018674
|
||||
X-033856Y-015154
|
||||
X-087186Y-018554
|
||||
X-033236Y-014554
|
||||
X-079606Y-013464
|
||||
X-032576Y-013954
|
||||
X-031966Y-013294
|
||||
X-099466Y-018304
|
||||
X-031376Y-012654
|
||||
X-056086Y-036104
|
||||
X-005239Y-047337
|
||||
X-005236Y-048444
|
||||
X-050366Y-042604
|
||||
X-005215Y-049535
|
||||
X-007606Y-052754
|
||||
X-005196Y-053934
|
||||
X-005189Y-055027
|
||||
X-045756Y-040054
|
||||
X-005166Y-056124
|
||||
X-051616Y-040034
|
||||
X-053656Y-035944
|
||||
X-056726Y-037524
|
||||
X-056006Y-042604
|
||||
X-050846Y-021284
|
||||
X-074966Y-049034
|
||||
X-069826Y-045014
|
||||
X-026706Y-044984
|
||||
X-068656Y-045694
|
||||
X-025966Y-045694
|
||||
X-072126Y-024584
|
||||
X-072116Y-026684
|
||||
X-075176Y-025914
|
||||
X-073566Y-031704
|
||||
X-091667Y-005777
|
||||
X-091667Y-003097
|
||||
X-088187Y003323
|
||||
X-087527Y003303
|
||||
X-088947Y000733
|
||||
X-088957Y000103
|
||||
X-072057Y-006757
|
||||
X-074327Y-006797
|
||||
X-074327Y-005817
|
||||
X-074327Y-004707
|
||||
X-074327Y-003647
|
||||
X-072067Y-005837
|
||||
X-072067Y-004707
|
||||
X-072077Y-003627
|
||||
X-072047Y-002657
|
||||
X-074327Y-002667
|
||||
X-102637Y-012197
|
||||
X-089997Y-006867
|
||||
X-098257Y-008057
|
||||
X-104077Y-007837
|
||||
X-104027Y-047287
|
||||
X-009987Y-058887
|
||||
X-026457Y-058877
|
||||
X-064777Y-058807
|
||||
X-017597Y-057937
|
||||
X-066337Y-056797
|
||||
X-015047Y-057287
|
||||
X-060747Y-007997
|
||||
X-014017Y-045807
|
||||
X-015837Y-050907
|
||||
X-015837Y-008637
|
||||
X-014007Y-007987
|
||||
X-058897Y-023907
|
||||
X-011707Y-050947
|
||||
X-019397Y-055467
|
||||
T03
|
||||
X-082557Y-047197
|
||||
X-052360Y-048694
|
||||
X-062517Y-048777
|
||||
X-020310Y-043744
|
||||
X-020260Y-013224
|
||||
T04
|
||||
X-094757Y-018407
|
||||
T05
|
||||
X-004727Y-009287
|
||||
X-013657Y006183
|
||||
T06
|
||||
X-091456Y-017046
|
||||
T07
|
||||
X-091456Y-011787
|
||||
T08
|
||||
X-089376Y-023421
|
||||
X-083012Y-029785
|
||||
T09
|
||||
X-096800Y-015997
|
||||
X-096800Y-015997
|
||||
T10
|
||||
X-075587Y-015997
|
||||
X-075587Y-037210
|
||||
X-075587Y-015997
|
||||
X-075587Y-037210
|
||||
M30
|
||||
@@ -0,0 +1,121 @@
|
||||
G04 Layer: BoardOutlineLayer*
|
||||
G04 EasyEDA v6.5.46, 2026-07-24 11:31:18*
|
||||
G04 Gerber Generator version 0.2*
|
||||
G04 Scale: 100 percent, Rotated: No, Reflected: No *
|
||||
G04 Dimensions in millimeters *
|
||||
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal *
|
||||
%FSLAX45Y45*%
|
||||
%MOMM*%
|
||||
|
||||
%ADD10C,0.2540*%
|
||||
D10*
|
||||
G75*
|
||||
G01*
|
||||
X-1099077Y-1257065D02*
|
||||
G03*
|
||||
X-1265445Y-1412005I-3999J-162495D01*
|
||||
G75*
|
||||
G01*
|
||||
X1082783Y-1257065D02*
|
||||
G03*
|
||||
X1232644Y-1103395I-7769J157484D01*
|
||||
G75*
|
||||
G01*
|
||||
X-1265445Y-3964384D02*
|
||||
G03*
|
||||
X-1125744Y-4092654I137677J9736D01*
|
||||
G75*
|
||||
G01*
|
||||
X1242805Y-4238703D02*
|
||||
G03*
|
||||
X1101833Y-4092652I-142231J3776D01*
|
||||
G75*
|
||||
G01*
|
||||
X910066Y-6418655D02*
|
||||
G03*
|
||||
X1242805Y-6089726I-18455J351431D01*
|
||||
G75*
|
||||
G01*
|
||||
X-10731546Y-6098616D02*
|
||||
G03*
|
||||
X-10384836Y-6418657I337963J18303D01*
|
||||
G75*
|
||||
G01*
|
||||
X-10396269Y1099569D02*
|
||||
G03*
|
||||
X-10731546Y768098I-19126J-315954D01*
|
||||
G75*
|
||||
G01*
|
||||
X1232644Y778266D02*
|
||||
G03*
|
||||
X925306Y1099573I-289029J31179D01*
|
||||
G75*
|
||||
G01*
|
||||
X1105599Y-52243D02*
|
||||
G03*
|
||||
X1105597Y-52845I-114999J-10D01*
|
||||
G75*
|
||||
G01*
|
||||
X-6426401Y-52243D02*
|
||||
G03*
|
||||
X-6426402Y-52845I-114998J-10D01*
|
||||
G75*
|
||||
G01*
|
||||
X737964Y-4641716D02*
|
||||
G03*
|
||||
X737963Y-4642083I-70000J11D01*
|
||||
G75*
|
||||
G01*
|
||||
X735424Y-5444316D02*
|
||||
G03*
|
||||
X735423Y-5444683I-70000J11D01*
|
||||
G75*
|
||||
G01*
|
||||
X-6426401Y-5294241D02*
|
||||
G03*
|
||||
X-6426402Y-5294844I-114998J-10D01*
|
||||
X245727Y-6538655D02*
|
||||
G01*
|
||||
X245727Y-6418656D01*
|
||||
X-10396270Y1099571D02*
|
||||
G01*
|
||||
X925304Y1099571D01*
|
||||
X-1099075Y-1257063D02*
|
||||
G01*
|
||||
X1082784Y-1257063D01*
|
||||
X1232644Y-1103396D02*
|
||||
G01*
|
||||
X1232644Y778266D01*
|
||||
X-1265445Y-3964383D02*
|
||||
G01*
|
||||
X-1265445Y-1412006D01*
|
||||
X-1125745Y-4092653D02*
|
||||
G01*
|
||||
X1101834Y-4092653D01*
|
||||
X1242804Y-6089726D02*
|
||||
G01*
|
||||
X1242804Y-4238703D01*
|
||||
X-10384838Y-6418656D02*
|
||||
G01*
|
||||
X910064Y-6418656D01*
|
||||
X-10731545Y-6098618D02*
|
||||
G01*
|
||||
X-10731545Y768095D01*
|
||||
G75*
|
||||
G01*
|
||||
X910069Y-6418654D02*
|
||||
G03*
|
||||
X1242809Y-6089726I-18454J351431D01*
|
||||
G75*
|
||||
G01*
|
||||
X910067Y-6418654D02*
|
||||
G03*
|
||||
X1242807Y-6089724I-18455J351431D01*
|
||||
G75*
|
||||
G01*
|
||||
X1105101Y-5295242D02*
|
||||
G03*
|
||||
X1105099Y-5295844I-114999J-10D01*
|
||||
|
||||
%LPD*%
|
||||
M02*
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
G04 Layer: BottomPasteMaskLayer*
|
||||
G04 EasyEDA v6.5.46, 2026-07-24 11:31:18*
|
||||
G04 Gerber Generator version 0.2*
|
||||
G04 Scale: 100 percent, Rotated: No, Reflected: No *
|
||||
G04 Dimensions in millimeters *
|
||||
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal *
|
||||
%FSLAX45Y45*%
|
||||
%MOMM*%
|
||||
|
||||
%AMMACRO1*21,1,$1,$2,0,0,$3*%
|
||||
%ADD10MACRO1,5X2.3X135.0000*%
|
||||
%ADD11MACRO1,5X2.3X-10.0001*%
|
||||
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X-10175539Y-1850323D03*
|
||||
D11*
|
||||
G01*
|
||||
X-10352539Y-2976319D03*
|
||||
M02*
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,106 @@
|
||||
G04 Layer: BottomSolderMaskLayer*
|
||||
G04 EasyEDA v6.5.46, 2026-07-24 11:31:18*
|
||||
G04 Gerber Generator version 0.2*
|
||||
G04 Scale: 100 percent, Rotated: No, Reflected: No *
|
||||
G04 Dimensions in millimeters *
|
||||
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal *
|
||||
%FSLAX45Y45*%
|
||||
%MOMM*%
|
||||
|
||||
%AMMACRO1*4,1,8,0.9335,-2.6317,-2.6317,0.9335,-2.6317,0.9756,-0.9756,2.6317,-0.9335,2.6317,2.6317,-0.9335,2.6317,-0.9756,0.9756,-2.6317,0.9335,-2.6317,0*%
|
||||
%AMMACRO2*4,1,8,2.2742,-1.6203,-2.6912,-0.7448,-2.7154,-0.7103,-2.3087,1.5962,-2.2742,1.6203,2.6912,0.7448,2.7154,0.7103,2.3087,-1.5962,2.2742,-1.6203,0*%
|
||||
%AMMACRO3*4,1,8,-0.8085,-0.8382,-0.8382,-0.8085,-0.8382,0.8084,-0.8085,0.8382,0.8084,0.8382,0.8382,0.8084,0.8382,-0.8085,0.8084,-0.8382,-0.8085,-0.8382,0*%
|
||||
%ADD10MACRO1*%
|
||||
%ADD11MACRO2*%
|
||||
%ADD12C,1.8016*%
|
||||
%ADD13C,1.7016*%
|
||||
%ADD14C,1.6766*%
|
||||
%ADD15C,1.6764*%
|
||||
%ADD16MACRO3*%
|
||||
%ADD17C,1.6016*%
|
||||
%ADD18C,5.4016*%
|
||||
%ADD20C,1.6256*%
|
||||
%ADD21C,2.4016*%
|
||||
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X-10175540Y-1850325D03*
|
||||
D11*
|
||||
G01*
|
||||
X-10352540Y-2976321D03*
|
||||
D12*
|
||||
G01*
|
||||
X-8844686Y667308D03*
|
||||
D13*
|
||||
G01*
|
||||
X-8590686Y667308D03*
|
||||
G01*
|
||||
X-9098686Y667308D03*
|
||||
D12*
|
||||
G01*
|
||||
X-5916574Y-6030417D03*
|
||||
D13*
|
||||
G01*
|
||||
X-5662574Y-6030417D03*
|
||||
G01*
|
||||
X-6170574Y-6030417D03*
|
||||
D14*
|
||||
G01*
|
||||
X-3402685Y574294D03*
|
||||
G01*
|
||||
X-3402685Y320294D03*
|
||||
G01*
|
||||
X-2640685Y574294D03*
|
||||
D15*
|
||||
G01*
|
||||
X-2386685Y320294D03*
|
||||
G01*
|
||||
X-2640685Y320294D03*
|
||||
G01*
|
||||
X-2894685Y320294D03*
|
||||
D16*
|
||||
G01*
|
||||
X-2386685Y574293D03*
|
||||
D15*
|
||||
G01*
|
||||
X-2894685Y574294D03*
|
||||
G01*
|
||||
X-3148685Y320294D03*
|
||||
G01*
|
||||
X-3148685Y574294D03*
|
||||
D17*
|
||||
G01*
|
||||
X-10508513Y-446481D03*
|
||||
G01*
|
||||
X-9797313Y-446481D03*
|
||||
D18*
|
||||
G01*
|
||||
X-10330713Y-6026861D03*
|
||||
G01*
|
||||
X868146Y-6020511D03*
|
||||
G01*
|
||||
X864336Y690168D03*
|
||||
G01*
|
||||
X-10344683Y667308D03*
|
||||
D20*
|
||||
G01*
|
||||
X-9081643Y-4839868D03*
|
||||
G01*
|
||||
X-8827643Y-4839868D03*
|
||||
D21*
|
||||
G01*
|
||||
X-9255759Y-2023922D03*
|
||||
G01*
|
||||
X-8258733Y-1045286D03*
|
||||
G01*
|
||||
X-8730386Y-2771343D03*
|
||||
G01*
|
||||
X-7960563Y-2001520D03*
|
||||
G01*
|
||||
X-7982965Y-3296716D03*
|
||||
G01*
|
||||
X-7108291Y-3433190D03*
|
||||
G01*
|
||||
X-8979992Y-4275353D03*
|
||||
M02*
|
||||
@@ -0,0 +1,48 @@
|
||||
G04 Layer: DocumentLayer*
|
||||
G04 EasyEDA v6.5.46, 2026-07-24 11:31:18*
|
||||
G04 Gerber Generator version 0.2*
|
||||
G04 Scale: 100 percent, Rotated: No, Reflected: No *
|
||||
G04 Dimensions in millimeters *
|
||||
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal *
|
||||
%FSLAX45Y45*%
|
||||
%MOMM*%
|
||||
|
||||
%ADD10C,0.2540*%
|
||||
%ADD11C,0.7860*%
|
||||
|
||||
%LPD*%
|
||||
G36*
|
||||
X-6899402Y125983D02*
|
||||
G01*
|
||||
X-6899402Y-128016D01*
|
||||
X-6874002Y-128016D01*
|
||||
X-6874002Y125983D01*
|
||||
G37*
|
||||
G36*
|
||||
X-7014362Y13766D02*
|
||||
G01*
|
||||
X-7014362Y-11633D01*
|
||||
X-6760362Y-11633D01*
|
||||
X-6760362Y13766D01*
|
||||
G37*
|
||||
G36*
|
||||
X-1475486Y12649D02*
|
||||
G01*
|
||||
X-1475486Y-12750D01*
|
||||
X-1221486Y-12750D01*
|
||||
X-1221486Y12649D01*
|
||||
G37*
|
||||
D10*
|
||||
X-10740466Y1506118D02*
|
||||
G01*
|
||||
X1248333Y1506118D01*
|
||||
X1248333Y-2073249D01*
|
||||
X1248333Y-7218781D01*
|
||||
X-10740466Y-7218781D01*
|
||||
X-10740466Y1506118D01*
|
||||
D11*
|
||||
G75*
|
||||
G01
|
||||
X-7676007Y799998D02*
|
||||
G03X-7676007Y799998I-39294J0D01*
|
||||
M02*
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
This folder contains the PCB files for PortaPack H4 Pro. If you have any questions about the PCB files, please feel free to contact me. Thank you!
|
||||
|
||||
Our email address is support@opensourcesdrlab.com
|
||||
@@ -0,0 +1 @@
|
||||
Here are the hardware files of H4M Pro. If you have any questions about them, please feel free to contact me. Our email address is support@opensourcesdrlab.com
|
||||
@@ -0,0 +1 @@
|
||||
Superrollo;BADBEEF;1;5
|
||||
@@ -0,0 +1 @@
|
||||
Superrollo;BADBEEF;1;7
|
||||
@@ -0,0 +1 @@
|
||||
Superrollo;BADBEEF;1;3
|
||||
Reference in New Issue
Block a user