OVMS3/OVMS.V3/components/ovms_script/src/ovms_script.cpp

249 lines
7.2 KiB
C++

/*
; Project: Open Vehicle Monitor System
; Date: 14th March 2017
;
; Changes:
; 1.0 Initial release
;
; (C) 2011 Michael Stegen / Stegen Electronics
; (C) 2011-2017 Mark Webb-Johnson
; (C) 2011 Sonny Chen @ EPRO/DX
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
; THE SOFTWARE.
*/
#include "ovms_log.h"
static const char *TAG = "script";
#include <string>
#include <fstream>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <esp_task_wdt.h>
#include "ovms_malloc.h"
#include "ovms_module.h"
#include "ovms_script.h"
#include "ovms_config.h"
#include "ovms_command.h"
#include "ovms_events.h"
#include "console_async.h"
#include "buffered_shell.h"
#include "ovms_netmanager.h"
#include "ovms_boot.h"
#include "ovms_peripherals.h"
#ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
#include "ovms_duktape.h"
static void script_reload(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
{
writer->puts("Reloading javascript engine");
MyDuktape.DuktapeReload();
}
static void script_eval(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
{
MyDuktape.DuktapeEvalNoResult(argv[0], writer);
}
static void script_compact(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
{
writer->puts("Compacting javascript memory");
MyDuktape.DuktapeCompact();
}
static void script_meminfo(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
{
MyDuktape.DuktapeEvalNoResult("JSON.print(meminfo())", writer);
}
#endif // #ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
OvmsScripts MyScripts __attribute__ ((init_priority (1600)));
static void script_ovms(int verbosity, OvmsWriter* writer,
const char* spath, FILE* sf, bool secure=false)
{
char *ext = rindex(spath, '.');
if ((ext != NULL)&&(strcmp(ext,".js")==0))
{
// Javascript script
#ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
fseek(sf,0,SEEK_END);
long slen = ftell(sf);
fseek(sf,0,SEEK_SET);
char *script = new char[slen+1];
memset(script,0,slen+1);
fread(script,1,slen,sf);
MyDuktape.NotifyDuktapeModuleLoad(spath);
MyDuktape.DuktapeEvalNoResult(script, writer, spath);
MyDuktape.NotifyDuktapeModuleUnload(spath);
delete [] script;
#else // #ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
if (writer)
{
writer->puts("Error: No javascript engine available");
}
else
{
ESP_LOGE(TAG, "Error: No javascript engine available");
}
#endif // #ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
fclose(sf);
}
else
{
// Default: OVMS command script
BufferedShell* bs = new BufferedShell(false, verbosity);
if (secure) bs->SetSecure(true);
char* cmdline = new char[_COMMAND_LINE_LEN];
while(fgets(cmdline, _COMMAND_LINE_LEN, sf) != NULL )
{
bs->ProcessChars(cmdline, strlen(cmdline));
if (strlen(cmdline) > 0 && cmdline[strlen(cmdline)-1] != '\n')
bs->ProcessChar('\n');
}
fclose(sf);
if (writer)
{
bs->Output(writer);
}
else
{
extram::string output;
bs->Dump(output);
ESP_LOGI(TAG, "%s", output.c_str());
}
delete bs;
delete [] cmdline;
}
}
static void script_run(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
{
FILE *sf = NULL;
std::string path;
if (argv[0][0] == '/')
{
// A direct path specification
path = std::string(argv[0]);
sf = fopen(argv[0], "r");
}
else
{
#ifdef CONFIG_OVMS_DEV_SDCARDSCRIPTS
path = std::string("/sd/scripts/");
path.append(argv[0]);
sf = fopen(path.c_str(), "r");
#endif // #ifdef CONFIG_OVMS_DEV_SDCARDSCRIPTS
if (sf == NULL)
{
path = std::string("/store/scripts/");
path.append(argv[0]);
sf = fopen(path.c_str(), "r");
}
}
if (sf == NULL)
{
writer->puts("Error: Script not found");
return;
}
script_ovms(verbosity, writer, path.c_str(), sf, writer->IsSecure());
}
void OvmsScripts::AllScripts(std::string path)
{
DIR *dir;
struct dirent *dp;
FILE *sf;
std::set<std::string> files;
// read dir, sort scripts by name:
if ((dir = opendir (path.c_str())) != NULL)
{
while ((dp = readdir (dir)) != NULL)
{
std::string fpath = path;
fpath.append("/");
fpath.append(dp->d_name);
files.insert(fpath);
}
closedir(dir);
}
// execute scripts:
for (auto it = files.begin(); it != files.end(); it++)
{
std::string fpath = *it;
sf = fopen(fpath.c_str(), "r");
if (sf)
{
ESP_LOGI(TAG, "Running script %s", fpath.c_str());
script_ovms(COMMAND_RESULT_MINIMAL, NULL, fpath.c_str(), sf, true);
// script_ovms() closes sf
}
}
}
void OvmsScripts::EventScript(std::string event, void* data)
{
std::string path;
#ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
MyDuktape.EventScript(event, data);
#endif // #ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
#ifdef CONFIG_OVMS_DEV_SDCARDSCRIPTS
// run event scripts on external storage:
path=std::string("/sd/events/");
path.append(event);
AllScripts(path);
#endif // #ifdef CONFIG_OVMS_DEV_SDCARDSCRIPTS
// run event scripts on internal storage:
path=std::string("/store/events/");
path.append(event);
AllScripts(path);
}
OvmsScripts::OvmsScripts()
{
ESP_LOGI(TAG, "Initialising SCRIPTS (1600)");
#ifdef CONFIG_OVMS_SC_JAVASCRIPT_NONE
ESP_LOGI(TAG, "No javascript engines enabled (command scripting only)");
#endif //#ifdef CONFIG_OVMS_SC_JAVASCRIPT_NONE
OvmsCommand* cmd_script = MyCommandApp.RegisterCommand("script","SCRIPT framework");
cmd_script->RegisterCommand("run","Run a script",script_run,"<path>",1,1);
#ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
cmd_script->RegisterCommand("reload","Reload javascript framework",script_reload);
cmd_script->RegisterCommand("eval","Eval some javascript code",script_eval,"<code>",1,1);
cmd_script->RegisterCommand("compact","Compact javascript heap",script_compact);
cmd_script->RegisterCommand("meminfo","Show heap memory status",script_meminfo);
#endif // #ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
MyCommandApp.RegisterCommand(".","Run a script",script_run,"<path>",1,1);
}
OvmsScripts::~OvmsScripts()
{
}