mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-12-01 19:42:15 +00:00
Compare commits
4 Commits
nightly-ta
...
nightly-ta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8073bca0f | ||
|
|
c30a61441b | ||
|
|
f0f279eec5 | ||
|
|
464cc8449e |
@@ -552,6 +552,7 @@ void DebugPmemView::update() {
|
||||
DebugScreenTest::DebugScreenTest(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
set_focusable(true);
|
||||
std::srand(LPC_RTC->CTIME0);
|
||||
}
|
||||
|
||||
bool DebugScreenTest::on_key(const KeyEvent key) {
|
||||
@@ -561,10 +562,10 @@ bool DebugScreenTest::on_key(const KeyEvent key) {
|
||||
nav_.pop();
|
||||
break;
|
||||
case KeyEvent::Down:
|
||||
painter.fill_rectangle({0, 0, screen_width, screen_height}, semirand());
|
||||
painter.fill_rectangle({0, 0, screen_width, screen_height}, std::rand());
|
||||
break;
|
||||
case KeyEvent::Left:
|
||||
pen_color = semirand();
|
||||
pen_color = std::rand();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -584,17 +585,10 @@ bool DebugScreenTest::on_touch(const TouchEvent event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t DebugScreenTest::semirand() {
|
||||
static uint64_t seed{0x0102030405060708};
|
||||
seed = seed * 137;
|
||||
seed = (seed >> 1) | ((seed & 0x01) << 63);
|
||||
return (uint16_t)seed;
|
||||
}
|
||||
|
||||
void DebugScreenTest::paint(Painter& painter) {
|
||||
painter.fill_rectangle({0, 16, screen_width, screen_height - 16}, Color::white());
|
||||
painter.draw_string({10 * 8, screen_height / 2}, Styles::white, "Use Stylus");
|
||||
pen_color = semirand();
|
||||
pen_color = std::rand();
|
||||
}
|
||||
|
||||
/* DebugLCRView *******************************************************/
|
||||
|
||||
@@ -385,7 +385,6 @@ class DebugScreenTest : public View {
|
||||
bool on_key(KeyEvent key) override;
|
||||
bool on_encoder(EncoderEvent delta) override;
|
||||
bool on_touch(TouchEvent event) override;
|
||||
uint16_t semirand();
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "tonesets.hpp"
|
||||
#include "ui_tone_key.hpp"
|
||||
#include "wm8731.hpp"
|
||||
#include "radio.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -336,6 +337,7 @@ MicTXView::MicTXView(
|
||||
&field_rxlna,
|
||||
&field_rxvga,
|
||||
&field_rxamp,
|
||||
hackrf_r9 ? &field_tx_iq_phase_cal_2839 : &field_tx_iq_phase_cal_2837,
|
||||
&tx_button,
|
||||
&tx_icon});
|
||||
|
||||
@@ -368,6 +370,21 @@ MicTXView::MicTXView(
|
||||
receiver_model.set_rf_amp(v);
|
||||
};
|
||||
|
||||
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
if (hackrf_r9) { // MAX2839 has 6 bits IQ CAL phasse adjustment.
|
||||
field_tx_iq_phase_cal_2839.set_value(iq_phase_calibration_value);
|
||||
field_tx_iq_phase_cal_2839.on_change = [this](int32_t v) {
|
||||
iq_phase_calibration_value = v;
|
||||
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
};
|
||||
} else { // MAX2837 has 5 bits IQ CAL phase adjustment.
|
||||
field_tx_iq_phase_cal_2837.set_value(iq_phase_calibration_value);
|
||||
field_tx_iq_phase_cal_2837.on_change = [this](int32_t v) {
|
||||
iq_phase_calibration_value = v;
|
||||
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
|
||||
};
|
||||
}
|
||||
|
||||
options_gain.on_change = [this](size_t, int32_t v) {
|
||||
mic_gain_x10 = v;
|
||||
configure_baseband();
|
||||
|
||||
@@ -113,6 +113,7 @@ class MicTXView : public View {
|
||||
uint32_t va_level{40};
|
||||
uint32_t attack_ms{500};
|
||||
uint32_t decay_ms{1000};
|
||||
uint8_t iq_phase_calibration_value{15};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_mic",
|
||||
app_settings::Mode::RX_TX,
|
||||
@@ -132,6 +133,7 @@ class MicTXView : public View {
|
||||
{"vox"sv, &va_enabled},
|
||||
{"rogerbeep"sv, &rogerbeep_enabled},
|
||||
{"tone_key_index"sv, &tone_key_index},
|
||||
{"iq_phase_calibration"sv, &iq_phase_calibration_value},
|
||||
}};
|
||||
|
||||
rf::Frequency tx_frequency{0};
|
||||
@@ -160,7 +162,8 @@ class MicTXView : public View {
|
||||
{{5 * 8, (25 * 8) + 2}, "F_RX:", Color::light_grey()},
|
||||
{{5 * 8, (27 * 8) + 2}, "LNA:", Color::light_grey()},
|
||||
{{12 * 8, (27 * 8) + 2}, "VGA:", Color::light_grey()},
|
||||
{{19 * 8, (27 * 8) + 2}, "AMP:", Color::light_grey()}};
|
||||
{{19 * 8, (27 * 8) + 2}, "AMP:", Color::light_grey()},
|
||||
{{21 * 8, (31 * 8)}, "TX-IQ-CAL:", Color::light_grey()}};
|
||||
Labels labels_WM8731{
|
||||
{{17 * 8, 1 * 8}, "Boost", Color::light_grey()}};
|
||||
Labels labels_AK4951{
|
||||
@@ -338,6 +341,22 @@ class MicTXView : public View {
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_tx_iq_phase_cal_2837{
|
||||
{24 * 8, (33 * 8)},
|
||||
2,
|
||||
{0, 31}, // 5 bits IQ CAL phase adjustment.
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_tx_iq_phase_cal_2839{
|
||||
{24 * 8, (33 * 8)},
|
||||
2,
|
||||
{0, 63}, // 6 bits IQ CAL phasse adjustment.
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
Button tx_button{
|
||||
{10 * 8, 30 * 8, 10 * 8, 5 * 8},
|
||||
"PTT TX",
|
||||
|
||||
16
firmware/application/external/external.cmake
vendored
16
firmware/application/external/external.cmake
vendored
@@ -3,7 +3,11 @@ set(EXTCPPSRC
|
||||
#pacman
|
||||
external/pacman/main.cpp
|
||||
external/pacman/ui_pacman.cpp
|
||||
|
||||
|
||||
#tetris
|
||||
external/tetris/main.cpp
|
||||
external/tetris/ui_tetris.cpp
|
||||
|
||||
#afsk_rx
|
||||
external/afsk_rx/main.cpp
|
||||
external/afsk_rx/ui_afsk_rx.cpp
|
||||
@@ -19,7 +23,7 @@ set(EXTCPPSRC
|
||||
#blespam
|
||||
external/blespam/main.cpp
|
||||
external/blespam/ui_blespam.cpp
|
||||
|
||||
|
||||
#analogtv
|
||||
external/analogtv/main.cpp
|
||||
external/analogtv/analog_tv_app.cpp
|
||||
@@ -35,13 +39,12 @@ set(EXTCPPSRC
|
||||
#lge
|
||||
external/lge/main.cpp
|
||||
external/lge/lge_app.cpp
|
||||
|
||||
|
||||
#lcr
|
||||
external/lcr/main.cpp
|
||||
external/lcr/ui_lcr.cpp
|
||||
|
||||
|
||||
#lcr
|
||||
|
||||
#jammer
|
||||
external/jammer/main.cpp
|
||||
external/jammer/ui_jammer.cpp
|
||||
|
||||
@@ -76,4 +79,5 @@ set(EXTAPPLIST
|
||||
gpssim
|
||||
spainter
|
||||
keyfob
|
||||
tetris
|
||||
)
|
||||
|
||||
19
firmware/application/external/external.ld
vendored
19
firmware/application/external/external.ld
vendored
@@ -31,6 +31,7 @@ MEMORY
|
||||
ram_external_app_gpssim(rwx) : org = 0xEEF40000, len = 32k
|
||||
ram_external_app_spainter(rwx) : org = 0xEEF50000, len = 32k
|
||||
ram_external_app_keyfob(rwx) : org = 0xEEF60000, len = 32k
|
||||
ram_external_app_tetris(rwx) : org = 0xEEF70000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -59,7 +60,7 @@ SECTIONS
|
||||
*(*ui*external_app*font_viewer*);
|
||||
} > ram_external_app_font_viewer
|
||||
|
||||
|
||||
|
||||
.external_app_blespam : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_blespam.application_information));
|
||||
@@ -77,33 +78,33 @@ SECTIONS
|
||||
KEEP(*(.external_app.app_nrf_rx.application_information));
|
||||
*(*ui*external_app*nrf_rx*);
|
||||
} > ram_external_app_nrf_rx
|
||||
|
||||
|
||||
.external_app_coasterp : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_coasterp.application_information));
|
||||
*(*ui*external_app*coasterp*);
|
||||
} > ram_external_app_coasterp
|
||||
|
||||
|
||||
.external_app_lge : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_lge.application_information));
|
||||
*(*ui*external_app*lge*);
|
||||
} > ram_external_app_lge
|
||||
|
||||
|
||||
|
||||
.external_app_lcr : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_lcr.application_information));
|
||||
*(*ui*external_app*lcr*);
|
||||
} > ram_external_app_lcr
|
||||
|
||||
|
||||
|
||||
.external_app_jammer : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_jammer.application_information));
|
||||
*(*ui*external_app*jammer*);
|
||||
} > ram_external_app_jammer
|
||||
|
||||
|
||||
.external_app_gpssim : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_gpssim.application_information));
|
||||
@@ -123,4 +124,10 @@ SECTIONS
|
||||
*(*ui*external_app*keyfob*);
|
||||
} > ram_external_app_keyfob
|
||||
|
||||
.external_app_tetris : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_tetris.application_information));
|
||||
*(*ui*external_app*tetris*);
|
||||
} > ram_external_app_tetris
|
||||
|
||||
}
|
||||
|
||||
29
firmware/application/external/tetris/Arial12x12.h
vendored
Normal file
29
firmware/application/external/tetris/Arial12x12.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// dummy include file to avoid changing original source
|
||||
|
||||
#ifndef __UI_Arial12x12_H__
|
||||
#define __UI_Arial12x12_H__
|
||||
|
||||
#define Arial12x12 (0)
|
||||
|
||||
#endif /*__UI_Arial12x12_H__*/
|
||||
102
firmware/application/external/tetris/SPI_TFT_ILI9341.h
vendored
Normal file
102
firmware/application/external/tetris/SPI_TFT_ILI9341.h
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// "HAL" display layer for Tetris code to run on PortaPack without its original ILI9341 functions
|
||||
|
||||
#ifndef __UI_SPI_TFT_ILI9341_H__
|
||||
#define __UI_SPI_TFT_ILI9341_H__
|
||||
|
||||
ui::Painter painter;
|
||||
|
||||
static int x_pos{0};
|
||||
static int y_pos{0};
|
||||
static int fg_color;
|
||||
static int bg_color;
|
||||
|
||||
enum {
|
||||
White,
|
||||
Blue,
|
||||
Yellow,
|
||||
Purple,
|
||||
Green,
|
||||
Red,
|
||||
Maroon,
|
||||
Orange,
|
||||
Black,
|
||||
};
|
||||
|
||||
// pp_colors must be in same order as enums above
|
||||
static const Color pp_colors[] = {
|
||||
Color::white(),
|
||||
Color::blue(),
|
||||
Color::yellow(),
|
||||
Color::purple(),
|
||||
Color::green(),
|
||||
Color::red(),
|
||||
Color::magenta(),
|
||||
Color::orange(),
|
||||
Color::black(),
|
||||
};
|
||||
|
||||
class SPI_TFT_ILI9341 {
|
||||
public:
|
||||
SPI_TFT_ILI9341(int, int, int, int, int, int, std::string) { (void)0; };
|
||||
|
||||
void claim(__FILE* x) { (void)x; };
|
||||
|
||||
void cls() {
|
||||
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
|
||||
};
|
||||
|
||||
void background(int color) { bg_color = color; };
|
||||
void foreground(int color) { fg_color = color; };
|
||||
|
||||
void locate(int x, int y) {
|
||||
x_pos = x;
|
||||
y_pos = y;
|
||||
};
|
||||
void set_orientation(int x) { (void)x; };
|
||||
void set_font(unsigned char* x) { (void)x; };
|
||||
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color) {
|
||||
painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||
};
|
||||
|
||||
void rect(int x1, int y1, int x2, int y2, int color) {
|
||||
painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||
};
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
static void printf(std::string str) {
|
||||
auto style = (fg_color == White) ? ui::Styles::white : ui::Styles::bg_white;
|
||||
painter.draw_string({x_pos, y_pos - 1}, style, str);
|
||||
};
|
||||
|
||||
static void printf(std::string str, int v) {
|
||||
if (str.find_first_of("%") != std::string::npos) {
|
||||
str.resize(str.find_first_of("%")); // remove %d from end of string
|
||||
}
|
||||
printf(str + to_string_dec_uint(v));
|
||||
};
|
||||
|
||||
#endif /*__UI_SPI_TFT_ILI9341_H__*/
|
||||
82
firmware/application/external/tetris/main.cpp
vendored
Normal file
82
firmware/application/external/tetris/main.cpp
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_tetris.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::tetris {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<TetrisView>();
|
||||
}
|
||||
} // namespace ui::external_app::tetris
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_tetris.application_information"), used)) application_information_t _application_information_tetris = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000, // will be filled at compile time
|
||||
/*.externalAppEntry = */ ui::external_app::tetris::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Tetris",
|
||||
/*.bitmap_data = */ {
|
||||
0xF8,
|
||||
0xFF,
|
||||
0x88,
|
||||
0x88,
|
||||
0x88,
|
||||
0x88,
|
||||
0x88,
|
||||
0x88,
|
||||
0xF8,
|
||||
0xFF,
|
||||
0x80,
|
||||
0x08,
|
||||
0x80,
|
||||
0x08,
|
||||
0x9F,
|
||||
0x08,
|
||||
0x91,
|
||||
0x0F,
|
||||
0x11,
|
||||
0x00,
|
||||
0x11,
|
||||
0x00,
|
||||
0xFF,
|
||||
0xF1,
|
||||
0x11,
|
||||
0x91,
|
||||
0x11,
|
||||
0x91,
|
||||
0x11,
|
||||
0x91,
|
||||
0xFF,
|
||||
0xF1,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::orange().v,
|
||||
/*.menu_location = */ app_location_t::UTILITIES,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_noop */ {'\0', '\0', '\0', '\0'}, // optional
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
220
firmware/application/external/tetris/mbed.h
vendored
Normal file
220
firmware/application/external/tetris/mbed.h
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// "HAL" layer for Tetris code to run on PortaPack without its original mbed OS
|
||||
// (the dream here was to avoid modifying the original code)
|
||||
|
||||
#ifndef __UI_mbed_H__
|
||||
#define __UI_mbed_H__
|
||||
|
||||
using Callback = void (*)(void);
|
||||
|
||||
#define wait_us(x) (void)0
|
||||
#define wait(x) chThdSleepMilliseconds(x * 1000)
|
||||
#define PullUp 1
|
||||
|
||||
enum {
|
||||
dp0,
|
||||
dp1,
|
||||
dp2,
|
||||
dp3,
|
||||
dp4,
|
||||
dp5,
|
||||
dp6,
|
||||
dp7,
|
||||
dp8,
|
||||
dp9,
|
||||
dp10,
|
||||
dp11,
|
||||
dp12,
|
||||
dp13,
|
||||
dp14,
|
||||
dp15,
|
||||
dp16,
|
||||
dp17,
|
||||
dp18,
|
||||
dp19,
|
||||
dp20,
|
||||
dp21,
|
||||
dp22,
|
||||
dp23,
|
||||
dp24,
|
||||
dp25,
|
||||
};
|
||||
|
||||
static bool but_RIGHT;
|
||||
static bool but_LEFT;
|
||||
static bool but_UP;
|
||||
static bool but_DOWN;
|
||||
static bool but_SELECT;
|
||||
|
||||
//
|
||||
// AnalogIn Class -- DID NOT WORK BECAUSE INITIALIZER CODE WON'T EXECUTE -- hacked original code module instead
|
||||
//
|
||||
// dp9 = joystick rotate button --> select button
|
||||
// dp10 = joystick y --> up & down buttons
|
||||
// dp11 = joystick x --> left & right buttons
|
||||
// dp13 = random number generator
|
||||
//
|
||||
//
|
||||
// class AnalogIn {
|
||||
// public:
|
||||
// AnalogIn(uint32_t analog_input) {
|
||||
// // FIXME - THIS CODE NEVER GETS EXECUTED!
|
||||
// analog_input_ = analog_input;
|
||||
// };
|
||||
//
|
||||
// // Tetris code only uses this function for dp13 - supposed to be a random number
|
||||
// uint16_t read_u16() {
|
||||
// return std::rand();
|
||||
// };
|
||||
//
|
||||
// // Tetris code uses read() function for direction buttons only
|
||||
// float read() {
|
||||
// float retval = 0.5;
|
||||
// switch (analog_input_) {
|
||||
// case dp11:
|
||||
// if (but_LEFT)
|
||||
// retval = 0.0;
|
||||
// else if (but_RIGHT)
|
||||
// retval = 1.0;
|
||||
// break;
|
||||
//
|
||||
// case dp10:
|
||||
// if (but_UP)
|
||||
// retval = 0.0;
|
||||
// else if (but_DOWN)
|
||||
// retval = 1.0;
|
||||
// break;
|
||||
// }
|
||||
// return retval;
|
||||
// };
|
||||
//
|
||||
// operator float() {
|
||||
// return read();
|
||||
// };
|
||||
//
|
||||
// private:
|
||||
// uint32_t analog_input_{INT_MAX};
|
||||
// };
|
||||
|
||||
//
|
||||
// Timer Class
|
||||
// (Timer object was used for unneeded button debouncing, so just returning 1000ms to indicate we've waited long enough)
|
||||
//
|
||||
class Timer {
|
||||
public:
|
||||
// NOTE: INITIALIZER CODE WON'T RUN
|
||||
Timer() { (void)0; };
|
||||
void reset() { (void)0; };
|
||||
void start() { (void)0; }
|
||||
uint32_t read_ms() { return 1000; };
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
//
|
||||
// Ticker Class
|
||||
// (Ticker is timed callback, used for checking "joystick" directional switches and when time to move piece down a row)
|
||||
//
|
||||
// NB: Only one callback is supported per Ticker class instantiation
|
||||
static Callback fall_timer_callback;
|
||||
static uint32_t fall_timer_timeout;
|
||||
static uint32_t fall_timer_counter;
|
||||
|
||||
static Callback dir_button_callback;
|
||||
|
||||
static void check_fall_timer() {
|
||||
if (fall_timer_callback) {
|
||||
if (++fall_timer_counter >= fall_timer_timeout) {
|
||||
fall_timer_counter = 0;
|
||||
fall_timer_callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Ticker {
|
||||
public:
|
||||
// NOTE: INITIALIZER CODE WON'T RUN
|
||||
Ticker() { (void)0; };
|
||||
|
||||
void attach(Callback func, double delay_sec) {
|
||||
// 0.3 sec is requested only for button check -- kludge to use on_key callback for this one instead of timer
|
||||
if (delay_sec == 0.3) {
|
||||
dir_button_callback = func;
|
||||
} else {
|
||||
fall_timer_callback = func;
|
||||
fall_timer_timeout = delay_sec * 60; // timer interrupts at 60 Hz
|
||||
}
|
||||
}
|
||||
|
||||
void detach() {
|
||||
// shouldn't detach both, but don't know how to tell which object is which
|
||||
dir_button_callback = nullptr;
|
||||
fall_timer_callback = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
//
|
||||
// InterruptIn Class
|
||||
// (just used for the Select button)
|
||||
//
|
||||
static Callback sel_button_callback;
|
||||
|
||||
static bool check_encoder(const EncoderEvent delta) {
|
||||
(void)delta;
|
||||
// TODO: consider adding ability to rotate Tetronimo via encoder too
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool check_key(const KeyEvent key) {
|
||||
auto switches_debounced = get_switches_state().to_ulong();
|
||||
but_RIGHT = (switches_debounced & 0x01) != 0;
|
||||
but_LEFT = (switches_debounced & 0x02) != 0;
|
||||
but_DOWN = (switches_debounced & 0x04) != 0;
|
||||
but_UP = (switches_debounced & 0x08) != 0;
|
||||
but_SELECT = (switches_debounced & 0x10) != 0;
|
||||
|
||||
if (key == KeyEvent::Select) {
|
||||
if (sel_button_callback)
|
||||
sel_button_callback();
|
||||
} else {
|
||||
if (dir_button_callback)
|
||||
dir_button_callback();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class InterruptIn {
|
||||
public:
|
||||
InterruptIn(int reg) {
|
||||
// NOTE: INITIALIZER CODE WON'T RUN
|
||||
(void)reg;
|
||||
};
|
||||
void fall(Callback func) { sel_button_callback = func; };
|
||||
void mode(int v) { (void)v; };
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif /*__UI_mbed_H__*/
|
||||
578
firmware/application/external/tetris/tetris.cpp
vendored
Normal file
578
firmware/application/external/tetris/tetris.cpp
vendored
Normal file
@@ -0,0 +1,578 @@
|
||||
// Projekat Tetris
|
||||
// by Vrnjak Lamija & Selimović Denis
|
||||
// Elektrotehnički fakultet Sarajevo
|
||||
|
||||
// clang-format off
|
||||
|
||||
//////// PORTAPACK CHANGES HIGHLIGHTED
|
||||
int main();
|
||||
void pause_game();
|
||||
//////// PORTAPACK
|
||||
|
||||
#include "mbed.h"
|
||||
#include "SPI_TFT_ILI9341.h"
|
||||
#include "Arial12x12.h"
|
||||
|
||||
#define dp23 P0_0
|
||||
|
||||
//deklaracija display-a
|
||||
SPI_TFT_ILI9341 display(dp2, dp1, dp6, dp24, dp23, dp25, "TFT");
|
||||
|
||||
//////// PORTAPACK - DISABLED ANALOGIN CLASS DUE TO OBJECT INITIALIZER CODE NOT RUNNING:
|
||||
//analogni ulazi za joystick
|
||||
// AnalogIn VRx(dp11);
|
||||
// AnalogIn VRy(dp10);
|
||||
//////// PORTAPACK
|
||||
|
||||
//taster na joysticku za rotaciju
|
||||
InterruptIn taster(dp9);
|
||||
|
||||
//////// PORTAPACK - DISABLED ANALOGIN CLASS DUE TO OBJECT INITIALIZER CODE NOT RUNNING:
|
||||
// AnalogIn random(dp13); //analogni ulaz za generisanje random vrijednosti
|
||||
//////// PORTAPACK
|
||||
|
||||
//ticker za spustanje figure
|
||||
//timer za debouncing tastera na joysticku
|
||||
Ticker game, joystick;
|
||||
Timer debounceTaster;
|
||||
|
||||
|
||||
unsigned char level = 0; //mora biti tipa usigned char jer inače se može desiti da level bude manji od 0, a i da ne trošimo memoriju
|
||||
const float delays[4] = {1.2, 0.7, 0.4, 0.25}; //svakih koliko se spusti jedan red, ovo provjeriti da li je presporo ili prebrzo, ovisi o levelu
|
||||
|
||||
//////// PORTAPACK - UNNEEDED JOYSTICK HYSTERESIS VARIABLES
|
||||
//char leftBoundary = 1, rightBoundary = 5, downBoundary = 1, upBoundary = 5;// sada je ovo tipa char
|
||||
//////// PORTAPACK
|
||||
|
||||
unsigned int score = 0; //stavio sam ovo unsigned int za veći opseg, mada je jako teško da se i int premaši, ali nmvz
|
||||
bool firstTime = true; //ako je prvi put, figura se crta u Tickeru
|
||||
bool gameStarted = false;
|
||||
unsigned char nextFigure = 1; //ovo je sad globalna varijabla, da bi mogli unaprijed generisati sljedeću figuru radi prikaza
|
||||
|
||||
|
||||
//white - no figure
|
||||
//I - BLUE
|
||||
//O - YELLOW
|
||||
//T - PURPLE
|
||||
//S - GREEN
|
||||
//Z - RED
|
||||
//J - MAROON
|
||||
//L - ORANGE
|
||||
const int colors[8] = {White, Blue, Yellow, Purple, Green, Red, Maroon, Orange};
|
||||
const short DIMENSION = 16;
|
||||
const short DIMENSION_NEXT = 12;
|
||||
short board[20][10] = {0}; //matrica boja, 0 - 7 indeksi boja
|
||||
|
||||
short figuresX[7][4] = {{0,0,0,0}, {0,0,1,1}, {0,1,1,1}, {1,1,0,0}, {0,1,0,1}, {1,1,1,0}, {1,1,1,0}};
|
||||
short figuresY[7][4] = {{0,1,2,3}, {1,0,0,1}, {1,1,2,0}, {0,1,1,2}, {0,1,1,2}, {2,1,0,0}, {0,1,2,2}};
|
||||
|
||||
unsigned int GenerateRandomSeed() {
|
||||
//////// PORTAPACK - USE RTC FOR SEED
|
||||
return LPC_RTC->CTIME0;
|
||||
// unsigned int randomNumber = 0;
|
||||
// for(int i = 0; i <= 32; i += 2) {
|
||||
// randomNumber += ((random.read_u16() % 3) << i);
|
||||
// wait_us(10);
|
||||
// }
|
||||
// return randomNumber;
|
||||
//////// PORTAPACK
|
||||
}
|
||||
|
||||
void Init() {
|
||||
//ovo su zajedničke osobine za sve prikaze na display-u
|
||||
//nikad se ne mijenjaju i pozvat ćemo je jednom prije petlje
|
||||
display.claim(stdout);
|
||||
display.set_orientation(2); // 2 ili 0, zavisi kako okrenemo display, provjerit ćemo na labu kako nam je najlakše povezat
|
||||
display.set_font((unsigned char*) Arial12x12);
|
||||
}
|
||||
|
||||
|
||||
void ShowScore() {
|
||||
//pomocna funkcija za prikazivanje score-a
|
||||
display.fillrect(165, 20, 235, 50, White); //popunimo pravugaonik da obrišemo stari score
|
||||
display.locate(200, 35); //valjda je na sredini pravougaonika
|
||||
printf("%d", score);
|
||||
}
|
||||
|
||||
void ShowNextFigure() {
|
||||
//prikaz sljedeće figure koristeći pomoćnu varijablu nextFigure
|
||||
display.fillrect(165, 70, 235, 120, White);
|
||||
int upperLeftX = 176, upperLeftY = 83;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
int x = upperLeftX + DIMENSION_NEXT * figuresY[nextFigure - 1][i], y = upperLeftY + DIMENSION_NEXT * figuresX[nextFigure - 1][i];
|
||||
display.fillrect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, colors[nextFigure]);
|
||||
display.rect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, Black);
|
||||
}
|
||||
}
|
||||
|
||||
//funkcija za crtanje cursora za odabir levela
|
||||
void DrawCursor(int color, unsigned char lev) {
|
||||
display.fillrect(60, lev * 70 + 50, 72, lev * 70 + 50 + 12, color);
|
||||
}
|
||||
|
||||
// PORTAPACK - ADDED EXTRA LEVEL:
|
||||
void ShowLevelMenu() {
|
||||
//ovdje inicijalizujemo display
|
||||
display.cls(); // brišemo prethodno
|
||||
display.background(Black);
|
||||
display.foreground(White);
|
||||
display.locate(80, 50);
|
||||
printf("LEVEL 1");
|
||||
display.locate(80, 120);
|
||||
printf("LEVEL 2");
|
||||
display.locate(80, 190);
|
||||
printf("LEVEL 3");
|
||||
display.locate(80, 260);
|
||||
printf("LEVEL 4");
|
||||
DrawCursor(White, level);
|
||||
}
|
||||
|
||||
//////// PORTAPACK - KLUDGED FOR BUTTONS VS JOYSTICK:
|
||||
void ReadJoystickForLevel(){
|
||||
unsigned char old = level;
|
||||
if(but_UP){
|
||||
// upBoundary = 4;
|
||||
(level == 0) ? level = 3 : level--;
|
||||
}
|
||||
else if(but_DOWN){
|
||||
//ne radi ona prethodna varijanta jer % vraća i negastivni rezultat
|
||||
//to što ne koristimo unsigned tip ne pomaže jer će doći do overflow-a
|
||||
// downBoundary = 2;
|
||||
level = (level + 1) % 4;
|
||||
}
|
||||
else {
|
||||
// downBoundary = 1;
|
||||
// upBoundary = 5;
|
||||
}
|
||||
DrawCursor(Black, old); //na prethodni level popunimo bojom pozadine
|
||||
DrawCursor(White, level); //na novi level popunimo bijelom bojom - pozadina je crna
|
||||
//koristio sam fillrect, jer njega svakako moramo koristiti, jer možda budemo morali da brišemo fillcircle iz biblioteke
|
||||
}
|
||||
//////// PORTAPACK
|
||||
|
||||
void EndPlay() {
|
||||
joystick.detach();
|
||||
score = 0;
|
||||
firstTime = true;
|
||||
gameStarted = false;
|
||||
for(int i = 0; i < 20; i++) {
|
||||
for(int j = 0; j < 10; j++) {
|
||||
board[i][j] = 0;
|
||||
}
|
||||
}
|
||||
//////// PORTAPACK - FIX TO REINITIALIZE SCREEN
|
||||
// ShowLevelMenu();
|
||||
// joystick.attach(&ReadJoystickForLevel, 0.3);
|
||||
main();
|
||||
//////// PORTAPACK
|
||||
}
|
||||
|
||||
void StartGame()
|
||||
{
|
||||
display.cls(); // brišemo ShowLevelMenu
|
||||
display.background(White);
|
||||
display.foreground(Black);
|
||||
display.fillrect(0, 0, 160, 320, White);
|
||||
display.fillrect(160, 0, 240, 320, Black); //dio za prikazivanje rezultata će biti crni pravougaonik, a tabla je bijeli
|
||||
ShowScore();
|
||||
}
|
||||
|
||||
void copyCoordinates(short X[], short Y[], unsigned char index)
|
||||
{
|
||||
//umjesto one prošle metode za kopiranje, ova prima index, čisto da nam olakša život
|
||||
for(int i = 0; i < 4; i++) {
|
||||
X[i] = figuresX[index][i];
|
||||
Y[i] = figuresY[index][i];
|
||||
}
|
||||
}
|
||||
|
||||
bool BottomEdge(int x){
|
||||
return x > 19;
|
||||
}
|
||||
|
||||
bool LeftEdge(int y){
|
||||
return y < 0;
|
||||
}
|
||||
|
||||
bool RightEdge(int y){
|
||||
return y > 9;
|
||||
}
|
||||
|
||||
bool OutOfBounds(int y, int x){
|
||||
return y < 0 || y > 9 || x > 19;
|
||||
}
|
||||
|
||||
void PutBorders(short x, short y) {
|
||||
for(int i = x - 1; i <= x + 1; i++) {
|
||||
for(int j = y - 1; j <= y + 1; j++) {
|
||||
if(i < 0 || i > 9 || j < 0 || j > 19 || board[j][i] == 0) continue;
|
||||
display.rect(i * DIMENSION, j * DIMENSION, (i + 1) * DIMENSION, (j + 1) * DIMENSION, Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Tetromino{
|
||||
private:
|
||||
short X[4];
|
||||
short Y[4];
|
||||
short boardX, boardY;
|
||||
unsigned char colorIndex;//dodao sam colorIndex zasad, jer nema drugog načina da popunimo matricu sa indeksima boja
|
||||
//ovo je najbezbolnija varijanta što se memorije tiče
|
||||
public:
|
||||
Tetromino(){
|
||||
//////// PORTAPACK - NOTE - DEFAULT INITIALIZER CODE DOESN'T GET EXECUTED FOR SOME REASON:
|
||||
unsigned char r = rand() % 7 + 1;
|
||||
Initialize(r);
|
||||
}
|
||||
|
||||
Tetromino(unsigned char colorIndex) {
|
||||
Initialize(colorIndex);
|
||||
}
|
||||
|
||||
void Initialize(unsigned char colorIndex) {
|
||||
Tetromino::colorIndex = colorIndex;
|
||||
boardX = 0;
|
||||
boardY = 4; //3,4 ili 5 najbolje da vidimo kad imamo display
|
||||
copyCoordinates(X, Y, colorIndex - 1);
|
||||
}
|
||||
|
||||
void Rotate(){
|
||||
short pivotX = X[1], pivotY = Y[1];
|
||||
//prvi elemnti u matrici su pivoti oko koje rotiramo
|
||||
|
||||
short newX[4]; //pozicije blokova nakon rotiranja ako sve bude ok
|
||||
short newY[4];
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
short tmp = X[i], tmp2 = Y[i];
|
||||
newX[i] = pivotX + pivotY - tmp2;
|
||||
newY[i] = tmp + pivotX - pivotY;
|
||||
|
||||
if(OutOfBounds(boardY + newY[i], boardX + newX[i]) || board[boardX + newX[i]][boardY + newY[i]] != 0) return;
|
||||
}
|
||||
DeleteFigure();
|
||||
for(int i = 0; i < 4; i++){
|
||||
X[i] = newX[i];
|
||||
Y[i] = newY[i];
|
||||
}
|
||||
DrawFigure();
|
||||
}
|
||||
|
||||
void DrawFigure() {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
//display je deklarisani display logy iz biblioteke one
|
||||
//računamo gornji lijevi pixel po x i y
|
||||
//donji desni dobijemo kad dodamo DIMENZIJU
|
||||
//stavio sam 16 za početak, možemo se opet skontati na labu
|
||||
//ovo pretpostavlja da nema margina, mogu se lagano dodati uz neku konstantu kao offset
|
||||
int upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
|
||||
display.fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, colors[colorIndex]);
|
||||
//ovo boji granice blokova u crno, možemo skloniti ako ti se ne sviđa
|
||||
|
||||
//////// PORTAPACK - HIDE DEFAULT WHITE BLOCK (ALTERNATE KLUDGE FOR TETRONIMO INITIALIZATION CODE NOT RUNNING AT CONSTRUCTION)
|
||||
if (colorIndex != White)
|
||||
//////// PORTAPACK
|
||||
display.rect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, Black);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteFigure() {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
//ista logika kao u DrawFigure, samo popunjavamo sve blokove sa bijelim pravougaonicima
|
||||
short upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
|
||||
display.fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, White);
|
||||
PutBorders(upperLeftY, upperLeftX);
|
||||
}
|
||||
}
|
||||
|
||||
void OnAttached() {
|
||||
//metoda se poziva kad figura prestanje da se krece
|
||||
//popunimo matricu indeksom boje
|
||||
for(int i = 0; i < 4; i++) {
|
||||
board[boardX + X[i]][boardY + Y[i]] = colorIndex;
|
||||
//btw board bi mogao biti niz tipa unsigned char, ali to ćemo vidjet kasnije
|
||||
}
|
||||
}
|
||||
|
||||
bool MoveDown(char delta = 1){
|
||||
//////// PORTAPACK - MOVE DEFAULT WHITE BLOCK TO BOTTOM IMMEDIATELY (ALTERNATE KLUDGE FOR TETRONIMO INITIALIZATION CODE NOT RUNNING AT CONSTRUCTION)
|
||||
if (colorIndex == White) delta = 19;
|
||||
//////// PORTAPACK
|
||||
if(!InCollisionDown(delta)){
|
||||
DeleteFigure();
|
||||
boardX+=delta;
|
||||
DrawFigure();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MoveLeft(){
|
||||
if(!InCollisionLeft()){
|
||||
DeleteFigure();
|
||||
boardY--;
|
||||
DrawFigure();
|
||||
}
|
||||
}
|
||||
|
||||
void MoveRight(){
|
||||
if(!InCollisionRight()){
|
||||
DeleteFigure();
|
||||
boardY++;
|
||||
DrawFigure();
|
||||
}
|
||||
}
|
||||
|
||||
void SoftDrop() {
|
||||
//ovo je funkcija za soft drop
|
||||
//obrisemo figuru, postavimo novu poziciju dva reda ispod, nacrtamo figuru
|
||||
DeleteFigure();
|
||||
MoveDown(2);
|
||||
DrawFigure();
|
||||
//treba još vidjeti koje izmjene u tickeru trebaju
|
||||
score += 2 * (level +1); //prema igrici koju smo igrali, dobije se 14 poena kad se uradi hard drop
|
||||
ShowScore();
|
||||
}
|
||||
|
||||
|
||||
bool InCollisionDown(char delta = 1){
|
||||
int newX, newY; //da bi bilo citljivije
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
newX = boardX + X[i] + delta;
|
||||
newY = boardY + Y[i];
|
||||
|
||||
if(BottomEdge(newX) || board[newX][newY] != 0){
|
||||
return true;
|
||||
}
|
||||
//jedna figura je u koliziji ako
|
||||
//pozicija na koju zelimo da pomjerimo bilo koji blok dotakne dno ili lijevu ili desnu ivicu ekrana
|
||||
//ili ako je pozicija na koju zelimo da pomjerimo bilo koji od blokova vec zauzeta a da nije dio figure prije pomijeranja
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InCollisionLeft(){
|
||||
int newX, newY;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
newX = boardX + X[i];
|
||||
newY = boardY + Y[i] - 1;
|
||||
|
||||
if(LeftEdge(newY) || board[newX][newY] != 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool InCollisionRight(){
|
||||
int newX, newY;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
newX = boardX + X[i];
|
||||
newY = boardY + Y[i] + 1;
|
||||
|
||||
if(RightEdge(newY) || board[newX][newY] != 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Tetromino currentTetromino;
|
||||
|
||||
//////// PORTAPACK - KLUDGED FOR BUTTONS VS JOYSTICK:
|
||||
void ReadJoystickForFigure() {
|
||||
if(but_LEFT) {
|
||||
// leftBoundary = 2;
|
||||
currentTetromino.MoveLeft();
|
||||
}
|
||||
else if(but_RIGHT) {
|
||||
// rightBoundary = 4;
|
||||
currentTetromino.MoveRight();
|
||||
}
|
||||
else if(but_UP) {
|
||||
// downBoundary = 2;
|
||||
pause_game();
|
||||
}
|
||||
else if(but_DOWN) {
|
||||
// upBoundary = 4;
|
||||
currentTetromino.SoftDrop();
|
||||
}
|
||||
else {
|
||||
// leftBoundary = 1;
|
||||
// rightBoundary = 5;
|
||||
// downBoundary = 1;
|
||||
// upBoundary = 5;
|
||||
}
|
||||
}
|
||||
//////// PORTAPACK
|
||||
|
||||
void CheckLines(short &firstLine, short &numberOfLines)
|
||||
{
|
||||
//vraća preko reference prvu liniju koja je popunjena do kraja, kao i takvih linija
|
||||
firstLine = -1; //postavljen na -1 jer ako nema linija koje treba brisati ispod u UpdateBoard neće se ući u petlju
|
||||
numberOfLines = 0;
|
||||
for(int i = 19; i >= 0; i--) {
|
||||
short temp = 0;
|
||||
for(int j = 0; j < 10; j++) {
|
||||
if(board[i][j] == 0) {
|
||||
if(numberOfLines > 0) return;
|
||||
break;
|
||||
}//ako je makar jedna bijela, prekida se brojanje
|
||||
temp++;
|
||||
}
|
||||
if(temp == 10) { //ako je temo došao do 10, niti jedna bijela - puna linija
|
||||
numberOfLines++;
|
||||
if(firstLine == -1) firstLine = i; //ovo mijenjamo samo prvi put
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int UpdateScore (short numOfLines){
|
||||
unsigned int newIncrement = 0;
|
||||
switch(numOfLines) {
|
||||
case 1 : newIncrement = 40; break;
|
||||
case 2 : newIncrement = 100; break;
|
||||
case 3 : newIncrement = 300; break;
|
||||
case 4 : newIncrement = 1200; break;
|
||||
default : newIncrement = 0; break; //update funkcije za score, još sam vratio ovo na 0
|
||||
}
|
||||
return newIncrement * (level + 1);
|
||||
}
|
||||
|
||||
void UpdateBoard()
|
||||
{
|
||||
short firstLine, numberOfLines;
|
||||
//pozivamo funkciju
|
||||
do {
|
||||
CheckLines(firstLine, numberOfLines);
|
||||
for(int i = firstLine; i >= numberOfLines; i--) {
|
||||
for(int j = 0; j < 10; j++) {
|
||||
board[i][j] = board[i - numberOfLines][j];
|
||||
board[i - numberOfLines][j] = 0;
|
||||
short tmp = i - numberOfLines;
|
||||
display.fillrect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , colors[board[i][j]]); // bojimo novi blok
|
||||
display.fillrect( j * DIMENSION, tmp * DIMENSION,(j + 1) * DIMENSION, (tmp + 1) * DIMENSION , White);
|
||||
if(board[i][j] != 0)
|
||||
display.rect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , Black);
|
||||
}
|
||||
}
|
||||
score += UpdateScore(numberOfLines);
|
||||
}
|
||||
while(numberOfLines != 0); //ovdje se mijenja globalna varijabla score
|
||||
}
|
||||
|
||||
bool IsOver() {
|
||||
for(int i = 0; i < 10; i++) {
|
||||
if(board[0][i] != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShowGameOverScreen() {
|
||||
//////// PORTAPACK - SKIP CLS
|
||||
// display.cls();
|
||||
// display.background(Black);
|
||||
// display.foreground(White);
|
||||
display.background(White);
|
||||
display.foreground(Black);
|
||||
//////// PORTAPACK
|
||||
display.locate(60, 120);
|
||||
printf("GAME OVER");
|
||||
display.locate(40, 150);
|
||||
printf("YOUR SCORE IS %d", score);
|
||||
wait(5); //ovaj prikaz traje 3s (možemo mijenjati) a nakon toga se ponovo prikazuje meni sa levelima
|
||||
}
|
||||
|
||||
void InitGame() {
|
||||
if(firstTime) {
|
||||
//////// PORTAPACK - NOTE - ATTEMPTED WORKAROUND FOR SKIPPED INITIALIZER CODE - BUT ANY OF THESE CRASHES FIRMWARE AT POWER-UP EVEN IF THERE'S NO TETRIS APP INSTALLED:
|
||||
// currentTetromino = Tetromino(rand() % 7 + 1); // TEST #1
|
||||
// currentTetromino.Initialize(rand() % 7 + 1); // TEST #2
|
||||
//////// PORTAPACK
|
||||
currentTetromino.DrawFigure();
|
||||
nextFigure = rand() % 7 + 1;
|
||||
ShowNextFigure();
|
||||
firstTime = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayGame(){
|
||||
InitGame();
|
||||
if(!currentTetromino.MoveDown()){
|
||||
currentTetromino.OnAttached();
|
||||
UpdateBoard();
|
||||
ShowScore();
|
||||
|
||||
currentTetromino = Tetromino(nextFigure);
|
||||
currentTetromino.DrawFigure();
|
||||
nextFigure = rand() % 7 + 1;
|
||||
ShowNextFigure();
|
||||
if(IsOver()) {
|
||||
//ako je igra završena brišemo sve sa displey-a, prikazujemo poruku i score
|
||||
//takođe moramo dettach-at ticker
|
||||
game.detach();
|
||||
ShowGameOverScreen(); //prikaz da je kraj igre, ima wait od 3s
|
||||
EndPlay();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OnTasterPressed(){
|
||||
if(debounceTaster.read_ms() > 200) {
|
||||
if(gameStarted){
|
||||
currentTetromino.Rotate();
|
||||
}
|
||||
else{
|
||||
joystick.detach();
|
||||
gameStarted = true;
|
||||
StartGame(); //pocinje igra, prikazuje se tabla
|
||||
joystick.attach(&ReadJoystickForFigure, 0.3);
|
||||
game.attach(&PlayGame, delays[level]); //svakih nekoliko spusta figuru jedan red nize
|
||||
}
|
||||
debounceTaster.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void SetTaster() {
|
||||
taster.mode(PullUp); //mora se aktivirati pull up otpornik na tasteru joystick-a
|
||||
taster.fall(&OnTasterPressed);
|
||||
debounceTaster.reset();
|
||||
debounceTaster.start();
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(GenerateRandomSeed());
|
||||
Init();
|
||||
ShowLevelMenu();
|
||||
joystick.attach(&ReadJoystickForLevel, 0.3);
|
||||
SetTaster();
|
||||
|
||||
//////// PORTAPACK: CAN'T HANG HERE IN MAYHEM OR WE WON'T GET ANY CALLBACKS
|
||||
// while(1);
|
||||
return 0;
|
||||
//////// PORTAPACK
|
||||
}
|
||||
|
||||
//////// PORTAPACK - ADDED PAUSE FEATURE:
|
||||
void pause_game() {
|
||||
game.detach();
|
||||
joystick.detach();
|
||||
display.locate(180, 200);
|
||||
printf("PAUSED");
|
||||
while ((get_switches_state().to_ulong() & 0x10) == 0); // wait for SELECT button to resume
|
||||
printf(" ");
|
||||
joystick.attach(&ReadJoystickForFigure, 0.3);
|
||||
game.attach(&PlayGame, delays[level]); //svakih nekoliko spusta figuru jedan red nize
|
||||
};
|
||||
//////// PORTAPACK
|
||||
39
firmware/application/external/tetris/ui_tetris.cpp
vendored
Normal file
39
firmware/application/external/tetris/ui_tetris.cpp
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "ui_tetris.hpp"
|
||||
|
||||
namespace ui::external_app::tetris {
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
// external code, so ignore warnings
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#include "tetris.cpp"
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
TetrisView::TetrisView(NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
add_children({&dummy});
|
||||
}
|
||||
|
||||
void TetrisView::paint(Painter& painter) {
|
||||
(void)painter;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
std::srand(LPC_RTC->CTIME0);
|
||||
main();
|
||||
}
|
||||
}
|
||||
|
||||
void TetrisView::frame_sync() {
|
||||
check_fall_timer();
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
bool TetrisView::on_encoder(const EncoderEvent delta) {
|
||||
return check_encoder(delta);
|
||||
}
|
||||
|
||||
bool TetrisView::on_key(const KeyEvent key) {
|
||||
return check_key(key);
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::tetris
|
||||
65
firmware/application/external/tetris/ui_tetris.hpp
vendored
Normal file
65
firmware/application/external/tetris/ui_tetris.hpp
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_TETRIS_H__
|
||||
#define __UI_TETRIS_H__
|
||||
|
||||
#include "ui_navigation.hpp"
|
||||
#include "event_m0.hpp"
|
||||
#include "message.hpp"
|
||||
#include "irq_controls.hpp"
|
||||
#include "ui_styles.hpp"
|
||||
#include "random.hpp"
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
#include "limits.h"
|
||||
|
||||
namespace ui::external_app::tetris {
|
||||
|
||||
class TetrisView : public View {
|
||||
public:
|
||||
TetrisView(NavigationView& nav);
|
||||
|
||||
std::string title() const override { return "Tetris"; };
|
||||
|
||||
void focus() override { dummy.focus(); };
|
||||
void paint(Painter& painter) override;
|
||||
void frame_sync();
|
||||
bool on_encoder(const EncoderEvent event) override;
|
||||
bool on_key(KeyEvent key) override;
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
NavigationView& nav_;
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->frame_sync();
|
||||
}};
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::tetris
|
||||
|
||||
#endif /*__UI_TETRIS_H__*/
|
||||
@@ -149,7 +149,33 @@ void MAX2837::init() {
|
||||
set_mode(Mode::Standby);
|
||||
}
|
||||
|
||||
enum class Mask {
|
||||
void MAX2837::set_tx_LO_iq_phase_calibration(const size_t v) {
|
||||
/* IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */
|
||||
|
||||
// TX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,0,1 (5dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
|
||||
set_mode(Mode::Tx_Calibration); // write to ram 3 LOGIC Pins .
|
||||
|
||||
gpio_max283x_enable.output();
|
||||
gpio_max2837_rxenable.output();
|
||||
gpio_max2837_txenable.output();
|
||||
|
||||
_map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
|
||||
flush_one(Register::SPI_EN);
|
||||
|
||||
_map.r.tx_lo_iq.TXLO_IQ_SPI_EN = 1; // reg 30 D5, TX LO I/Q Phase SPI Adjust. Active when Address 30 D5 (TXLO_IQ_SPI_EN) = 1.
|
||||
_map.r.tx_lo_iq.TXLO_IQ_SPI = v; // reg 30 D4:D0, TX LO I/Q Phase SPI Adjust.
|
||||
flush_one(Register::TX_LO_IQ);
|
||||
|
||||
// Exit Calibration mode, Go back to reg 16, D1:D0 , Out of CALIBRATION , back to default conditions, but keep CS activated.
|
||||
_map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (0 = Normal operation (default)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable )
|
||||
flush_one(Register::SPI_EN);
|
||||
|
||||
set_mode(Mode::Standby); // Back 3 logic pins CALIBRATION mode -> Standby.
|
||||
}
|
||||
|
||||
enum class Mask { // There are class Mask ,and class mode with same names, but they are not same.
|
||||
Enable = 0b001,
|
||||
RxEnable = 0b010,
|
||||
TxEnable = 0b100,
|
||||
@@ -157,9 +183,11 @@ enum class Mask {
|
||||
Standby = Enable,
|
||||
Receive = Enable | RxEnable,
|
||||
Transmit = Enable | TxEnable,
|
||||
Rx_calibration = Enable | RxEnable, // sets the same 3 x logic pins to the Receive operating mode.
|
||||
Tx_calibration = Enable | TxEnable, // sets the same 3 x logic pins to the Transmit operating mode.
|
||||
};
|
||||
|
||||
Mask mode_mask(const Mode mode) {
|
||||
Mask mode_mask(const Mode mode) { // based on enum Mode cases, we set up the correct 3 logic PINS .
|
||||
switch (mode) {
|
||||
case Mode::Standby:
|
||||
return Mask::Standby;
|
||||
@@ -167,12 +195,16 @@ Mask mode_mask(const Mode mode) {
|
||||
return Mask::Receive;
|
||||
case Mode::Transmit:
|
||||
return Mask::Transmit;
|
||||
case Mode::Rx_Calibration: // Let's add those two CAL logic pin settings- Rx and Tx calibration modes.
|
||||
return Mask::Rx_calibration; // same logic pins as Receive mode = Enable | RxEnable, (the difference is in Reg add 16 D1:DO)
|
||||
case Mode::Tx_Calibration: // Let's add this CAL Tx calibration mode = Transmit.
|
||||
return Mask::Tx_calibration; // same logic pins as Transmit = Enable | TxEnable,(the difference is in Reg add 16 D1:DO)
|
||||
default:
|
||||
return Mask::Shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
void MAX2837::set_mode(const Mode mode) {
|
||||
void MAX2837::set_mode(const Mode mode) { // We set up the 3 Logic Pins ENABLE, RXENABLE, TXENABLE accordingly to the max2837 mode case, that we want to set up .
|
||||
Mask mask = mode_mask(mode);
|
||||
gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable));
|
||||
gpio_max2837_rxenable.write(toUType(mask) & toUType(Mask::RxEnable));
|
||||
|
||||
@@ -829,6 +829,7 @@ class MAX2837 : public MAX283x {
|
||||
bool set_frequency(const rf::Frequency lo_frequency) override;
|
||||
|
||||
void set_rx_lo_iq_calibration(const size_t v) override;
|
||||
void set_tx_LO_iq_phase_calibration(const size_t v) override;
|
||||
void set_rx_bias_trim(const size_t v);
|
||||
void set_vco_bias(const size_t v);
|
||||
void set_rx_buff_vcm(const size_t v) override;
|
||||
|
||||
@@ -142,6 +142,31 @@ void MAX2839::init() {
|
||||
set_mode(Mode::Standby);
|
||||
}
|
||||
|
||||
void MAX2839::set_tx_LO_iq_phase_calibration(const size_t v) {
|
||||
/* IQ phase deg CAL adj (+4 ...-4) This IC in 64 steps (6 bits), 000000 = +4deg (Q lags I by 94degs, default), 011111 = +0deg, 111111 = -4deg (Q lags I by 86degs) */
|
||||
|
||||
// TX calibration , 2 x Logic pins , ENABLE, RXENABLE = 1,0, (2dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
|
||||
set_mode(Mode::Tx_Calibration); // write to ram 3 LOGIC Pins .
|
||||
|
||||
gpio_max283x_enable.output(); // max2839 has only 2 x pins + regs to decide mode.
|
||||
gpio_max2839_rxtx.output(); // Here is combined rx & tx pin in one port.
|
||||
|
||||
_map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
|
||||
flush_one(Register::SPI_EN);
|
||||
|
||||
_map.r.pa_drv.TXLO_IQ_SPI_EN = 1; // reg 27 D6, TX LO I/Q Phase SPI Adjust. Active when Address 27 D6 (TXLO_IQ_SPI_EN) = 1.
|
||||
_map.r.pa_drv.TXLO_IQ_SPI = v; // reg 27 D5:D0 6 bits, TX LO I/Q Phase SPI Adjust.
|
||||
flush_one(Register::PA_DRV);
|
||||
|
||||
// Exit Calibration mode, Go back to reg 16, D1:D0 , Out of CALIBRATION , back to default conditions, but keep CS activated.
|
||||
_map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (0 = Normal operation (default)
|
||||
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable )
|
||||
flush_one(Register::SPI_EN);
|
||||
|
||||
set_mode(Mode::Standby); // Back 3 logic pins CALIBRATION mode -> Standby.
|
||||
}
|
||||
|
||||
enum class Mask {
|
||||
Enable = 0b01,
|
||||
RxTx = 0b10,
|
||||
@@ -149,6 +174,8 @@ enum class Mask {
|
||||
Standby = RxTx,
|
||||
Receive = Enable | RxTx,
|
||||
Transmit = Enable,
|
||||
Rx_calibration = Enable | RxTx, // sets the same 2 x logic pins to the Receive operating mode.
|
||||
Tx_calibration = Enable, // sets the same 2 x logic pins to the Transmit operating mode.
|
||||
};
|
||||
|
||||
Mask mode_mask(const Mode mode) {
|
||||
@@ -159,6 +186,10 @@ Mask mode_mask(const Mode mode) {
|
||||
return Mask::Receive;
|
||||
case Mode::Transmit:
|
||||
return Mask::Transmit;
|
||||
case Mode::Rx_Calibration: // Let's add this not used previously Rx calibration mode.
|
||||
return Mask::Rx_calibration; // same logic pins as Receive mode = Enable | RxTx, ,(the difference is in Regs )
|
||||
case Mode::Tx_Calibration: // Let's add this not used previously Tx calibration mode.
|
||||
return Mask::Tx_calibration; // same logic pins as Transmit = Enable , (the difference is in Reg add 16 D1:DO)
|
||||
default:
|
||||
return Mask::Shutdown;
|
||||
}
|
||||
|
||||
@@ -690,6 +690,7 @@ class MAX2839 : public MAX283x {
|
||||
void set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) override;
|
||||
bool set_frequency(const rf::Frequency lo_frequency) override;
|
||||
void set_rx_lo_iq_calibration(const size_t v) override;
|
||||
void set_tx_LO_iq_phase_calibration(const size_t v) override;
|
||||
void set_rx_buff_vcm(const size_t v) override;
|
||||
|
||||
int8_t temp_sense() override;
|
||||
|
||||
@@ -98,11 +98,13 @@ constexpr auto bandwidth_maximum = bandwidths[bandwidths.size() - 1];
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
enum Mode {
|
||||
enum Mode { // MAX283x Operating modes.
|
||||
Shutdown,
|
||||
Standby,
|
||||
Receive,
|
||||
Transmit,
|
||||
Rx_Calibration, // just add the sequential enum of those two CAL operating modes .
|
||||
Tx_Calibration,
|
||||
};
|
||||
|
||||
using reg_t = uint16_t;
|
||||
@@ -124,6 +126,8 @@ class MAX283x {
|
||||
virtual bool set_frequency(const rf::Frequency lo_frequency);
|
||||
|
||||
virtual void set_rx_lo_iq_calibration(const size_t v);
|
||||
virtual void set_tx_LO_iq_phase_calibration(const size_t v);
|
||||
|
||||
virtual void set_rx_buff_vcm(const size_t v);
|
||||
|
||||
virtual int8_t temp_sense();
|
||||
|
||||
@@ -248,6 +248,10 @@ void set_antenna_bias(const bool on) {
|
||||
}
|
||||
}
|
||||
|
||||
void set_tx_max283x_iq_phase_calibration(const size_t v) {
|
||||
second_if->set_tx_LO_iq_phase_calibration(v);
|
||||
}
|
||||
|
||||
/*void enable(Configuration configuration) {
|
||||
configure(configuration);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ void set_baseband_filter_bandwidth_rx(const uint32_t bandwidth_minimum);
|
||||
void set_baseband_filter_bandwidth_tx(const uint32_t bandwidth_minimum);
|
||||
void set_baseband_rate(const uint32_t rate);
|
||||
void set_antenna_bias(const bool on);
|
||||
void set_tx_max283x_iq_phase_calibration(const size_t v);
|
||||
|
||||
/* Use ReceiverModel or TransmitterModel instead. */
|
||||
// void enable(Configuration configuration);
|
||||
|
||||
BIN
firmware/graphics/icon_tetris.png
Normal file
BIN
firmware/graphics/icon_tetris.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 179 B |
@@ -2,31 +2,20 @@
|
||||
# (Freq range in MHz, min separation 3MHz)
|
||||
# (Description up to 20 char)
|
||||
# (fields comma delimiter)
|
||||
# PAGERS https://www.fcc.gov/wireless/bureau-divisions/mobility-division/paging
|
||||
34,36,USA PAGERS 35
|
||||
43,45,USA PAGERS 44
|
||||
151,153,USA PAGERS 152
|
||||
453,454,USA PAGERS 454
|
||||
929,931,USA PAGERS 930
|
||||
# KEYFOBS
|
||||
260,500,315/433 MHz KEYFOBS
|
||||
# MICS, RADIOSONDES, LEYFOB
|
||||
140,380,VHF MICS AND MARINE
|
||||
390,420,RADIOSONDES
|
||||
420,660,UHF MICS
|
||||
# LoRa
|
||||
433,435,LoRa 443EU
|
||||
863,870,LoRa 868EU
|
||||
902,928,LoRa 915US
|
||||
779,787,LoRa 780CN
|
||||
# BROADCAST RADIO
|
||||
65,74,FM BROADCAST RUSSIA
|
||||
76,95,FM BROADCAST JAPAN
|
||||
76,108,FM BROADCAST BRAZIL
|
||||
87,108,FM BROADCAST
|
||||
# 433 MHz BAND
|
||||
423,443,433 BAND
|
||||
# AVIATION
|
||||
108,137,AVIATION 108
|
||||
960,1215,AVIATION 960
|
||||
# BROADCAST RADIO
|
||||
87,108,FM BROADCAST
|
||||
76,108,FM BROADCAST BRAZIL
|
||||
76,95,FM BROADCAST JAPAN
|
||||
65,74,FM BROADCAST RUSSIA
|
||||
# DECT
|
||||
1879,1931,DECT
|
||||
# FRS/GMRS
|
||||
462,468,FRS/GMRS
|
||||
# HAM RADIO
|
||||
28,30,HAM 10-METER
|
||||
50,54,HAM 6-METER
|
||||
@@ -35,6 +24,26 @@
|
||||
420,450,HAM 70-CM
|
||||
902,928,HAM 33-CM
|
||||
1240,1300,HAM 23-CM
|
||||
# KEYFOBS
|
||||
260,500,315/433 MHz KEYFOBS
|
||||
# LoRa
|
||||
433,435,LoRa 443EU
|
||||
863,870,LoRa 868EU
|
||||
902,928,LoRa 915US
|
||||
779,787,LoRa 780CN
|
||||
# MARINE BAND
|
||||
155,163,MARINE VHF
|
||||
# MICS
|
||||
140,380,MICS (VHF) AND MARINE
|
||||
420,660,MICS (UHF)
|
||||
# PAGERS https://www.fcc.gov/wireless/bureau-divisions/mobility-division/paging
|
||||
34,36,USA PAGERS 35
|
||||
43,45,USA PAGERS 44
|
||||
151,153,USA PAGERS 152
|
||||
453,454,USA PAGERS 454
|
||||
929,931,USA PAGERS 930
|
||||
# RADIOSONDES
|
||||
390,420,RADIOSONDES
|
||||
# WATER METERS
|
||||
850,900,Water meters
|
||||
902,928,ISM 900MHz
|
||||
|
||||
Reference in New Issue
Block a user