Skip to content

Commit

Permalink
Version independent external apps (standalone apps) (#2145)
Browse files Browse the repository at this point in the history
This pull requests adds a new type of external app to the firmware: The standalone app.

Pros:

Will work after an upgrade.
Size of image is only limited by shared heap size of M0 (application) (64kb total).
Cons:

No full access to all functions in the main firmware. One well defined (and versioned) API handles all communication.
The Pacman app was converted to be the first the the new kind.
  • Loading branch information
bernd-herzog committed May 12, 2024
1 parent fe71592 commit 100bea6
Show file tree
Hide file tree
Showing 23 changed files with 807 additions and 120 deletions.
6 changes: 4 additions & 2 deletions firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ endif()

add_subdirectory(application)
add_subdirectory(baseband)
add_subdirectory(standalone)
add_subdirectory(test)

# NOTE: Dependencies break if the .bin files aren't included in DEPENDS. WTF, CMake?
Expand Down Expand Up @@ -88,7 +89,7 @@ add_custom_target(
program-external-apps
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${PROJECT_SOURCE_DIR}/tools/copy_external_apps.sh
DEPENDS program
DEPENDS program standalone_apps
)

add_custom_command(
Expand All @@ -100,8 +101,9 @@ add_custom_command(
COMMAND cp ${FIRMWARE_FILENAME} firmware_tar/FIRMWARE/portapack-mayhem_${VERSION_NOHASH}.bin
COMMAND mkdir -p firmware_tar/APPS
COMMAND cp application/*.ppma firmware_tar/APPS
COMMAND cp standalone/*/*.ppmp firmware_tar/APPS
COMMAND cd firmware_tar && tar -cvaf ../${PPFW_FILENAME} *
DEPENDS firmware ${FIRMWARE_FILENAME}
DEPENDS firmware ${FIRMWARE_FILENAME} standalone_apps
# Dont use VERBATIM here as it prevents usage of globbing (*)
# There shouldnt be any funny business in the filenames above :)
)
Expand Down
1 change: 1 addition & 0 deletions firmware/application/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ set(CPPSRC
# apps/ui_spectrum_painter.cpp
apps/ui_ss_viewer.cpp
apps/ui_sstvtx.cpp
apps/ui_standalone_view.cpp
apps/ui_subghzd.cpp
# apps/ui_test.cpp
apps/ui_text_editor.cpp
Expand Down
82 changes: 82 additions & 0 deletions firmware/application/apps/ui_standalone_view.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2024 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along 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_standalone_view.hpp"
#include "irq_controls.hpp"

namespace ui {

void create_thread(int32_t (*fn)(void*), void* arg, size_t stack_size, int priority) {
// TODO: collect memory on terminate, once this is used
chThdCreateFromHeap(NULL, stack_size, priority, fn, arg);
}

void fill_rectangle(int x, int y, int width, int height, uint16_t color) {
ui::Painter painter;
painter.fill_rectangle({x, y, width, height}, ui::Color(color));
}

void* alloc(size_t size) {
void* p = chHeapAlloc(0x0, size);
if (p == nullptr)
chDbgPanic("Out of Memory");
return p;
}

uint64_t get_switches_state_ulong() {
return get_switches_state().to_ulong();
}

standalone_application_api_t api = {
/* .malloc = */ &alloc,
/* .calloc = */ &calloc,
/* .realloc = */ &realloc,
/* .free = */ &chHeapFree,
/* .create_thread = */ &create_thread,
/* .fill_rectangle = */ &fill_rectangle,
/* .swizzled_switches = */ &swizzled_switches,
/* .get_switches_state = */ &get_switches_state_ulong,
};

StandaloneView::StandaloneView(NavigationView& nav, std::unique_ptr<uint8_t[]> app_image)
: nav_(nav), _app_image(std::move(app_image)) {
get_application_information()->initialize(api);
add_children({&dummy});
}

void StandaloneView::focus() {
dummy.focus();
}

void StandaloneView::paint(Painter& painter) {
(void)painter;
}

void StandaloneView::frame_sync() {
// skip first refresh
if (!initialized) {
initialized = true;
} else {
get_application_information()->on_event(1);
}
}

} // namespace ui
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Bernd Herzog
* Copyright (C) 2024 Bernd Herzog
*
* This file is part of PortaPack.
*
Expand All @@ -19,29 +19,35 @@
* Boston, MA 02110-1301, USA.
*/

#ifndef __UI_PACMAN_H__
#define __UI_PACMAN_H__
#ifndef __UI_STANDALONE_VIEW_H__
#define __UI_STANDALONE_VIEW_H__

#include "ui_navigation.hpp"
#include "event_m0.hpp"
#include "message.hpp"
#include "standalone_app.hpp"

namespace ui::external_app::pacman {
namespace ui {

class PacmanView : public View {
class StandaloneView : public View {
public:
PacmanView(NavigationView& nav);
StandaloneView(NavigationView& nav, std::unique_ptr<uint8_t[]> app_image);
virtual ~StandaloneView() override { get_application_information()->shutdown(); }

void focus() override;

std::string title() const override { return "Pac-Man"; };
std::string title() const override { return (const char*)get_application_information()->app_name; };

void paint(Painter& painter) override;
void frame_sync();

private:
bool initialized = false;
NavigationView& nav_;
std::unique_ptr<uint8_t[]> _app_image;
standalone_application_information_t* get_application_information() const {
return reinterpret_cast<standalone_application_information_t*>(_app_image.get());
}

Button dummy{
{240, 0, 0, 0},
Expand All @@ -54,6 +60,6 @@ class PacmanView : public View {
}};
};

} // namespace ui::external_app::pacman
} // namespace ui

#endif /*__UI_PACMAN_H__*/
#endif /*__UI_STANDALONE_VIEW_H__*/
5 changes: 0 additions & 5 deletions firmware/application/external/external.cmake
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
set(EXTCPPSRC

#pacman
external/pacman/main.cpp
external/pacman/ui_pacman.cpp

#tetris
external/tetris/main.cpp
external/tetris/ui_tetris.cpp
Expand Down Expand Up @@ -87,7 +83,6 @@ set(EXTCPPSRC
)

set(EXTAPPLIST
pacman
afsk_rx
calculator
font_viewer
Expand Down
7 changes: 0 additions & 7 deletions firmware/application/external/external.ld
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ MEMORY
* Also need to consider processor memory map - reading 0xADxxxxxx generates a fault which may be better than unexpected behavior.
* External app address ranges below must match those in python file "external_app_info.py".
*/
ram_external_app_pacman (rwx) : org = 0xADB00000, len = 32k
ram_external_app_afsk_rx (rwx) : org = 0xADB10000, len = 32k
ram_external_app_calculator (rwx) : org = 0xADB20000, len = 32k
ram_external_app_font_viewer(rwx) : org = 0xADB30000, len = 32k
Expand All @@ -47,12 +46,6 @@ MEMORY

SECTIONS
{
.external_app_pacman : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_pacman.application_information));
*(*ui*external_app*pacman*);
} > ram_external_app_pacman

.external_app_afsk_rx : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_afsk_rx.application_information));
Expand Down
65 changes: 0 additions & 65 deletions firmware/application/external/pacman/ui_pacman.cpp

This file was deleted.

Loading

0 comments on commit 100bea6

Please sign in to comment.