308 lines
8.2 KiB
C++
308 lines
8.2 KiB
C++
/*
|
|
*******************************************************************************
|
|
* INCLUDE
|
|
*******************************************************************************
|
|
*/
|
|
#include "Application.h"
|
|
#ifdef USING_NETWORK_SUBSYSTEM
|
|
#include "NetworkSubsystem.h"
|
|
#endif
|
|
#ifdef USING_GRAPHICS_SUBSYSTEM
|
|
#include "GraphicsSubsystem.h"
|
|
#endif
|
|
|
|
#include <Poco/Dynamic/Var.h>
|
|
#include <Poco/File.h>
|
|
#include <Poco/FileStream.h>
|
|
#include <Poco/JSON/Object.h>
|
|
#include <Poco/JSON/Parser.h>
|
|
#include <Poco/JSON/PrintHandler.h>
|
|
#include <Poco/Net/DNS.h>
|
|
#include <Poco/Net/IPAddress.h>
|
|
#include <Poco/Net/NetworkInterface.h>
|
|
#include <Poco/Path.h>
|
|
#include <Poco/Pipe.h>
|
|
#include <Poco/PipeStream.h>
|
|
#include <Poco/Process.h>
|
|
#include <Poco/StreamCopier.h>
|
|
#include <Poco/Timespan.h>
|
|
#include <Poco/Util/JSONConfiguration.h>
|
|
#include <Poco/Util/Timer.h>
|
|
#include <Poco/Checksum.h>
|
|
#include <atca_basic.h>
|
|
#include <atca_cfgs.h>
|
|
#include <atca_device.h>
|
|
#include <host/atca_host.h>
|
|
#include <sys/stat.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <arpa/inet.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
#include <sys/reboot.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include "hardware/BoardInfo.h"
|
|
#include "hardware/GPIO.h"
|
|
#include "hardware/HardwareSubsystem.h"
|
|
#include "util/HexBinaryCodec.h"
|
|
#include "util/SystemInfo.h"
|
|
#include "util/Temperature.h"
|
|
|
|
/*
|
|
*******************************************************************************
|
|
* CONSTANTS
|
|
*******************************************************************************
|
|
*/
|
|
static const std::string CONFIG_ROOT_PATH = "/customer/conf";
|
|
static const std::string ROOTCFG_FILENAME = CONFIG_ROOT_PATH + "/config.json";
|
|
static const std::string DEFAULT_ROOTCFG_FILENAME = CONFIG_ROOT_PATH + "/config_default.json";
|
|
const std::string VERSION_FILE = "/customer/VERSION";
|
|
const std::string IMAGE_VERSION_FILE = "/etc/IMAGE_VERSION";
|
|
|
|
/*
|
|
*******************************************************************************
|
|
* CLASS DEFINE
|
|
*******************************************************************************
|
|
*/
|
|
const std::string Application::ROOT_CONFIG = "config";
|
|
|
|
void Application::initialize(Poco::Util::Application& self)
|
|
{
|
|
_exitRequst = false;
|
|
initConfigAll();
|
|
|
|
Poco::Util::Application::initialize(self);
|
|
}
|
|
|
|
void Application::uninitialize()
|
|
{
|
|
Poco::Util::Application::uninitialize();
|
|
}
|
|
|
|
int Application::main(const std::vector<std::string>& args)
|
|
{
|
|
while (!_exitRequst)
|
|
Poco::Thread::sleep(1000);
|
|
|
|
return EXIT_OK;
|
|
}
|
|
|
|
std::string Application::getConfigFilePath(const std::string& label)
|
|
{
|
|
Poco::Path path(getConfig(Application::ROOT_CONFIG).getString("buss_params_path"));
|
|
if (path.isRelative())
|
|
path = path.makeAbsolute(Poco::Path::current());
|
|
|
|
return path.toString() + label + ".json";
|
|
}
|
|
|
|
void Application::initConfigAll()
|
|
{
|
|
config().add(new Poco::Util::JSONConfiguration(ROOTCFG_FILENAME), ROOT_CONFIG, PRIO_SYSTEM, true);
|
|
}
|
|
|
|
void Application::initConfig(const std::string& label)
|
|
{
|
|
int retry = 0;
|
|
while (retry++ < 3)
|
|
{
|
|
try
|
|
{
|
|
config().add(new Poco::Util::JSONConfiguration(getConfigFilePath(label)), label, PRIO_APPLICATION, true);
|
|
break;
|
|
}
|
|
catch (Poco::Exception& e)
|
|
{
|
|
logger().error("Load config file '%s' FAIL: %s, USE DEFAULT CONFIG FILE INSTEAD!", label, e.displayText());
|
|
Poco::File dFile(getConfigFilePath(label + "_default"));
|
|
if (dFile.exists())
|
|
{
|
|
dFile.copyTo(getConfigFilePath(label));
|
|
}
|
|
else
|
|
{
|
|
logger().error("Load config file '%s' FAIL: %s, DEFAULT CONFIG FILE IS NOT EXIST", label,
|
|
e.displayText());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string Application::version() const
|
|
{
|
|
try
|
|
{
|
|
Poco::FileInputStream istr(VERSION_FILE);
|
|
std::string version;
|
|
istr >> version;
|
|
return version;
|
|
}
|
|
catch (...)
|
|
{
|
|
return "0.0.0";
|
|
}
|
|
}
|
|
|
|
Poco::Util::AbstractConfiguration& Application::getConfig() const
|
|
{
|
|
return config();
|
|
}
|
|
|
|
Poco::Util::AbstractConfiguration& Application::getConfig(const std::string& label) const
|
|
{
|
|
return findConfig<Poco::Util::JSONConfiguration>(label);
|
|
}
|
|
|
|
void Application::saveConfig(const std::string& label)
|
|
{
|
|
logger().information("Saving config...");
|
|
std::string tmpFilePath = "/tmp/" + label + ".json.tmp";
|
|
std::string filePath = getConfigFilePath(label);
|
|
|
|
Poco::FileOutputStream fost(tmpFilePath);
|
|
dumpConfig(label, fost);
|
|
fost.flush();
|
|
fost.close();
|
|
|
|
try
|
|
{
|
|
Poco::File(tmpFilePath).moveTo(filePath);
|
|
logger().information("Config saved successfully.");
|
|
}
|
|
catch (Poco::Exception& e)
|
|
{
|
|
logger().error("Save config file ERROR: %s", e.displayText());
|
|
}
|
|
}
|
|
|
|
void Application::loadConfig(const std::string& label, std::istream& istr)
|
|
{
|
|
auto& config = findConfig<Poco::Util::JSONConfiguration>(label);
|
|
config.load(istr);
|
|
saveConfig(label);
|
|
ConfigChanged.notifyAsync(this, label);
|
|
}
|
|
|
|
void Application::loadConfig(const std::string& label, const std::string& str)
|
|
{
|
|
std::istringstream istr(str);
|
|
loadConfig(label, istr);
|
|
}
|
|
|
|
void Application::dumpConfig(const std::string& label, std::ostream& os)
|
|
{
|
|
auto& config = findConfig<Poco::Util::JSONConfiguration>(label);
|
|
config.save(os);
|
|
}
|
|
|
|
void Application::configNotifyAsync(const std::string& label)
|
|
{
|
|
ConfigChanged.notifyAsync(this, label);
|
|
}
|
|
|
|
void Application::restoreFactorySettings()
|
|
{
|
|
try
|
|
{
|
|
printf("Restore system factory settings...\r\n");
|
|
system("/customer/reset-key -Pweb");
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
|
|
reboot(2000);
|
|
}
|
|
|
|
void Application::reboot(uint32_t delay)
|
|
{
|
|
_delayRebootThread.startFunc([=]() -> void {
|
|
logger().warning("Reboot after %u ms ...", delay);
|
|
Poco::Thread::sleep(delay);
|
|
|
|
exit();
|
|
::sync();
|
|
|
|
if (system("reboot") != 0)
|
|
logger().error("System reboot command failed!");
|
|
|
|
::reboot(RB_AUTOBOOT);
|
|
});
|
|
}
|
|
|
|
void Application::setSystemTime(uint32_t timestamp, int timezone)
|
|
{
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = timestamp;
|
|
tv.tv_usec = 0;
|
|
settimeofday(&tv, NULL);
|
|
|
|
try
|
|
{
|
|
std::string cmd = "";
|
|
if (timezone >= 0)
|
|
{
|
|
cmd = Poco::format("ln -snf /customer/zoneinfo/Etc/GMT-%d /etc/localtime", timezone);
|
|
}
|
|
else
|
|
{
|
|
cmd = Poco::format("ln -snf /customer/zoneinfo/Etc/GMT+%d /etc/localtime", -1 * timezone);
|
|
}
|
|
system(cmd.c_str());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << e.what() << '\n';
|
|
}
|
|
system("hwclock -w -l");
|
|
}
|
|
|
|
void Application::exit()
|
|
{
|
|
ApplicationExitNotify.notify(this);
|
|
_exitRequst = true;
|
|
}
|
|
|
|
void Application::upgrade(const std::string& file)
|
|
{
|
|
#if defined(FIRMWARE_UPGRADE_FROM_BACKUP_PARTITION)
|
|
Poco::File("/customer/DIRTY").createFile();
|
|
logger().warning("Reboot to upgrade firmware ....");
|
|
#else
|
|
|
|
std::string specCharacters[] = {
|
|
"\\", " ", "\"", "'", "(", ")", "*", "!", "$", "%", "&", ">", "<", "|", "`",
|
|
};
|
|
|
|
for (auto& c : specCharacters)
|
|
file = Poco::replace(file, c, "\\" + c);
|
|
|
|
Poco::Pipe inPipe, outPipe;
|
|
Poco::Process::Args args;
|
|
Poco::ProcessHandle handle = Poco::Process::launch("sh", args, &inPipe, &outPipe, 0);
|
|
|
|
Poco::PipeOutputStream outputStream(inPipe);
|
|
std::string tmpdir = "/tmp/upgrade";
|
|
outputStream << Poco::format("mkdir -p %s", tmpdir) << std::endl;
|
|
outputStream << Poco::format("tar xf %s -C %s", file, tmpdir) << std::endl;
|
|
outputStream << Poco::format("%s/upgrade.sh", tmpdir) << std::endl;
|
|
outputStream.flush();
|
|
outputStream.close();
|
|
|
|
handle.wait();
|
|
|
|
Poco::PipeInputStream inputStream(outPipe);
|
|
std::string str;
|
|
Poco::StreamCopier::copyToString(inputStream, str);
|
|
logger().information("Firmware upgrade complete, reboot....");
|
|
#endif
|
|
reboot(2000);
|
|
}
|