/** * @file littlefs-do-main.cpp * */ /********************* * INCLUDES *********************/ #define _DEFAULT_SOURCE /* needed for usleep() */ #include #include #include #include #include #include #include #include #include // std::pow #include "components/fs/FS.h" #include "components/settings/Settings.h" #include "drivers/SpiNorFlash.h" /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ /********************** * STATIC VARIABLES **********************/ /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ /********************** * VARIABLES **********************/ /********************** * STATIC PROTOTYPES **********************/ /********************** * GLOBAL FUNCTIONS **********************/ Pinetime::Drivers::SpiNorFlash spiNorFlash {"spiNorFlash.raw"}; Pinetime::Controllers::FS fs {spiNorFlash}; Pinetime::Controllers::Settings settingsController {fs}; const char* lfs_error_to_string(int err) { if (err == LFS_ERR_OK) return "LFS_ERR_OK"; // No error if (err == LFS_ERR_IO) return "LFS_ERR_IO"; // Error during device operation if (err == LFS_ERR_CORRUPT) return "LFS_ERR_CORRUPT"; // Corrupted if (err == LFS_ERR_NOENT) return "LFS_ERR_NOENT"; // No directory entry if (err == LFS_ERR_EXIST) return "LFS_ERR_EXIST"; // Entry already exists if (err == LFS_ERR_NOTDIR) return "LFS_ERR_NOTDIR"; // Entry is not a dir if (err == LFS_ERR_ISDIR) return "LFS_ERR_ISDIR"; // Entry is a dir if (err == LFS_ERR_NOTEMPTY) return "LFS_ERR_NOTEMPTY"; // Dir is not empty if (err == LFS_ERR_BADF) return "LFS_ERR_BADF"; // Bad file number if (err == LFS_ERR_FBIG) return "LFS_ERR_FBIG"; // File too large if (err == LFS_ERR_INVAL) return "LFS_ERR_INVAL"; // Invalid parameter if (err == LFS_ERR_NOSPC) return "LFS_ERR_NOSPC"; // No space left on device if (err == LFS_ERR_NOMEM) return "LFS_ERR_NOMEM"; // No more memory available if (err == LFS_ERR_NOATTR) return "LFS_ERR_NOATTR"; // No data/attr available if (err == LFS_ERR_NAMETOOLONG) return "LFS_ERR_NAMETOOLONG"; // File name too long return "unknown"; } void print_help_generic(const std::string &program_name) { std::cout << "Usage: " << program_name << " [options]" << std::endl; std::cout << "Commands:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; std::cout << " -v, --verbose print status messages to the console" << std::endl; std::cout << " stat show information of specified file or directory" << std::endl; std::cout << " ls list available files in 'spiNorFlash.raw' file" << std::endl; std::cout << " mkdir create directory" << std::endl; std::cout << " rmdir remove directory" << std::endl; std::cout << " rm remove directory or file" << std::endl; std::cout << " cp copy files into or out of flash file" << std::endl; std::cout << " settings list settings from 'settings.h'" << std::endl; } void print_help_stat(const std::string &program_name) { std::cout << "Usage: " << program_name << " stat [options] [path]" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; std::cout << " path path to directory or file to work on, defaults to '/'" << std::endl; } void print_help_ls(const std::string &program_name) { std::cout << "Usage: " << program_name << " ls [options] [path]" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; std::cout << " path path to directory or file to work on, defaults to '/'" << std::endl; } void print_help_mkdir(const std::string &program_name) { std::cout << "Usage: " << program_name << " mkdir [options] path" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; std::cout << " path path to directory to create" << std::endl; } void print_help_rmdir(const std::string &program_name) { std::cout << "Usage: " << program_name << " rmdir [options] path" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; std::cout << " path path to directory to remove" << std::endl; } void print_help_rm(const std::string &program_name) { std::cout << "Usage: " << program_name << " rm [options] path" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; std::cout << " path path to file or directory directory to remove" << std::endl; } void print_help_cp(const std::string &program_name) { std::cout << "Usage: " << program_name << " cp [options] source [source2 ...] destination" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; std::cout << std::endl; std::cout << "if the destination starts with '/' it is assumed to copy sources from" << std::endl; std::cout << "the host system into the raw image, otherwise the files are copied" << std::endl; std::cout << "from the raw image to the host system provided directory." << std::endl; } void print_help_settings(const std::string &program_name) { std::cout << "Usage: " << program_name << " settings [options]" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h, --help show this help message for the selected command and exit" << std::endl; } int command_stat(const std::string &program_name, const std::vector &args, bool verbose) { if (verbose) std::cout << "running command 'stat'" << std::endl; // argv: littlefs-do stat [args] std::string path = "/"; // check for help flag first for (const std::string &arg : args) { if (arg == "-h" || arg == "--help") { print_help_stat(program_name); return 0; } } if (args.empty()) { if (verbose) { std::cout << "no path given, showing '/'" << std::endl; } } if (args.size() == 1) { path = args.at(0); } lfs_info info; int ret = fs.Stat(path.c_str(), &info); if (ret) { std::cout << "fs.Stat returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } if (info.type == LFS_TYPE_REG) { std::cout << "type: REG" << std::endl; std::cout << "size: " << info.size << std::endl; std::cout << "name: " << std::string(info.name) << std::endl; } else if (info.type == LFS_TYPE_DIR) { std::cout << "type: DIR" << std::endl; std::cout << "name: " << std::string(info.name) << std::endl; } else { std::cout << "unknown type: " << info.type << std::endl; return 1; } return 0; } int command_ls(const std::string &program_name, const std::vector &args, bool verbose) { if (verbose) std::cout << "running command 'ls'" << std::endl; // argv: littlefs-do ls [args] std::string path = "/"; // check for help flag first for (const std::string &arg : args) { if (arg == "-h" || arg == "--help") { print_help_ls(program_name); return 0; } } if (args.empty()) { if (verbose) { std::cout << "no path given, showing '/'" << std::endl; } } if (args.size() == 1) { path = args.at(0); } lfs_info info; int ret = fs.Stat(path.c_str(), &info); if (ret) { std::cout << "fs.Stat returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } if (info.type == LFS_TYPE_REG) { std::cout << "type: REG" << std::endl; std::cout << "size: " << info.size << std::endl; std::cout << "name: " << std::string(info.name) << std::endl; } else if (info.type == LFS_TYPE_DIR) { std::cout << "type: DIR" << std::endl; std::cout << "name: " << std::string(info.name) << std::endl; lfs_dir_t lfs_dir; ret = fs.DirOpen(path.c_str(), &lfs_dir); if (ret) { std::cout << "fs.DirOpen returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } ret = fs.DirRead(&lfs_dir, &info); while (ret > 0) { if (ret < 0) { std::cout << "fs.DirRead returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } if (info.type == LFS_TYPE_REG) { std::cout << "type: REG"; std::cout << " size: " << info.size; std::cout << " name: " << std::string(info.name) << std::endl; } else if (info.type == LFS_TYPE_DIR) { std::cout << "type: DIR"; std::cout << " name: " << std::string(info.name) << std::endl; } else { std::cout << "unknown type: " << info.type << std::endl; return 1; } // fill for next iteration ret = fs.DirRead(&lfs_dir, &info); } // end of while loop if (ret < 0) { std::cout << "fs.DirRead returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } } else { // endif provided path std::cout << "unknown type: " << info.type << std::endl; return 1; } return 0; } int command_mkdir(const std::string &program_name, const std::vector &args, bool verbose) { if (verbose) { std::cout << "running command 'mkdir'" << std::endl; } // argv: littlefs-do mkdir path // check for help flag first for (const std::string &arg : args) { if (arg == "-h" || arg == "--help") { print_help_mkdir(program_name); return 0; } } if (args.empty()) { std::cout << "error: no path given" << std::endl; print_help_mkdir(program_name); return 1; } for (const std::string &path : args) { if (verbose) { std::cout << "mkdir: " << path << std::endl; } int ret = fs.DirCreate(path.c_str()); if (ret < 0) { std::cout << "fs.DirCreate returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } } return 0; } int command_rmdir(const std::string &program_name, const std::vector &args, bool verbose) { if (verbose) { std::cout << "running command 'rmdir'" << std::endl; } // argv: littlefs-do rmdir path // check for help flag first for (const std::string &arg : args) { if (arg == "-h" || arg == "--help") { print_help_rmdir(program_name); return 0; } } if (args.empty()) { std::cout << "error: no path given" << std::endl; print_help_rmdir(program_name); return 1; } for (const std::string &path : args) { if (verbose) { std::cout << "rmdir: " << path << std::endl; } lfs_info info; int ret = fs.Stat(path.c_str(), &info); if (ret) { std::cout << "fs.Stat returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } if (info.type == LFS_TYPE_REG) { std::cout << "error: provided path '" << path << "is a file" << std::endl; return 1; } // assume non-files are directories ret = fs.FileDelete(path.c_str()); if (ret < 0) { std::cout << "fs.FileDelete returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } } return 0; } int command_rm(const std::string &program_name, const std::vector &args, bool verbose) { if (verbose) { std::cout << "running command 'rm'" << std::endl; } // argv: littlefs-do rm path // check for help flag first for (const std::string &arg : args) { if (arg == "-h" || arg == "--help") { print_help_rm(program_name); return 0; } } if (args.empty()) { std::cout << "error: no path given" << std::endl; print_help_rm(program_name); return 1; } for (const std::string &path : args) { if (verbose) { std::cout << "rm: " << path << std::endl; } // assume non-files are directories int ret = fs.FileDelete(path.c_str()); if (ret < 0) { std::cout << "fs.FileDelete returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } } return 0; } int command_cp(const std::string &program_name, const std::vector &args, bool verbose) { if (verbose) { std::cout << "running 'cp'" << std::endl; } for (const std::string &arg : args) { if (arg == "-h" || arg == "--help") { print_help_cp(program_name); return 0; } } if (args.size() < 2) { std::cout << "error: no destination given, need source and destination" << std::endl; print_help_cp(program_name); return 1; } const std::string &destination = args.back(); static constexpr size_t memorySize {0x400000}; std::array buffer; if (destination[0] == '/') { if (verbose) { std::cout << "destination starts with '/', copying files into image" << std::endl; } { lfs_info info; int ret = fs.Stat(destination.c_str(), &info); if (ret) { std::cout << "fs.Stat for destination path returned error code: " << ret << " " << lfs_error_to_string(ret) << std::endl; return ret; } if (info.type == LFS_TYPE_REG) { std::cout << "destination is file, assumed directory" << std::endl; return 1; } } for (size_t i=0; i &args, bool verbose) { if (verbose) { std::cout << "running 'settings'" << std::endl; } for (const std::string &arg : args) { if (arg == "-h" || arg == "--help") { print_help_settings(program_name); return 0; } } if (verbose) { std::cout << "calling Settings::Init()" << std::endl; } settingsController.Init(); using namespace Pinetime::Controllers; { auto clockface = settingsController.GetClockFace(); auto clockface_str = [](auto val) { if (val == 0) return "Digital"; if (val == 1) return "Analog"; if (val == 2) return "PineTimeStyle"; if (val == 3) return "Terminal"; return "unknown"; }(clockface); std::cout << "ClockFace: " << static_cast(clockface) << " " << clockface_str << std::endl; } { auto chimes = settingsController.GetChimeOption(); auto chimes_str = [](auto val) { if (val == Settings::ChimesOption::None) return "None"; if (val == Settings::ChimesOption::Hours) return "Hours"; if (val == Settings::ChimesOption::HalfHours) return "HalfHours"; return "unknown"; }(chimes); std::cout << "Chimes: " << static_cast(chimes) << " " << chimes_str << std::endl; } auto color_str = [](auto c) { if (c == Settings::Colors::White) return "White"; if (c == Settings::Colors::Silver) return "Silver"; if (c == Settings::Colors::Gray) return "Gray"; if (c == Settings::Colors::Black) return "Black"; if (c == Settings::Colors::Red) return "Red"; if (c == Settings::Colors::Maroon) return "Maroon"; if (c == Settings::Colors::Yellow) return "Yellow"; if (c == Settings::Colors::Olive) return "Olive"; if (c == Settings::Colors::Lime) return "Lime"; if (c == Settings::Colors::Green) return "Cyan"; if (c == Settings::Colors::Teal) return "Teal"; if (c == Settings::Colors::Blue) return "Blue"; if (c == Settings::Colors::Navy) return "Navy"; if (c == Settings::Colors::Magenta) return "Magenta"; if (c == Settings::Colors::Purple) return "Purple"; if (c == Settings::Colors::Orange) return "Orange"; return "unknown"; }; std::cout << "PTSColorTime: " << color_str(settingsController.GetPTSColorTime()) << std::endl; std::cout << "PTSColorBar: " << color_str(settingsController.GetPTSColorBar()) << std::endl; std::cout << "PTSColorBG: " << color_str(settingsController.GetPTSColorBG()) << std::endl; std::cout << "AppMenu: " << static_cast(settingsController.GetAppMenu()) << std::endl; std::cout << "SettingsMenu: " << static_cast(settingsController.GetSettingsMenu()) << std::endl; std::cout << "ClockType: " << (settingsController.GetClockType() == Settings::ClockType::H24 ? "H24" : "H12") << std::endl; { auto notif = settingsController.GetNotificationStatus(); auto notif_str = [](auto val) { if (val == Settings::Notification::ON) return "ON"; if (val == Settings::Notification::OFF) return "OFF"; return "unknown"; }(notif); std::cout << "NotificationStatus: " << static_cast(notif) << " " << notif_str << std::endl; } std::cout << "ScreenTimeOut: " << settingsController.GetScreenTimeOut() << " ms" << std::endl; std::cout << "ShakeThreshold: " << settingsController.GetShakeThreshold() << std::endl; { std::cout << "WakeUpModes: " << std::endl; std::cout << "- SingleTap: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::SingleTap) ? "ON" : "OFF") << std::endl; std::cout << "- DoubleTap: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::DoubleTap) ? "ON" : "OFF") << std::endl; std::cout << "- RaiseWrist: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::RaiseWrist) ? "ON" : "OFF") << std::endl; std::cout << "- Shake: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::Shake) ? "ON" : "OFF") << std::endl; } { auto brightness = settingsController.GetBrightness(); auto brightness_str = [](auto val) { if (val == BrightnessController::Levels::Off) return "Off"; if (val == BrightnessController::Levels::Low) return "Low"; if (val == BrightnessController::Levels::Medium) return "Medium"; if (val == BrightnessController::Levels::High) return "High"; return "unknown"; }(brightness); std::cout << "Brightness: " << static_cast(brightness) << " " << brightness_str << std::endl; } std::cout << "StepsGoal: " << settingsController.GetStepsGoal() << std::endl; std::cout << "BleRadioEnabled: " << (settingsController.GetBleRadioEnabled() ? "true" : "false") << std::endl; return 0; } int main(int argc, char **argv) { // parse arguments if (argc <= 1) { print_help_generic(argv[0]); return 1; } bool verbose = false; std::vector args; for (int i=1; i