Run clang-format on source

This commit is contained in:
redfast00 2021-09-19 04:13:10 +02:00
parent e070010401
commit eb14a20f89
No known key found for this signature in database
GPG key ID: 5946E0E34FD0553C
3 changed files with 253 additions and 241 deletions

View file

@ -1,12 +1,13 @@
#include <string>
#include "log.h" #include "log.h"
#include <string>
using namespace std; using namespace std;
struct InterpreterConfig { struct InterpreterConfig {
unsigned int begin; unsigned int begin;
unsigned int length; unsigned int length;
bool enabled; bool enabled;
std::string scriptkey; // To change the script in this part of the interpreter and get logger output std::string scriptkey; // To change the script in this part of the interpreter
std::string persistkey; // To persist the current running script to disk // and get logger output
Log logger; std::string persistkey; // To persist the current running script to disk
Log logger;
}; };

View file

@ -1,55 +1,53 @@
#include <iostream> #include <iostream>
#include <vector>
#include <sstream> #include <sstream>
#include <vector>
#ifndef _LOG_ #ifndef _LOG_
#define _LOG_ #define _LOG_
class Log { class Log {
public: public:
Log() {} Log() {}
Log(unsigned int s) {size = s;} Log(unsigned int s) { size = s; }
~Log() { ~Log() {}
} template <typename T> Log &operator<<(const T &msg) {
template<typename T> std::stringstream current_string;
Log& operator<<(const T &msg) { current_string << msg;
std::stringstream current_string; os << msg;
current_string << msg;
os << msg;
if (current_string.str().back() == '\n') { if (current_string.str().back() == '\n') {
std::cout << "LOG: " << os.str(); std::cout << "LOG: " << os.str();
if (current >= size || full) { if (current >= size || full) {
if (ctr >= size) { if (ctr >= size) {
ctr = 0; ctr = 0;
}
buffer[ctr] = os.str();
full = true;
} else {
buffer.push_back(os.str());
}
ctr++;
current++;
os.str("");
} }
return *this; buffer[ctr] = os.str();
} full = true;
std::vector<std::string> getLogs() { } else {
std::vector<std::string> result; buffer.push_back(os.str());
int iterator_limit = std::min(size, current);
for (int i = iterator_limit - 1; i >= 0; i--) {
result.emplace_back(buffer[(current - 1 - i) % size]);
} }
return result; ctr++;
current++;
os.str("");
} }
return *this;
}
std::vector<std::string> getLogs() {
std::vector<std::string> result;
int iterator_limit = std::min(size, current);
for (int i = iterator_limit - 1; i >= 0; i--) {
result.emplace_back(buffer[(current - 1 - i) % size]);
}
return result;
}
private: private:
unsigned int current = 0; unsigned int current = 0;
unsigned int ctr = 0; unsigned int ctr = 0;
bool full = false; bool full = false;
std::vector<std::string> buffer; std::vector<std::string> buffer;
std::stringstream os; std::stringstream os;
unsigned int size = 255; unsigned int size = 255;
}; };
#endif #endif

View file

@ -1,18 +1,18 @@
#include <cstdio>
#include <thread>
#include <chrono>
#include <cstring>
#include <cstdlib>
#include <csignal>
#include <unordered_map>
#include <atomic> #include <atomic>
#include <chrono>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <optional> #include <optional>
#include <thread>
#include <unordered_map>
#include "interpreter_config.h"
#include "json.hpp"
#include "log.h"
#include "lua.hpp" #include "lua.hpp"
#include "ws2811.h" #include "ws2811.h"
#include "interpreter_config.h"
#include "log.h"
#include "json.hpp"
#include "httplib.h" #include "httplib.h"
@ -21,194 +21,210 @@ using std::chrono::duration_cast;
using std::chrono::milliseconds; using std::chrono::milliseconds;
using std::chrono::system_clock; using std::chrono::system_clock;
#define TARGET_FREQ WS2811_TARGET_FREQ
#define GPIO_PIN 18
#define DMA 10
#define STRIP_TYPE WS2812_STRIP // WS2812/SK6812RGB integrated chip+leds
#define LED_COUNT 30 * 5
#define TARGET_FREQ WS2811_TARGET_FREQ #define FPS 15
#define GPIO_PIN 18
#define DMA 10
#define STRIP_TYPE WS2812_STRIP // WS2812/SK6812RGB integrated chip+leds
#define LED_COUNT 30*5
#define FPS 15
int frametime = 1000 / FPS; int frametime = 1000 / FPS;
struct LedSegment { struct LedSegment {
std::optional<std::thread> lua_thread; std::optional<std::thread> lua_thread;
InterpreterConfig* interpreter_config; InterpreterConfig *interpreter_config;
std::string owner; std::string owner;
std::string lua_code; std::string lua_code;
}; };
std::vector<LedSegment*> ledsegments; std::vector<LedSegment *> ledsegments;
// this map is used to be able to see allowed leds from lua // this map is used to be able to see allowed leds from lua
std::unordered_map<lua_State*, InterpreterConfig*> statemap; std::unordered_map<lua_State *, InterpreterConfig *> statemap;
std::atomic<std::uint64_t> framecounter = {0}; std::atomic<std::uint64_t> framecounter = {0};
ws2811_t ledstring = ws2811_t ledstring = {
{
.freq = TARGET_FREQ, .freq = TARGET_FREQ,
.dmanum = DMA, .dmanum = DMA,
.channel = .channel =
{ {
[0] = { [0] =
.gpionum = GPIO_PIN, {
.invert = 0, .gpionum = GPIO_PIN,
.count = LED_COUNT, .invert = 0,
.strip_type = STRIP_TYPE, .count = LED_COUNT,
.brightness = 10, .strip_type = STRIP_TYPE,
.brightness = 10,
},
[1] =
{
.gpionum = 0,
.invert = 0,
.count = 0,
.brightness = 0,
},
}, },
[1] = {
.gpionum = 0,
.invert = 0,
.count = 0,
.brightness = 0,
},
},
}; };
void hook(lua_State* L, lua_Debug *ar); void hook(lua_State *L, lua_Debug *ar);
inline bool kill_thread_if_desired(lua_State *L) { inline bool kill_thread_if_desired(lua_State *L) {
if (!statemap[L]->enabled) if (!statemap[L]->enabled) {
{ cout << "putting errors on the stack" << endl;
cout << "putting errors on the stack" << endl; lua_sethook(L, hook, LUA_MASKLINE, 0);
lua_sethook(L, hook, LUA_MASKLINE, 0); luaL_error(L, "killed by manager");
luaL_error(L, "killed by manager"); return true;
return true;
} }
return false; return false;
} }
// TODO also call this hook about once every second // TODO also call this hook about once every second
void hook(lua_State* L, lua_Debug *ar) void hook(lua_State *L, lua_Debug *ar) { kill_thread_if_desired(L); }
{
kill_thread_if_desired(L);
}
extern "C" { extern "C" {
static int c_override_print (lua_State *L) { static int c_override_print(lua_State *L) {
kill_thread_if_desired(L); kill_thread_if_desired(L);
int n = lua_gettop(L); /* number of arguments */ int n = lua_gettop(L); /* number of arguments */
int i; int i;
for (i = 1; i <= n; i++) { /* for each argument */ for (i = 1; i <= n; i++) { /* for each argument */
size_t l; size_t l;
const char *s = luaL_tolstring(L, i, &l); /* convert it to string */ const char *s = luaL_tolstring(L, i, &l); /* convert it to string */
if (i > 1) /* not the first element? */ if (i > 1) /* not the first element? */
statemap[L]->logger << '\t'; /* add a tab before it */ statemap[L]->logger << '\t'; /* add a tab before it */
statemap[L]->logger << s; /* print it */ statemap[L]->logger << s; /* print it */
lua_pop(L, 1); /* pop result */ lua_pop(L, 1); /* pop result */
} }
statemap[L]->logger << '\n'; statemap[L]->logger << '\n';
return 0;
}
static int c_led(lua_State *L) {
kill_thread_if_desired(L);
int virtual_location = luaL_checkinteger(L, 1);
int red = luaL_checkinteger(L, 2);
int green = luaL_checkinteger(L, 3);
int blue = luaL_checkinteger(L, 4);
InterpreterConfig *config = statemap[L];
// Lua is one-based, let's keep it consistent and also make our API one-based
if (virtual_location <= 0 || virtual_location > (int)config->length) {
std::ostringstream errstream;
errstream << "setting led " << virtual_location << " of strip with lenght "
<< config->length << "";
luaL_argerror(L, 1, errstream.str().c_str());
return 0;
} else if (red < 0 || red > 0xff) {
std::ostringstream errstream;
errstream << "setting red channel to " << red
<< " but should be between 0 and 255";
luaL_argerror(L, 2, errstream.str().c_str());
return 0;
} else if (green < 0 || green > 0xff) {
std::ostringstream errstream;
errstream << "setting green channel to " << green
<< " but should be between 0 and 255";
luaL_argerror(L, 3, errstream.str().c_str());
return 0;
} else if (blue < 0 || blue > 0xff) {
std::ostringstream errstream;
errstream << "setting blue channel to " << blue
<< " but should be between 0 and 255";
luaL_argerror(L, 4, errstream.str().c_str());
return 0; return 0;
} }
unsigned int real_location = config->begin + virtual_location - 1;
// TODO remove this debugging line
ledstring.channel[0].leds[real_location] = (red << 16) | (green << 8) | blue;
return 0;
}
static int c_led (lua_State *L) { static int c_ledamount(lua_State *L) {
kill_thread_if_desired(L); kill_thread_if_desired(L);
int virtual_location = luaL_checkinteger(L, 1); lua_pushinteger(L, statemap[L]->length);
int red = luaL_checkinteger(L, 2); return 1;
int green = luaL_checkinteger(L, 3); }
int blue = luaL_checkinteger(L, 4);
InterpreterConfig* config = statemap[L];
// Lua is one-based, let's keep it consistent and also make our API one-based static int c_delay(lua_State *L) {
if (virtual_location <= 0 || virtual_location > (int) config->length) { if (kill_thread_if_desired(L)) {
std::ostringstream errstream; return 0;
errstream << "setting led " << virtual_location << " of strip with lenght " << config->length << ""; }
luaL_argerror(L, 1, errstream.str().c_str()); uint64_t millis = luaL_checkinteger(L, 1);
return 0; uint64_t begin =
} else if (red < 0 || red > 0xff) { duration_cast<milliseconds>(system_clock::now().time_since_epoch())
std::ostringstream errstream; .count();
errstream << "setting red channel to " << red << " but should be between 0 and 255";
luaL_argerror(L, 2, errstream.str().c_str()); while (duration_cast<milliseconds>(system_clock::now().time_since_epoch())
return 0; .count() -
} else if (green < 0 || green > 0xff) { begin <
std::ostringstream errstream; millis - 100) {
errstream << "setting green channel to " << green << " but should be between 0 and 255"; std::this_thread::sleep_for(std::chrono::milliseconds(100 - 5));
luaL_argerror(L, 3, errstream.str().c_str()); if (kill_thread_if_desired(L)) {
return 0;
} else if (blue < 0 || blue > 0xff) {
std::ostringstream errstream;
errstream << "setting blue channel to " << blue << " but should be between 0 and 255";
luaL_argerror(L, 4, errstream.str().c_str());
return 0;
}
unsigned int real_location = config->begin + virtual_location - 1;
// TODO remove this debugging line
ledstring.channel[0].leds[real_location] = (red << 16) | (green << 8)| blue;
return 0; return 0;
}
static int c_ledamount(lua_State *L) {
kill_thread_if_desired(L);
lua_pushinteger(L, statemap[L]->length);
return 1;
}
static int c_delay(lua_State *L) {
if (kill_thread_if_desired(L)) {return 0;}
uint64_t millis = luaL_checkinteger (L, 1);
uint64_t begin = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
while (duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count() - begin < millis - 100) {
std::this_thread::sleep_for(std::chrono::milliseconds(100-5));
if (kill_thread_if_desired(L)) {return 0;}
} }
uint64_t passed = (duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count() - begin);
std::this_thread::sleep_for(std::chrono::milliseconds(millis-passed));
return 0;
} }
uint64_t passed =
(duration_cast<milliseconds>(system_clock::now().time_since_epoch())
.count() -
begin);
std::this_thread::sleep_for(std::chrono::milliseconds(millis - passed));
return 0;
}
static int c_waitframes(lua_State *L) { static int c_waitframes(lua_State *L) {
kill_thread_if_desired(L); kill_thread_if_desired(L);
// TODO this is incorrect, fix this // TODO this is incorrect, fix this
int amount = luaL_checkinteger(L, 1); int amount = luaL_checkinteger(L, 1);
uint64_t destination = amount + framecounter; uint64_t destination = amount + framecounter;
if (amount >= 2 * FPS) { if (amount >= 2 * FPS) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000 * ((amount / FPS) - 1))); std::this_thread::sleep_for(
} std::chrono::milliseconds(1000 * ((amount / FPS) - 1)));
while (framecounter <= destination) {
std::this_thread::sleep_for(std::chrono::milliseconds(frametime / 2));
}
return 0;
} }
while (framecounter <= destination) {
std::this_thread::sleep_for(std::chrono::milliseconds(frametime / 2));
}
return 0;
}
} }
// Thanks to https://www.stefanmisik.com/post/sandboxing-lua-from-c.html // Thanks to https://www.stefanmisik.com/post/sandboxing-lua-from-c.html
static void LuaLoadAndUndefine(lua_State* L, lua_CFunction openFunction, const char* moduleName, const char* functions[]) static void LuaLoadAndUndefine(lua_State *L, lua_CFunction openFunction,
{ const char *moduleName,
/* Load the module, the module table gets placed on the top of the stack */ const char *functions[]) {
luaL_requiref(L, moduleName, openFunction, 1); /* Load the module, the module table gets placed on the top of the stack */
luaL_requiref(L, moduleName, openFunction, 1);
/* Undefine the unwanted functions */ /* Undefine the unwanted functions */
for (int i = 0; functions[i] != NULL; i++) for (int i = 0; functions[i] != NULL; i++) {
{ lua_pushnil(L);
lua_pushnil(L); lua_setfield(L, -2, functions[i]);
lua_setfield(L, -2, functions[i]); }
}
/* Pop the module table */ /* Pop the module table */
lua_pop(L, 1); lua_pop(L, 1);
} }
lua_State* setup_lua_sandbox(const char* luacode) { lua_State *setup_lua_sandbox(const char *luacode) {
lua_State* L = luaL_newstate(); lua_State *L = luaL_newstate();
L = luaL_newstate(); L = luaL_newstate();
if (!L) { if (!L) {
return nullptr; return nullptr;
} }
static const char* remove_base[] = {"assert", static const char *remove_base[] = {"assert", "collectgarbage",
"collectgarbage", "dofile", "getmetatable", "loadfile", "load", "dofile", "getmetatable",
"loadstring", "rawequal", "rawlen", "rawget", "rawset", "loadfile", "load",
"setmetatable", "print", NULL}; "loadstring", "rawequal",
"rawlen", "rawget",
"rawset", "setmetatable",
"print", NULL};
LuaLoadAndUndefine(L, luaopen_base, "_G", remove_base); LuaLoadAndUndefine(L, luaopen_base, "_G", remove_base);
static const char* remove_str[] = {"dump", NULL}; static const char *remove_str[] = {"dump", NULL};
LuaLoadAndUndefine(L, luaopen_string, LUA_STRLIBNAME, remove_str); LuaLoadAndUndefine(L, luaopen_string, LUA_STRLIBNAME, remove_str);
static const char* all_allowed[] = {NULL}; static const char *all_allowed[] = {NULL};
LuaLoadAndUndefine(L, luaopen_table, LUA_TABLIBNAME, all_allowed); LuaLoadAndUndefine(L, luaopen_table, LUA_TABLIBNAME, all_allowed);
LuaLoadAndUndefine(L, luaopen_math, LUA_MATHLIBNAME, all_allowed); LuaLoadAndUndefine(L, luaopen_math, LUA_MATHLIBNAME, all_allowed);
lua_pushcfunction(L, c_led); lua_pushcfunction(L, c_led);
lua_setglobal(L, "led"); lua_setglobal(L, "led");
lua_pushcfunction(L, c_ledamount); lua_pushcfunction(L, c_ledamount);
lua_setglobal(L, "ledamount"); lua_setglobal(L, "ledamount");
@ -225,7 +241,7 @@ lua_State* setup_lua_sandbox(const char* luacode) {
return L; return L;
} }
int execute_lua_sandbox(lua_State* L) { int execute_lua_sandbox(lua_State *L) {
int ret = lua_pcall(L, 0, 0, 0); int ret = lua_pcall(L, 0, 0, 0);
if (ret != 0) { if (ret != 0) {
// TODO get full stacktrace // TODO get full stacktrace
@ -238,66 +254,61 @@ int execute_lua_sandbox(lua_State* L) {
return 0; return 0;
} }
std::thread spawn_lua_tread(const char* luacode, InterpreterConfig* config) { std::thread spawn_lua_tread(const char *luacode, InterpreterConfig *config) {
lua_State* L = setup_lua_sandbox(luacode); lua_State *L = setup_lua_sandbox(luacode);
statemap[L] = config; statemap[L] = config;
std::thread t(execute_lua_sandbox, L); std::thread t(execute_lua_sandbox, L);
return t; return t;
} }
void signal_callback_handler(int signum) { void signal_callback_handler(int signum) {
(void) signum; (void)signum;
ws2811_fini(&ledstring); ws2811_fini(&ledstring);
exit(1); exit(1);
} }
httplib::Server svr; httplib::Server svr;
void starthttpserver() { void starthttpserver() { svr.listen("0.0.0.0", 8080); }
svr.listen("0.0.0.0", 8080);
}
int main(int argc, char **argv) {
int main(int argc, char** argv)
{
unsigned int amount = 10; unsigned int amount = 10;
unsigned int leds_per_segment = LED_COUNT / amount; unsigned int leds_per_segment = LED_COUNT / amount;
for (unsigned int i = 0; i < amount; i++) { for (unsigned int i = 0; i < amount; i++) {
InterpreterConfig* config = new InterpreterConfig { InterpreterConfig *config =
.begin = leds_per_segment*i, new InterpreterConfig{.begin = leds_per_segment * i,
.length = leds_per_segment, .length = leds_per_segment,
.enabled = true .enabled = true};
};
cout << config->begin << endl; cout << config->begin << endl;
LedSegment* segment = new LedSegment { LedSegment *segment = new LedSegment{.lua_thread = std::nullopt,
.lua_thread = std::nullopt, .interpreter_config = config,
.interpreter_config = config, .owner = "",
.owner = "", .lua_code = ""};
.lua_code = ""
};
ledsegments.push_back(segment); ledsegments.push_back(segment);
} }
svr.Get("/api/segments.json", [](const httplib::Request &, httplib::Response &res) { svr.Get("/api/segments.json",
res.set_header("Access-Control-Allow-Origin", "*"); [](const httplib::Request &, httplib::Response &res) {
res.set_header("Access-Control-Allow-Methods", "GET"); res.set_header("Access-Control-Allow-Origin", "*");
json j; res.set_header("Access-Control-Allow-Methods", "GET");
int i = 0; json j;
for (LedSegment* ledsegment : ledsegments) { int i = 0;
json o; for (LedSegment *ledsegment : ledsegments) {
o["begin"] = ledsegment->interpreter_config->begin; json o;
o["length"] = ledsegment->interpreter_config->length; o["begin"] = ledsegment->interpreter_config->begin;
o["owner"] = ledsegment->owner; o["length"] = ledsegment->interpreter_config->length;
o["code"] = ledsegment->lua_code; o["owner"] = ledsegment->owner;
o["id"] = i; o["code"] = ledsegment->lua_code;
i++; o["id"] = i;
j.push_back(o); i++;
} j.push_back(o);
res.set_content(j.dump(), "text/json"); }
}); res.set_content(j.dump(), "text/json");
});
svr.Put("/api/code.json", [](const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) { svr.Put("/api/code.json", [](const httplib::Request &req,
httplib::Response &res,
const httplib::ContentReader &content_reader) {
res.set_header("Access-Control-Allow-Origin", "*"); res.set_header("Access-Control-Allow-Origin", "*");
res.set_header("Access-Control-Allow-Methods", "PUT"); res.set_header("Access-Control-Allow-Methods", "PUT");
if (req.is_multipart_form_data()) { if (req.is_multipart_form_data()) {
@ -307,7 +318,7 @@ int main(int argc, char** argv)
content_reader([&](const char *raw_data, size_t data_length) { content_reader([&](const char *raw_data, size_t data_length) {
std::string data(raw_data, data_length); std::string data(raw_data, data_length);
auto j = json::parse(data); auto j = json::parse(data);
LedSegment* selected = ledsegments.at(j["id"].get<unsigned int>()); LedSegment *selected = ledsegments.at(j["id"].get<unsigned int>());
if (selected->lua_thread.has_value()) { if (selected->lua_thread.has_value()) {
selected->interpreter_config->enabled = false; selected->interpreter_config->enabled = false;
selected->lua_thread.value().join(); selected->lua_thread.value().join();
@ -315,27 +326,29 @@ int main(int argc, char** argv)
selected->owner = j["owner"].get<std::string>(); selected->owner = j["owner"].get<std::string>();
selected->lua_code = j["code"].get<std::string>(); selected->lua_code = j["code"].get<std::string>();
selected->interpreter_config->enabled = true; selected->interpreter_config->enabled = true;
selected->lua_thread = spawn_lua_tread(selected->lua_code.c_str(), selected->interpreter_config); selected->lua_thread = spawn_lua_tread(selected->lua_code.c_str(),
cout << "Uploaded new code from " << selected->owner << " to segment " << j["id"].get<unsigned int>() << endl; selected->interpreter_config);
cout << "Uploaded new code from " << selected->owner << " to segment "
<< j["id"].get<unsigned int>() << endl;
return true; return true;
}); });
} }
return true; return true;
}); });
svr.Options("/api/code.json", [](const httplib::Request &req, httplib::Response &res) { svr.Options("/api/code.json",
res.set_header("Access-Control-Allow-Origin", "*"); [](const httplib::Request &req, httplib::Response &res) {
res.set_header("Access-Control-Allow-Methods", "PUT"); res.set_header("Access-Control-Allow-Origin", "*");
return true; res.set_header("Access-Control-Allow-Methods", "PUT");
}); return true;
});
std::thread httpserverthread(starthttpserver); std::thread httpserverthread(starthttpserver);
ws2811_return_t ret; ws2811_return_t ret;
if ((ret = ws2811_init(&ledstring)) != WS2811_SUCCESS) if ((ret = ws2811_init(&ledstring)) != WS2811_SUCCESS) {
{ fprintf(stderr, "ws2811_init failed: %s\n", ws2811_get_return_t_str(ret));
fprintf(stderr, "ws2811_init failed: %s\n", ws2811_get_return_t_str(ret)); return ret;
return ret;
} }
signal(SIGINT, signal_callback_handler); signal(SIGINT, signal_callback_handler);
signal(SIGHUP, signal_callback_handler); signal(SIGHUP, signal_callback_handler);