Commit 861d604a authored by schneider's avatar schneider

Merge branch 'schneider/default-main-master' into 'master'

Default main app selector

See merge request !375
parents 6e823291 9b737f6a
Pipeline #4542 passed with stages
in 2 minutes and 35 seconds
......@@ -40,4 +40,6 @@ Option name Type Description
``execute_elf`` Boolean Allow running of binary :ref:`l0dables`. These files can be nefarious, so this option is off by default.
--------------- ---------- -----------
``timezone`` String Timezone for card10; must be of format ``[+-]HHMM``. Examples: ``+0800``, ``-0200``
--------------- ---------- -----------
``default_app`` String Full path to the exectutable file of the default application. If this option is not set,``apps/analog_clock/__init__.py`` is used.
=============== ========== ===========
......@@ -62,6 +62,8 @@ class ColorExample(rst.Directive):
color = self.arguments[0]
html_text = '<div style="width: 30px;height: 30px;background: {};border: black 1px solid;border-radius: 15px;"></div>'
return [nodes.raw("", html_text.format(color), format="html")]
# }}}
# -- Options for HTML output ------------------------------------------------- {{{
......@@ -112,6 +114,7 @@ autodoc_mock_imports = [
"sys_display",
"sys_leds",
"sys_max30001",
"sys_config",
"ucollections",
"urandom",
"utime",
......
......@@ -27,6 +27,7 @@ Last but not least, if you want to start hacking the lower-level firmware, the
pycardium/max30001
pycardium/buttons
pycardium/color
pycardium/config
pycardium/display
pycardium/gpio
pycardium/leds
......
``config`` - Configuration
==========================
The ``config`` module provides functions to interact with card10's
configuration file (``card10.cfg``).
.. automodule:: config
:members:
......@@ -145,6 +145,7 @@ typedef _Bool bool;
#define API_CONFIG_GET_STRING 0x130
#define API_CONFIG_GET_INTEGER 0x131
#define API_CONFIG_GET_BOOLEAN 0x132
#define API_CONFIG_SET_STRING 0x133
/* clang-format on */
typedef uint32_t api_int_id_t;
......@@ -2060,5 +2061,21 @@ API(API_CONFIG_GET_BOOLEAN, int epic_config_get_boolean(const char *key, bool *v
API(API_CONFIG_GET_STRING, int epic_config_get_string(const char *key, char *buf, size_t buf_len));
/**
* Write a string to the configuration file.
*
* :param char* key: Name of the option to write
* :param char* value: The value to write
* :return: `0` on success or a negative value if an error occured. Possivle
* errors:
*
* - ``-EINVAL``: Parameters out of range
* - ``-ENOENT``: Key already exists but can not be read
* - ``-EIO`` : Unspecified I/O error
* - Any fopen/fread/fwrite/fclose related error code
*
* .. versionadded:: 1.16
*/
API(API_CONFIG_SET_STRING, int epic_config_set_string(const char *key, const char *value));
#endif /* _EPICARDIUM_H */
This diff is collapsed.
......@@ -12,6 +12,7 @@
#include "epicardium.h"
#include "modules/filesystem.h"
#include "modules/config.h"
#include "usb/cdcacm.h"
#include "usb/mass_storage.h"
......@@ -139,6 +140,7 @@ int epic_usb_shutdown(void)
esb_deinit();
if (s_fsDetached) {
fatfs_attach();
load_config();
}
return 0;
}
......@@ -155,6 +157,7 @@ int epic_usb_cdcacm(void)
esb_deinit();
if (s_fsDetached) {
fatfs_attach();
load_config();
}
return esb_init(&s_cfg_cdcacm);
}
......
......@@ -3,7 +3,13 @@ import os
def main():
# Try loading analog clock
default_app = "apps/analog_clock/__init__.py"
try:
import config
default_app = config.get_string("default_app")
except OSError:
default_app = "apps/analog_clock/__init__.py"
try:
with open(default_app, "r"):
pass
......
......@@ -90,6 +90,24 @@ def usb_mode(disp):
os.exit(0)
class SubMenu(simple_menu.Menu):
timeout = 30.0
def on_select(self, name, index):
print(name)
if name == "Make Default":
self.disp.clear(color.CHAOSBLUE)
self.disp.print("Making", posx=0, posy=20)
self.disp.print(self.app.name, posx=0, posy=40)
self.disp.print("default", posx=0, posy=60)
self.disp.update()
import config
config.set_string("default_app", self.app.path)
utime.sleep(1)
self.exit()
class MainMenu(simple_menu.Menu):
timeout = 30.0
......@@ -112,6 +130,14 @@ class MainMenu(simple_menu.Menu):
utime.sleep(1.0)
os.exit(1)
def on_long_select(self, app, index):
print("Long press\n")
if app.path not in ["main.py", "USB_STORAGE_FLAG"]:
# sm = SubMenu(("Make Default", "Fav", "Unfav", "Delete", "Exit"))
sm = SubMenu(("Make Default", "Exit", "", ""))
sm.app = app
sm.run()
def on_timeout(self):
try:
f = open("main.py")
......
......@@ -3,6 +3,7 @@ name = 'pycardium'
modsrc = files(
'modules/bhi160-sys.c',
'modules/buttons.c',
'modules/sys_config.c',
'modules/fat_file.c',
'modules/fat_reader_import.c',
'modules/gpio.c',
......
import sys_config
def set_string(key, value):
"""
Write a string to the configuration file ``card10.cfg``.
Both ``key`` and ``value`` must be strings or must be
convertible to a string using the ``str()`` function.
``key`` must not contain spaces, control characters (including tabs),
number signs ans equal signs.
``value` must not contain control characters (including tabs).
Neither is allowed to contain the sub-string ``execute_elf``.
The key/value pair is immediately written to the configuration
file (``card10.cfg``). After the file is written, configuration
is read again and the new value is available via ``config.get_string``.
:param str key: Name of the configuration option.
:param str value: Value to write.
:raises OSError: If writing to the configuration file failed.
:raises OSError: If key or value contain illegal characters.
:raises ValueError: If key or value contain the sub-string ``execute_elf``.
.. versionadded:: 1.16
"""
sys_config.set_string(str(key), str(value))
def get_string(key):
"""
Read a string from the configuration file ``card10.cfg``.
``key`` must be a string or must be convertible to a string using
the ``str()`` function.
:param str key: Name of the configuration option.
:rtype: str
:returns: Value of the configuration option.
:raises OSError: if the key is not present in the configuration.
.. versionadded:: 1.16
"""
return sys_config.get_string(str(key))
python_modules = files(
'config.py',
'bhi160.py',
'bme680.py',
'color.py',
......
......@@ -141,6 +141,18 @@ class Menu:
"""
pass
def on_long_select(self, item, index):
"""
Hook when an item as selected using a long press.
The given ``index`` was selected with a long SELECT button press. Overwrite
this function in your menu to perform an action on select.
:param item: The item which was selected.
:param int index: Index into the ``entries`` list of the ``item``.
"""
pass
def on_select(self, item, index):
"""
Hook when an item as selected.
......@@ -238,9 +250,7 @@ class Menu:
offset + 20,
col=self.color_1 if index % 2 == 0 else self.color_2,
)
self.disp.print(
string, posx=14, posy=offset, fg=self.color_text, bg=None,
)
self.disp.print(string, posx=14, posy=offset, fg=self.color_text, bg=None)
def draw_menu(self, offset=0):
"""
......@@ -318,8 +328,18 @@ class Menu:
print("Exception during menu.on_scroll():")
sys.print_exception(e)
elif ev == self.button_select:
t0 = utime.time()
long_press = False
while buttons.read(buttons.TOP_RIGHT) > 0:
if utime.time() - t0 > 1:
long_press = True
break
try:
self.on_select(self.entries[self.idx], self.idx)
if long_press:
self.on_long_select(self.entries[self.idx], self.idx)
else:
self.on_select(self.entries[self.idx], self.idx)
self.select_time = utime.time_ms()
except _ExitMenuException:
raise
......
......@@ -188,3 +188,7 @@ Q(MAX86150)
/* ws2812 */
Q(ws2812)
Q(set_all)
Q(config)
Q(set_string)
Q(get_string)
#include "epicardium.h"
#include "py/obj.h"
#include "py/runtime.h"
#include <string.h>
#include <strings.h>
#include <stdbool.h>
static void extract_string(
mp_obj_t obj, char *buf, size_t buf_len, const char *error_message
) {
size_t len;
const char *str_ptr = mp_obj_str_get_data(obj, &len);
/*
* The string retrieved from MicroPython is not NULL-terminated so we
* first need to copy it and add a NULL-byte.
*/
if (len > (buf_len - 1)) {
mp_raise_ValueError(error_message);
}
memcpy(buf, str_ptr, len);
buf[len] = '\0';
}
static mp_obj_t mp_config_set_string(mp_obj_t key_in, mp_obj_t value_in)
{
const char *const forbidden_key = "execute_elf";
char key_str[128], value_str[128];
extract_string(key_in, key_str, sizeof(key_str), "key too long");
extract_string(
value_in, value_str, sizeof(value_str), "value too long"
);
if (strstr(key_str, forbidden_key) != NULL ||
strstr(value_str, forbidden_key) != NULL) {
/* A Permission Error might be nice but is not available in MP */
mp_raise_ValueError("Not allowed");
}
int status = epic_config_set_string(key_str, value_str);
if (status < 0) {
mp_raise_OSError(-status);
}
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_2(set_string_obj, mp_config_set_string);
static mp_obj_t mp_config_get_string(mp_obj_t key_in)
{
char key_str[128], value_str[128];
extract_string(key_in, key_str, sizeof(key_str), "key too long");
int status =
epic_config_get_string(key_str, value_str, sizeof(value_str));
if (status < 0) {
mp_raise_OSError(-status);
}
mp_obj_t ret = mp_obj_new_str(value_str, strlen(value_str));
return ret;
}
static MP_DEFINE_CONST_FUN_OBJ_1(get_string_obj, mp_config_get_string);
static const mp_rom_map_elem_t config_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys_config) },
{ MP_ROM_QSTR(MP_QSTR_set_string), MP_ROM_PTR(&set_string_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_string), MP_ROM_PTR(&get_string_obj) },
};
static MP_DEFINE_CONST_DICT(config_module_globals, config_module_globals_table);
// Define module object.
const mp_obj_module_t config_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&config_module_globals,
};
/* This is a special macro that will make MicroPython aware of this module */
/* clang-format off */
MP_REGISTER_MODULE(MP_QSTR_sys_config, config_module, MODULE_CONFIG_ENABLED);
......@@ -64,6 +64,7 @@ int mp_hal_trng_read_int(void);
#define MODULE_UTIME_ENABLED (1)
#define MODULE_VIBRA_ENABLED (1)
#define MODULE_WS2812_ENABLED (1)
#define MODULE_CONFIG_ENABLED (1)
/*
* This port is intended to be 32-bit, but unfortunately, int32_t for
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment