TactilityC additions (#287)

New TactilityC implementations for:
- WiFi
- GPS
- Preferences
- Timezone

Also includes:
- Some fixes to enums/naming
- Cleanup elsewhere
This commit is contained in:
Ken Van Hoeylandt 2025-06-09 13:46:08 +02:00 committed by GitHub
parent 869a56125f
commit 1593eb80ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 528 additions and 64 deletions

View File

@ -9,13 +9,18 @@ import time
import urllib.request import urllib.request
import zipfile import zipfile
esp_platforms = ["esp32", "esp32s3"] # Targetable platforms that represent a specific hardware target
platform_targets = ["esp32", "esp32s3"]
# All valid platform commandline arguments
platform_arguments = platform_targets.copy()
platform_arguments.append("all")
ttbuild_path = ".tactility" ttbuild_path = ".tactility"
ttbuild_version = "0.1.0" ttbuild_version = "0.3.0"
ttbuild_properties_file = "tactility.properties" ttbuild_properties_file = "tactility.properties"
ttbuild_cdn = "https://cdn.tactility.one" ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds ttbuild_sdk_json_validity = 3600 # seconds
verbose = False verbose = False
use_local_sdk = False
spinner_pattern = [ spinner_pattern = [
"", "",
@ -49,13 +54,17 @@ def print_help():
print("Usage: python tactility.py [action] [options]") print("Usage: python tactility.py [action] [options]")
print("") print("")
print("Actions:") print("Actions:")
print(" build [esp32,esp32s3,all] Build the app for 1 or more platforms") print(" build [esp32,esp32s3,all,local] Build the app for the specified platform")
print(" esp32: ESP32")
print(" esp32s3: ESP32 S3")
print(" all: all supported ESP platforms")
print(" clean Clean the build folders") print(" clean Clean the build folders")
print(" clearcache Clear the SDK cache") print(" clearcache Clear the SDK cache")
print(" updateself Update this tool") print(" updateself Update this tool")
print("") print("")
print("Options:") print("Options:")
print(" --help Show this commandline info") print(" --help Show this commandline info")
print(" --local-sdk Use SDK specifiedc by environment variable TACTILITY_SDK_PATH")
print(" --skip-build Run everything except the idf.py/CMake commands") print(" --skip-build Run everything except the idf.py/CMake commands")
print(" --verbose Show extra console output") print(" --verbose Show extra console output")
@ -92,22 +101,30 @@ def exit_with_error(message):
sys.exit(1) sys.exit(1)
def is_valid_platform_name(name): def is_valid_platform_name(name):
return name == "all" or name == "esp32" or name == "esp32s3" global platform_arguments
return name in platform_arguments
def validate_environment(): def validate_environment():
global ttbuild_properties_file global ttbuild_properties_file, use_local_sdk
if os.environ.get("IDF_PATH") is None: if os.environ.get("IDF_PATH") is None:
exit_with_error("IDF is not installed or activated. Ensure you installed the toolset and ran the export command.") exit_with_error("Cannot find the Espressif IDF SDK. Ensure it is installed and that it is activated via $PATH_TO_IDF_SDK/export.sh")
if os.environ.get("TACTILITY_SDK_PATH") is not None:
print_warning("TACTILITY_SDK_PATH is set, but will be ignored by this command")
if not os.path.exists(ttbuild_properties_file): if not os.path.exists(ttbuild_properties_file):
exit_with_error(f"{ttbuild_properties_file} file not found") exit_with_error(f"{ttbuild_properties_file} file not found")
if use_local_sdk == False and os.environ.get("TACTILITY_SDK_PATH") is not None:
print_warning("TACTILITY_SDK_PATH is set, but will be ignored by this command.")
print_warning("If you want to use it, use the 'build local' parameters.")
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def setup_environment(): def setup_environment():
global ttbuild_path global ttbuild_path
os.makedirs(ttbuild_path, exist_ok=True) os.makedirs(ttbuild_path, exist_ok=True)
def get_sdk_dir(version, platform): def get_sdk_dir(version, platform):
global use_local_sdk
if use_local_sdk:
return os.environ.get("TACTILITY_SDK_PATH")
else:
global ttbuild_cdn global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}", "TactilitySDK") return os.path.join(ttbuild_path, f"{version}-{platform}", "TactilitySDK")
@ -151,14 +168,14 @@ def update_sdk_json():
return download_file(json_url, json_filepath) return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(): def should_fetch_sdkconfig_files():
for platform in esp_platforms: for platform in platform_targets:
sdkconfig_filename = f"sdkconfig.app.{platform}" sdkconfig_filename = f"sdkconfig.app.{platform}"
if not os.path.exists(os.path.join(ttbuild_path, sdkconfig_filename)): if not os.path.exists(os.path.join(ttbuild_path, sdkconfig_filename)):
return True return True
return False return False
def fetch_sdkconfig_files(): def fetch_sdkconfig_files():
for platform in esp_platforms: for platform in platform_targets:
sdkconfig_filename = f"sdkconfig.app.{platform}" sdkconfig_filename = f"sdkconfig.app.{platform}"
target_path = os.path.join(ttbuild_path, sdkconfig_filename) target_path = os.path.join(ttbuild_path, sdkconfig_filename)
if not download_file(f"{ttbuild_cdn}/{sdkconfig_filename}", target_path): if not download_file(f"{ttbuild_cdn}/{sdkconfig_filename}", target_path):
@ -190,7 +207,7 @@ def validate_self(sdk_json):
if re.search(tool_compatibility, ttbuild_version) is None: if re.search(tool_compatibility, ttbuild_version) is None:
print_error("The tool is not compatible anymore.") print_error("The tool is not compatible anymore.")
print_error("Run 'tactility.py updateself' to update.") print_error("Run 'tactility.py updateself' to update.")
sys.exit() sys.exit(1)
def sdk_download(version, platform): def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform) sdk_root_dir = get_sdk_root_dir(version, platform)
@ -316,9 +333,11 @@ def build_action(platform_arg):
validate_environment() validate_environment()
# Environment setup # Environment setup
setup_environment() setup_environment()
platforms_to_build = platform_targets if platform_arg == "all" else [platform_arg]
if not is_valid_platform_name(platform_arg): if not is_valid_platform_name(platform_arg):
print_help() print_help()
exit_with_error("Invalid platform name") exit_with_error("Invalid platform name")
if not use_local_sdk:
if should_fetch_sdkconfig_files(): if should_fetch_sdkconfig_files():
fetch_sdkconfig_files() fetch_sdkconfig_files()
# Update SDK cache # Update SDK cache
@ -329,8 +348,8 @@ def build_action(platform_arg):
if not "versions" in sdk_json: if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json") exit_with_error("Version data not found in sdk.json")
# Build # Build
platforms_to_build = esp_platforms if platform_arg == "all" else [platform_arg]
sdk_version = get_sdk_version() sdk_version = get_sdk_version()
if not use_local_sdk:
validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build) validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build)
if not sdk_download_all(sdk_version, platforms_to_build): if not sdk_download_all(sdk_version, platforms_to_build):
exit_with_error("Failed to download one or more SDKs") exit_with_error("Failed to download one or more SDKs")
@ -373,14 +392,13 @@ if __name__ == "__main__":
action_arg = sys.argv[1] action_arg = sys.argv[1]
verbose = "--verbose" in sys.argv verbose = "--verbose" in sys.argv
skip_build = "--skip-build" in sys.argv skip_build = "--skip-build" in sys.argv
use_local_sdk = "--local-sdk" in sys.argv
# Actions # Actions
if action_arg == "build": if action_arg == "build":
if len(sys.argv) < 3: if len(sys.argv) < 3:
print_help() print_help()
sys.exit() exit_with_error("Commandline parameter missing")
else: build_action(sys.argv[2])
platform_arg = sys.argv[2]
build_action(platform_arg)
elif action_arg == "clean": elif action_arg == "clean":
clean_action() clean_action()
elif action_arg == "clearcache": elif action_arg == "clearcache":
@ -389,4 +407,4 @@ if __name__ == "__main__":
update_self_action() update_self_action()
else: else:
print_help() print_help()
sys.exit() exit_with_error("Unknown commandline parameter")

View File

@ -8,9 +8,13 @@ namespace tt {
/** /**
* Settings that persist on NVS flash for ESP32. * Settings that persist on NVS flash for ESP32.
* On simulator, the settings are only in-memory. * On simulator, the settings are only in-memory.
*
* Note that on ESP32, there are limitations:
* - namespace name is limited by NVS_NS_NAME_MAX_SIZE (generally 16 characters)
* - key is limited by NVS_KEY_NAME_MAX_SIZE (generally 16 characters)
*/ */
class Preferences { class Preferences {
private:
const char* namespace_; const char* namespace_;
public: public:

View File

@ -24,8 +24,6 @@ extern const AppManifest manifest;
class GpsSettingsApp final : public App { class GpsSettingsApp final : public App {
private:
std::unique_ptr<Timer> timer; std::unique_ptr<Timer> timer;
std::shared_ptr<GpsSettingsApp*> appReference = std::make_shared<GpsSettingsApp*>(this); std::shared_ptr<GpsSettingsApp*> appReference = std::make_shared<GpsSettingsApp*>(this);
lv_obj_t* statusWrapper = nullptr; lv_obj_t* statusWrapper = nullptr;
@ -96,7 +94,7 @@ private:
memcpy(&index, &index_as_voidptr, sizeof(int)); memcpy(&index, &index_as_voidptr, sizeof(int));
std::vector<tt::hal::gps::GpsConfiguration> configurations; std::vector<tt::hal::gps::GpsConfiguration> configurations;
auto gps_service = tt::service::gps::findGpsService(); auto gps_service = service::gps::findGpsService();
if (gps_service && gps_service->getGpsConfigurations(configurations)) { if (gps_service && gps_service->getGpsConfigurations(configurations)) {
TT_LOG_I(TAG, "Found service and configs %d %d", index, configurations.size()); TT_LOG_I(TAG, "Found service and configs %d %d", index, configurations.size());
if (index <= configurations.size()) { if (index <= configurations.size()) {

View File

@ -18,7 +18,7 @@ BundleHandle _Nullable tt_app_get_parameters(AppHandle handle);
* @param[in] result the result state to set * @param[in] result the result state to set
* @param[in] bundle the result bundle to set * @param[in] bundle the result bundle to set
*/ */
void tt_app_set_result(AppHandle handle, Result result, BundleHandle _Nullable bundle); void tt_app_set_result(AppHandle handle, AppResult result, BundleHandle _Nullable bundle);
/** @return true if a result was set for this app context */ /** @return true if a result was set for this app context */
bool tt_app_has_result(AppHandle handle); bool tt_app_has_result(AppHandle handle);

View File

@ -9,14 +9,14 @@ extern "C" {
/** Important: These values must map to tt::app::Result values exactly */ /** Important: These values must map to tt::app::Result values exactly */
typedef enum { typedef enum {
AppResultOk = 0, APP_RESULT_OK = 0,
AppResultCancelled = 1, APP_RESULT_CANCELLED = 1,
AppResultError = 2 APP_RESULT_ERROR = 2
} Result; } AppResult;
typedef void* AppHandle; typedef void* AppHandle;
typedef unsigned int LaunchId; typedef unsigned int AppLaunchId;
/** Important: These function types must map to t::app types exactly */ /** Important: These function types must map to t::app types exactly */
typedef void* (*AppCreateData)(); typedef void* (*AppCreateData)();
@ -25,7 +25,7 @@ typedef void (*AppOnCreate)(AppHandle app, void* _Nullable data);
typedef void (*AppOnDestroy)(AppHandle app, void* _Nullable data); typedef void (*AppOnDestroy)(AppHandle app, void* _Nullable data);
typedef void (*AppOnShow)(AppHandle app, void* _Nullable data, lv_obj_t* parent); typedef void (*AppOnShow)(AppHandle app, void* _Nullable data, lv_obj_t* parent);
typedef void (*AppOnHide)(AppHandle app, void* _Nullable data); typedef void (*AppOnHide)(AppHandle app, void* _Nullable data);
typedef void (*AppOnResult)(AppHandle app, void* _Nullable data, LaunchId launchId, Result result, BundleHandle resultData); typedef void (*AppOnResult)(AppHandle app, void* _Nullable data, AppLaunchId launchId, AppResult result, BundleHandle resultData);
typedef struct { typedef struct {
/** The application's human-readable name */ /** The application's human-readable name */

View File

@ -0,0 +1,21 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
bool tt_gps_has_coordinates();
bool tt_gps_get_coordinates(
float* longitude,
float* latitude,
float* speed,
float* course,
int* day,
int* month,
int* year
);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,83 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/**
* Note that on ESP32, there are limitations:
* - namespace name is limited by NVS_NS_NAME_MAX_SIZE (generally 16 characters)
* - key is limited by NVS_KEY_NAME_MAX_SIZE (generally 16 characters)
*/
/** The handle that represents a Preferences instance */
typedef void* PreferencesHandle;
/**
* @param[in] identifier the name of the preferences. This determines the NVS namespace on ESP.
* @return a new preferences instance
*/
PreferencesHandle tt_preferences_alloc(const char* identifier);
/** Dealloc an existing preferences instance */
void tt_preferences_free(PreferencesHandle handle);
/**
* Try to get a boolean value
* @param[in] handle the handle that represents the preferences
* @param[in] key the identifier that represents the stored value (~variable name)
* @param[out] out the output value (only set when return value is set to true)
* @return true if "out" was set
*/
bool tt_preferences_opt_bool(PreferencesHandle handle, const char* key, bool* out);
/**
* Try to get an int32_t value
* @param[in] handle the handle that represents the preferences
* @param[in] key the identifier that represents the stored value (~variable name)
* @param[out] out the output value (only set when return value is set to true)
* @return true if "out" was set
*/
bool tt_preferences_opt_int32(PreferencesHandle handle, const char* key, int32_t* out);
/**
* Try to get a string
* @warning outSize must be large enough to include null terminator. This means that your string has to be the expected text length + 1 extra character.
* @param[in] handle the handle that represents the preferences
* @param[in] key the identifier that represents the stored value (~variable name)
* @param[out] out the buffer to store the string in
* @param[in] outSize the size of the buffer
* @return true if "out" was set
*/
bool tt_preferences_opt_string(PreferencesHandle handle, const char* key, char* out, uint32_t outSize);
/**
* Store a boolean value
* @param[in] handle the handle that represents the preferences
* @param[in] key the identifier that represents the stored value (~variable name)
* @param[in] value the value to store
*/
void tt_preferences_put_bool(PreferencesHandle handle, const char* key, bool value);
/**
* Store an int32_t value
* @param[in] handle the handle that represents the preferences
* @param[in] key the identifier that represents the stored value (~variable name)
* @param[in] value the value to store
*/
void tt_preferences_put_int32(PreferencesHandle handle, const char* key, int32_t value);
/**
* Store a string value
* @param[in] handle the handle that represents the preferences
* @param[in] key the identifier that represents the stored value (~variable name)
* @param[in] value the value to store
*/
void tt_preferences_put_string(PreferencesHandle handle, const char* key, const char* value);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,42 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#define TT_TIMEZONE_NAME_BUFFER_LENGTH 32
#define TT_TIMEZONE_CODE_BUFFER_LENGTH 48
/**
* Set the timezone
* @param[in] name human-readable name
* @param[in] code the technical code (from timezones.csv)
*/
void tt_timezone_set(const char* name, const char* code);
/**
* Get the name of the timezone
* @param[out] buffer the output buffer which will include a null terminator (should be TT_TIMEZONE_NAME_BUFFER_LENGTH)
* @param[in] bufferSize the size of the output buffer
*/
bool tt_timezone_get_name(char* buffer, size_t bufferSize);
/**
* Get the code of the timezone (see timezones.csv)
*/
bool tt_timezone_get_code(char* buffer, size_t bufferSize);
/** @return true when clocks should be shown as a 24 hours one instead of 12 hours */
bool tt_timezone_is_format_24_hour();
/** Set whether clocks should be shown as a 24 hours instead of 12 hours
* @param[in] show24Hour
*/
void tt_timezone_set_format_24_hour(bool show24Hour);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,74 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#define TT_WIFI_SSID_LIMIT 32 // 32 characters/octets, according to IEEE 802.11-2020 spec
#define TT_WIFI_CREDENTIALS_PASSWORD_LIMIT 64 // 64 characters/octets, according to IEEE 802.11-2020 spec
#ifdef __cplusplus
extern "C" {
#endif
/** Important: These values must map to tt::service::wifi::RadioState values exactly */
typedef enum {
WIFI_RADIO_STATE_ON_PENDING,
WIFI_RADIO_STATE_ON,
WIFI_RADIO_STATE_CONNECTION_PENDING,
WIFI_RADIO_STATE_CONNECTION_ACTIVE,
WIFI_RADIO_STATE_OFF_PENDING,
WIFI_RADIO_STATE_OFF,
} WifiRadioState;
/** @return the state of the WiFi radio */
WifiRadioState tt_wifi_get_radio_state();
/** @return a textual representation of the WiFi radio state */
const char* tt_wifi_radio_state_to_string(WifiRadioState state);
/** Start scanning */
void tt_wifi_scan();
/** @return true if a scan is active/pending */
bool tt_wifi_is_scanning();
/**
* Return the WiFi SSID that the system tries to connect to, or is connected to.
* @param[out] buffer an allocated string buffer. Its size must be (WIFI_SSID_LIMIT + 1).
*/
void tt_wifi_get_connection_target(char* buffer);
/**
* @brief Enable/disable the radio. Ignores input if desired state matches current state.
* @param[in] enabled
*/
void tt_wifi_set_enabled(bool enabled);
/**
*
* @param ssid The access point identifier - maximal 32 characters/octets
* @param password the password - maximum 64 characters/octets
* @param channel 0 means "any"
* @param autoConnect whether we want to automatically reconnect if a disconnect occurs
* @param remember whether the record should be stored permanently on the device (it is only stored if this connection attempt succeeds)
*/
void tt_wifi_connect(const char* ssid, const char* password, int32_t channel, bool autoConnect, bool remember);
/**
* If WiFi is connected, this disconnects it.
*/
void tt_wifi_disconnect();
/**
* @return true if WiFi is active and encrypted
*/
bool tt_wifi_is_connnection_secure();
/**
* @return the current radio connection link quality
*/
int tt_wifi_get_rssi();
#ifdef __cplusplus
}
#endif

View File

@ -10,9 +10,9 @@ BundleHandle _Nullable tt_app_get_parameters(AppHandle handle) {
return (BundleHandle)HANDLE_AS_APP_CONTEXT(handle)->getParameters().get(); return (BundleHandle)HANDLE_AS_APP_CONTEXT(handle)->getParameters().get();
} }
void tt_app_set_result(AppHandle handle, Result result, BundleHandle _Nullable bundle) { void tt_app_set_result(AppHandle handle, AppResult result, BundleHandle _Nullable bundle) {
auto shared_bundle = std::unique_ptr<tt::Bundle>((tt::Bundle*)bundle); auto shared_bundle = std::unique_ptr<tt::Bundle>(static_cast<tt::Bundle*>(bundle));
HANDLE_AS_APP_CONTEXT(handle)->getApp()->setResult((tt::app::Result)result, std::move(shared_bundle)); HANDLE_AS_APP_CONTEXT(handle)->getApp()->setResult(static_cast<tt::app::Result>(result), std::move(shared_bundle));
} }
bool tt_app_has_result(AppHandle handle) { bool tt_app_has_result(AppHandle handle) {
@ -24,7 +24,7 @@ void tt_app_start(const char* appId) {
} }
void tt_app_start_with_bundle(const char* appId, BundleHandle parameters) { void tt_app_start_with_bundle(const char* appId, BundleHandle parameters) {
tt::app::start(appId, std::shared_ptr<tt::Bundle>((tt::Bundle*)parameters)); tt::app::start(appId, std::shared_ptr<tt::Bundle>(static_cast<tt::Bundle*>(parameters)));
} }
void tt_app_stop() { void tt_app_stop() {

View File

@ -23,17 +23,19 @@ bool tt_bundle_opt_int32(BundleHandle handle, const char* key, int32_t* out) {
} }
bool tt_bundle_opt_string(BundleHandle handle, const char* key, char* out, uint32_t outSize) { bool tt_bundle_opt_string(BundleHandle handle, const char* key, char* out, uint32_t outSize) {
std::string out_string; std::string out_string;
if (HANDLE_AS_BUNDLE(handle)->optString(key, out_string)) {
if (out_string.length() < outSize) { // Need 1 byte to add 0 at the end if (!HANDLE_AS_BUNDLE(handle)->optString(key, out_string)) {
return false;
}
if (out_string.length() >= outSize) {
// Need 1 byte to add 0 at the end
return false;
}
memcpy(out, out_string.c_str(), out_string.length()); memcpy(out, out_string.c_str(), out_string.length());
out[out_string.length()] = 0x00; out[out_string.length()] = 0x00;
return true; return true;
} else {
return false;
}
} else {
return false;
}
} }
void tt_bundle_put_bool(BundleHandle handle, const char* key, bool value) { void tt_bundle_put_bool(BundleHandle handle, const char* key, bool value) {

View File

@ -0,0 +1,45 @@
#include "tt_gps.h"
#include <Tactility/service/gps/GpsService.h>
using namespace tt::service;
extern "C" {
bool tt_gps_has_coordinates() {
auto service = gps::findGpsService();
return service != nullptr && service->hasCoordinates();
}
bool tt_gps_get_coordinates(
float* longitude,
float* latitude,
float* speed,
float* course,
int* day,
int* month,
int* year
) {
auto service = gps::findGpsService();
if (service == nullptr) {
return false;
}
minmea_sentence_rmc rmc;
if (!service->getCoordinates(rmc)) {
return false;
}
*longitude = minmea_tocoord(&rmc.longitude);
*latitude = minmea_tocoord(&rmc.latitude);
*speed = minmea_tocoord(&rmc.speed);
*course = minmea_tocoord(&rmc.course);
*day = rmc.date.day;
*month = rmc.date.month;
*year = rmc.date.year;
return true;
}
}

View File

@ -5,15 +5,19 @@
#include "tt_app_manifest.h" #include "tt_app_manifest.h"
#include "tt_app_selectiondialog.h" #include "tt_app_selectiondialog.h"
#include "tt_bundle.h" #include "tt_bundle.h"
#include "tt_gps.h"
#include "tt_hal_i2c.h" #include "tt_hal_i2c.h"
#include "tt_lvgl_keyboard.h" #include "tt_lvgl_keyboard.h"
#include "tt_lvgl_spinner.h" #include "tt_lvgl_spinner.h"
#include "tt_lvgl_toolbar.h" #include "tt_lvgl_toolbar.h"
#include "tt_message_queue.h" #include "tt_message_queue.h"
#include "tt_mutex.h" #include "tt_mutex.h"
#include "tt_preferences.h"
#include "tt_semaphore.h" #include "tt_semaphore.h"
#include "tt_thread.h" #include "tt_thread.h"
#include "tt_time.h"
#include "tt_timer.h" #include "tt_timer.h"
#include "tt_wifi.h"
#include <private/elf_symbol.h> #include <private/elf_symbol.h>
@ -39,6 +43,8 @@ const struct esp_elfsym elf_symbols[] {
ESP_ELFSYM_EXPORT(tt_bundle_put_bool), ESP_ELFSYM_EXPORT(tt_bundle_put_bool),
ESP_ELFSYM_EXPORT(tt_bundle_put_int32), ESP_ELFSYM_EXPORT(tt_bundle_put_int32),
ESP_ELFSYM_EXPORT(tt_bundle_put_string), ESP_ELFSYM_EXPORT(tt_bundle_put_string),
ESP_ELFSYM_EXPORT(tt_gps_has_coordinates),
ESP_ELFSYM_EXPORT(tt_gps_get_coordinates),
ESP_ELFSYM_EXPORT(tt_hal_i2c_start), ESP_ELFSYM_EXPORT(tt_hal_i2c_start),
ESP_ELFSYM_EXPORT(tt_hal_i2c_stop), ESP_ELFSYM_EXPORT(tt_hal_i2c_stop),
ESP_ELFSYM_EXPORT(tt_hal_i2c_is_started), ESP_ELFSYM_EXPORT(tt_hal_i2c_is_started),
@ -72,6 +78,14 @@ const struct esp_elfsym elf_symbols[] {
ESP_ELFSYM_EXPORT(tt_mutex_free), ESP_ELFSYM_EXPORT(tt_mutex_free),
ESP_ELFSYM_EXPORT(tt_mutex_lock), ESP_ELFSYM_EXPORT(tt_mutex_lock),
ESP_ELFSYM_EXPORT(tt_mutex_unlock), ESP_ELFSYM_EXPORT(tt_mutex_unlock),
ESP_ELFSYM_EXPORT(tt_preferences_alloc),
ESP_ELFSYM_EXPORT(tt_preferences_free),
ESP_ELFSYM_EXPORT(tt_preferences_opt_bool),
ESP_ELFSYM_EXPORT(tt_preferences_opt_int32),
ESP_ELFSYM_EXPORT(tt_preferences_opt_string),
ESP_ELFSYM_EXPORT(tt_preferences_put_bool),
ESP_ELFSYM_EXPORT(tt_preferences_put_int32),
ESP_ELFSYM_EXPORT(tt_preferences_put_string),
ESP_ELFSYM_EXPORT(tt_semaphore_alloc), ESP_ELFSYM_EXPORT(tt_semaphore_alloc),
ESP_ELFSYM_EXPORT(tt_semaphore_free), ESP_ELFSYM_EXPORT(tt_semaphore_free),
ESP_ELFSYM_EXPORT(tt_semaphore_acquire), ESP_ELFSYM_EXPORT(tt_semaphore_acquire),
@ -99,6 +113,21 @@ const struct esp_elfsym elf_symbols[] {
ESP_ELFSYM_EXPORT(tt_timer_get_expire_time), ESP_ELFSYM_EXPORT(tt_timer_get_expire_time),
ESP_ELFSYM_EXPORT(tt_timer_set_pending_callback), ESP_ELFSYM_EXPORT(tt_timer_set_pending_callback),
ESP_ELFSYM_EXPORT(tt_timer_set_thread_priority), ESP_ELFSYM_EXPORT(tt_timer_set_thread_priority),
ESP_ELFSYM_EXPORT(tt_timezone_set),
ESP_ELFSYM_EXPORT(tt_timezone_get_name),
ESP_ELFSYM_EXPORT(tt_timezone_get_code),
ESP_ELFSYM_EXPORT(tt_timezone_is_format_24_hour),
ESP_ELFSYM_EXPORT(tt_timezone_set_format_24_hour),
ESP_ELFSYM_EXPORT(tt_wifi_get_radio_state),
ESP_ELFSYM_EXPORT(tt_wifi_radio_state_to_string),
ESP_ELFSYM_EXPORT(tt_wifi_scan),
ESP_ELFSYM_EXPORT(tt_wifi_is_scanning),
ESP_ELFSYM_EXPORT(tt_wifi_get_connection_target),
ESP_ELFSYM_EXPORT(tt_wifi_set_enabled),
ESP_ELFSYM_EXPORT(tt_wifi_connect),
ESP_ELFSYM_EXPORT(tt_wifi_disconnect),
ESP_ELFSYM_EXPORT(tt_wifi_is_connnection_secure),
ESP_ELFSYM_EXPORT(tt_wifi_get_rssi),
// tt::lvgl // tt::lvgl
ESP_ELFSYM_EXPORT(tt_lvgl_spinner_create), ESP_ELFSYM_EXPORT(tt_lvgl_spinner_create),
// lv_event // lv_event

View File

@ -0,0 +1,53 @@
#include "tt_preferences.h"
#include <Tactility/Preferences.h>
#include <cstring>
#define HANDLE_AS_PREFERENCES(handle) ((tt::Preferences*)(handle))
extern "C" {
PreferencesHandle tt_preferences_alloc(const char* identifier) {
return new tt::Preferences(identifier);
}
void tt_preferences_free(PreferencesHandle handle) {
delete HANDLE_AS_PREFERENCES(handle);
}
bool tt_preferences_opt_bool(PreferencesHandle handle, const char* key, bool* out) {
return HANDLE_AS_PREFERENCES(handle)->optBool(key, *out);
}
bool tt_preferences_opt_int32(PreferencesHandle handle, const char* key, int32_t* out) {
return HANDLE_AS_PREFERENCES(handle)->optInt32(key, *out);
}
bool tt_preferences_opt_string(PreferencesHandle handle, const char* key, char* out, uint32_t outSize) {
std::string out_string;
if (!HANDLE_AS_PREFERENCES(handle)->optString(key, out_string)) {
return false;
}
if (out_string.length() >= outSize) {
// Need 1 byte to add 0 at the end
return false;
}
memcpy(out, out_string.c_str(), out_string.length());
out[out_string.length()] = 0x00;
return true;
}
void tt_preferences_put_bool(PreferencesHandle handle, const char* key, bool value) {
HANDLE_AS_PREFERENCES(handle)->putBool(key, value);
}
void tt_preferences_put_int32(PreferencesHandle handle, const char* key, int32_t value) {
HANDLE_AS_PREFERENCES(handle)->putInt32(key, value);
}
void tt_preferences_put_string(PreferencesHandle handle, const char* key, const char* value) {
HANDLE_AS_PREFERENCES(handle)->putString(key, value);
}
}

View File

@ -0,0 +1,42 @@
#include "tt_time.h"
#include <Tactility/time/Time.h>
#include <cstring>
using namespace tt;
extern "C" {
void tt_timezone_set(const char* name, const char* code) {
time::setTimeZone(name, code);
}
bool tt_timezone_get_name(char* buffer, size_t bufferSize) {
auto name = time::getTimeZoneName();
if (bufferSize < (name.length() + 1)) {
return false;
} else {
strcpy(buffer, name.c_str());
return true;
}
}
bool tt_timezone_get_code(char* buffer, size_t bufferSize) {
auto code = time::getTimeZoneCode();
if (bufferSize < (code.length() + 1)) {
return false;
} else {
strcpy(buffer, code.c_str());
return true;
}
}
bool tt_timezone_is_format_24_hour() {
return time::isTimeFormat24Hour();
}
void tt_timezone_set_format_24_hour(bool show24Hour) {
return time::setTimeFormat24Hour(show24Hour);
}
}

View File

@ -7,7 +7,6 @@ struct TimerWrapper {
extern "C" { extern "C" {
TimerHandle tt_timer_alloc(TimerType type, TimerCallback callback, void* callbackContext) { TimerHandle tt_timer_alloc(TimerType type, TimerCallback callback, void* callbackContext) {
auto wrapper = std::make_shared<TimerWrapper>(); auto wrapper = std::make_shared<TimerWrapper>();
wrapper->timer = std::make_unique<tt::Timer>((tt::Timer::Type)type, [callback, callbackContext](){ callback(callbackContext); }); wrapper->timer = std::make_unique<tt::Timer>((tt::Timer::Type)type, [callback, callbackContext](){ callback(callbackContext); });
@ -54,4 +53,3 @@ void tt_timer_set_thread_priority(TimerHandle handle, ThreadPriority priority) {
} }
} }

View File

@ -0,0 +1,55 @@
#include "tt_wifi.h"
#include <cstring>
#include <Tactility/service/wifi/Wifi.h>
#include <Tactility/service/wifi/WifiSettings.h>
using namespace tt::service;
extern "C" {
WifiRadioState tt_wifi_get_radio_state() {
return static_cast<WifiRadioState>(wifi::getRadioState());
}
const char* tt_wifi_radio_state_to_string(WifiRadioState state) {
return wifi::radioStateToString(static_cast<wifi::RadioState>(state));
}
void tt_wifi_scan() {
wifi::scan();
}
bool tt_wifi_is_scanning() {
return wifi::isScanning();
}
void tt_wifi_get_connection_target(char* buffer) {
auto target = wifi::getConnectionTarget();
strcpy(buffer, target.c_str());
}
void tt_wifi_set_enabled(bool enabled) {
wifi::setEnabled(enabled);
}
void tt_wifi_connect(const char* ssid, const char* password, int32_t channel, bool autoConnect, bool remember) {
wifi::settings::WifiApSettings settings;
strcpy(settings.ssid, ssid);
strcpy(settings.password, password);
settings.channel = channel;
settings.auto_connect = autoConnect;
}
void tt_wifi_disconnect() {
wifi::disconnect();
}
bool tt_wifi_is_connnection_secure() {
return wifi::isConnectionSecure();
}
int tt_wifi_get_rssi() {
return wifi::getRssi();
}
}