Uniot Core
0.9.0
Loading...
Searching...
No Matches
unLisp.h
Go to the documentation of this file.
1/*
2 * This is a part of the Uniot project.
3 * Copyright (C) 2016-2023 Uniot <contact@uniot.io>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
26
36
37#pragma once
38
39#include <Bytes.h>
40#include <CBORObject.h>
41#include <Common.h>
42#include <EventListener.h>
43#include <LimitedQueue.h>
44#include <LispEvents.h>
45#include <LispHelper.h>
46#include <Logger.h>
47#include <PrimitiveExpeditor.h>
48#include <Singleton.h>
49#include <TaskScheduler.h>
50#include <libminilisp.h>
51
52namespace uniot {
53using namespace lisp;
54
56 public:
58 int32_t value;
59 int8_t errorCode;
60
62 IncomingEvent(int32_t v, int8_t err = 0) : value(v), errorCode(err) {}
63 };
64
65 void pushEvent(const Bytes &eventData) {
66 CBORObject eventObj(eventData);
67 auto eventID = eventObj.getString("eventID");
68 auto valueStr = eventObj.getValueAsString("value");
69
70 if (eventID.isEmpty() || valueStr.isEmpty()) {
71 return; // Invalid event
72 }
73
74 auto value = valueStr.toInt();
75 auto isNumber = value || valueStr == "0";
76 if (!isNumber) {
77 return; // Invalid event
78 }
79
80 bool isNewEvent = !mIncomingEvents.exist(eventID);
81 if (isNewEvent) {
82 auto eventQueue = std::make_shared<EventQueue>();
83 mIncomingEvents.put(eventID, eventQueue);
84 UNIOT_LOG_DEBUG("created new event queue for '%s'", eventID.c_str());
85 }
86
87 auto eventQueue = mIncomingEvents.get(eventID);
88 eventQueue->lastAccessed = millis();
89
90 size_t queueSizeBefore = eventQueue->queue.size();
91 eventQueue->queue.pushLimited(IncomingEvent(value));
92 size_t queueSizeAfter = eventQueue->queue.size();
93
94 if (queueSizeAfter > queueSizeBefore) {
95 UNIOT_LOG_TRACE("pushed event '%s' with value '%d', queue size: %d", eventID.c_str(), value, queueSizeAfter);
96 } else {
97 UNIOT_LOG_WARN("event queue for '%s' is full (limit: %d), oldest event was dropped", eventID.c_str(), EVENTS_LIMIT);
98 }
99 }
100
101 bool isEventAvailable(const String &eventID) {
102 if (!mIncomingEvents.exist(eventID)) {
103 return false;
104 }
105
106 auto eventQueue = mIncomingEvents.get(eventID);
107 eventQueue->isUsedInScript = true;
108 eventQueue->lastAccessed = millis();
109
110 return eventQueue->queue.size() > 0;
111 }
112
113 IncomingEvent popEvent(const String &eventID) {
114 const IncomingEvent emptyEvent(0, -1);
115
116 if (!mIncomingEvents.exist(eventID)) {
117 UNIOT_LOG_WARN("attempted to pop non-existent event '%s'", eventID.c_str());
118 return emptyEvent;
119 }
120
121 auto eventQueue = mIncomingEvents.get(eventID);
122 eventQueue->isUsedInScript = true;
123 eventQueue->lastAccessed = millis();
124
125 if (eventQueue->queue.size() == 0) {
126 UNIOT_LOG_WARN("attempted to pop from empty event queue '%s'", eventID.c_str());
127 return emptyEvent;
128 }
129
130 return eventQueue->queue.popLimited(emptyEvent);
131 }
132
134 unsigned long currentTime = millis();
135 ClearQueue<String> keysToRemove;
136 size_t totalEvents = 0;
137 size_t unusedEvents = 0;
138 size_t expiredEvents = 0;
139 size_t totalQueuedItems = 0;
140
141 mIncomingEvents.forEach([&](const Pair<String, SharedPointer<EventQueue>> &entry) {
142 totalEvents++;
143 auto eventQueue = entry.second;
144 totalQueuedItems += eventQueue->queue.size();
145 unsigned long timeSinceLastAccess = currentTime - eventQueue->lastAccessed;
146
147 if (!eventQueue->isUsedInScript) {
148 unusedEvents++;
149 if (timeSinceLastAccess > EVENT_TTL_MS) {
150 expiredEvents++;
151 keysToRemove.push(entry.first);
152 UNIOT_LOG_DEBUG("marking event '%s' for removal (unused, last accessed %lu ms ago)",
153 entry.first.c_str(), timeSinceLastAccess);
154 }
155 }
156 });
157
158 // Remove expired events
159 keysToRemove.forEach([this](const String &key) {
160 mIncomingEvents.remove(key);
161 });
162
163 if (expiredEvents > 0) {
164 UNIOT_LOG_INFO("cleaned up %d expired events (total: %d, unused: %d, queued items: %d)",
165 expiredEvents, totalEvents, unusedEvents, totalQueuedItems);
166 } else if (totalEvents > 0) {
167 UNIOT_LOG_TRACE("no events to cleanup (total: %d, unused: %d, queued items: %d)", totalEvents, unusedEvents, totalQueuedItems);
168 }
169 }
170
171 void clean() {
172 mIncomingEvents.clean();
173 UNIOT_LOG_DEBUG("cleared all incoming events");
174 }
175
176 private:
177 struct EventQueue {
179 unsigned long lastAccessed;
180 bool isUsedInScript;
181
182 EventQueue() : lastAccessed(millis()), isUsedInScript(false) {
183 queue.limit(EVENTS_LIMIT);
184 }
185 };
186
187 Map<String, SharedPointer<EventQueue>> mIncomingEvents;
188 static constexpr size_t EVENTS_LIMIT = 2;
189 static constexpr unsigned long EVENT_TTL_MS = 30000; // 30 seconds TTL
190};
191
209class unLisp : public CoreEventListener, public Singleton<unLisp> {
210 friend class Singleton<unLisp>;
211
212 public:
218 return mTaskLispEval;
219 }
220
222 return mTaskEventCleanup;
223 }
224
230 bool isCreated() {
231 return lisp_is_created();
232 }
233
240 return mTaskLispEval->isAttached();
241 }
242
247 size_t memoryUsed() {
248 return lisp_mem_used();
249 }
250
260 // An empty script means "run nothing": stop whatever is running without building a
261 // machine for it. Emptiness is judged by content, not size -- code arrives as a
262 // terminated string, so an empty one is a single '\0' rather than zero bytes.
263 //
264 // mLastCode keeps a valid empty string rather than being freed, because store()
265 // reads it back through c_str() and would otherwise be handed a null pointer.
266 if (!data.size() || !data.c_str()[0]) {
267 mLastCode = data;
268 mLastCode.terminate();
269 mTaskLispEval->detach();
270 _destroyMachine(LispStopReason::Cleared);
271 return;
272 }
273
274 mLastCode = data;
275
276 mTaskLispEval->detach();
277 _destroyMachine(LispStopReason::Replaced);
278 _createMachine(reason);
279
280 auto code = mLastCode.terminate().c_str();
281 UNIOT_LOG_DEBUG("eval: %s", code);
282
283 _refreshIncomingEvents();
284 lisp_eval(mLispRoot, mLispEnv, code);
285 if (!mTaskLispEval->isAttached()) {
286 _destroyMachine(LispStopReason::Completed);
287 }
288 }
289
302 mStartHook = hook;
303 }
304
320 mStopHook = hook;
321 }
322
329 unLisp *pushPrimitive(Primitive *primitive) {
331 mUserPrimitives.push(MakePair(description.name, primitive));
332 UNIOT_LOG_TRACE("primitive added: %s", description.name.c_str());
333 UNIOT_LOG_TRACE("args count: %d", description.argsCount);
334 UNIOT_LOG_TRACE("return type: %d", description.returnType);
335 for (auto i = 0; i < description.argsCount; i++) {
336 UNIOT_LOG_TRACE("arg %d: %d", i, description.argsTypes[i]);
337 }
338 return this;
339 }
340
350 mUserPrimitives.forEach([&](Pair<const String &, Primitive *> holder) {
351 auto description = PrimitiveExpeditor::extractDescription(holder.second);
352 obj.putArray(holder.first.c_str())
353 .append(description.returnType)
354 .appendArray()
355 .append(description.argsCount, reinterpret_cast<const uint8_t *>(description.argsTypes));
356 });
357 }
358
364 UNIOT_LOG_WARN_IF(!mLastCode.size(), "there is no last saved code");
365 return mLastCode;
366 }
367
372 mLastCode.clean();
373 }
374
384 virtual void onEventReceived(unsigned int topic, int msg) override {
388 _pushIncomingEvent(data);
389 });
390 return;
391 }
392 return;
393 }
394 }
395
396 private:
403 unLisp() {
405
406 auto fnPrintOut = [](const char *msg, int size) {
407 if (size > 0) {
408 auto &instance = unLisp::getInstance();
409 instance.sendDataToChannel(events::lisp::Channel::OUT_LISP, Bytes((uint8_t *)msg, size).terminate());
411 }
412 yield();
413 };
414
415 auto fnPrintLog = [](const char *msg, int size) {
416 if (size > 0) {
417 auto &instance = unLisp::getInstance();
418 instance.sendDataToChannel(events::lisp::Channel::OUT_LISP_LOG, Bytes((uint8_t *)msg, size).terminate());
420 }
421 yield();
422 };
423
424 auto fnPrintErr = [](const char *msg, int size) {
425 auto &instance = unLisp::getInstance();
426 instance.sendDataToChannel(events::lisp::Channel::OUT_LISP_ERR, Bytes((uint8_t *)msg, size).terminate());
428
429 instance.mTaskLispEval->detach();
430 instance._destroyMachine(LispStopReason::Failed);
431 };
432
433 lisp_set_cycle_yield(yield);
434 lisp_set_printers(fnPrintOut, fnPrintLog, fnPrintErr);
435
436 _constructLispEnv();
437
438 mTaskLispEval = TaskScheduler::make([this](SchedulerTask &self, short t) {
439 auto root = mLispRoot;
440 auto env = mLispEnv;
441
442 DEFINE2(t_obj, t_pass);
443 *t_pass = get_variable(root, env, "#t_pass");
444 (*t_pass)->cdr->value = t;
445 *t_obj = get_variable(root, env, "#t_obj")->cdr;
446 safe_eval(root, env, t_obj);
447
448 if (!t) {
449 _destroyMachine(LispStopReason::Completed);
450 }
451
452 // UNIOT_LOG_DEBUG("lisp machine running, mem used: %d", lisp_mem_used());
453 });
454
455 mTaskEventCleanup = TaskScheduler::make([this](SchedulerTask &self, short t) {
456 mEventManager.cleanupUnusedEvents();
457 yield();
458 });
459 }
460
466 void _constructLispEnv() {
467 mLispEnvConstructor[0] = NULL;
468 mLispEnvConstructor[1] = NULL;
469 mLispEnvConstructor[2] = ROOT_END;
470 mLispRoot = mLispEnvConstructor;
471 mLispEnv = (Obj **)(mLispEnvConstructor + 1);
472 }
473
480 void _createMachine(LispStartReason reason) {
481 // The recursion limit was measured on target with examples/LispEvalDepth.
483
484 *mLispEnv = make_env(mLispRoot, &Nil, &Nil);
485 define_constants(mLispRoot, mLispEnv);
486 define_primitives(mLispRoot, mLispEnv);
487
488 // Register special variables and built-in primitives
489 add_constant(mLispRoot, mLispEnv, "#t_obj", &Nil);
490 add_constant_int(mLispRoot, mLispEnv, "#t_pass", 0);
491 add_primitive(mLispRoot, mLispEnv, "task", mPrimitiveTask);
492 add_primitive(mLispRoot, mLispEnv, "is_event", mPrimitiveIsEventAvailable);
493 add_primitive(mLispRoot, mLispEnv, "pop_event", mPrimitivePopEvent);
494 add_primitive(mLispRoot, mLispEnv, "push_event", mPrimitivePushEvent);
495
496 // Register all user-defined primitives
497 mUserPrimitives.forEach([this](Pair<const String &, Primitive *> holder) {
498 add_primitive(mLispRoot, mLispEnv, holder.first.c_str(), holder.second);
499 });
500
501 UNIOT_LOG_DEBUG("lisp machine created, mem used: %d", lisp_mem_used());
502
503 // Last, so the script sees a machine that is fully built, and so a hook that
504 // touches hardware runs before the first evaluation reads it.
505 if (mStartHook) {
506 mStartHook(reason);
507 }
508 }
509
519 void _destroyMachine(LispStopReason reason) {
520 // lisp_destroy() is a no-op when nothing was created, and runCode() calls this
521 // before the first script of all. Without this guard a stop would fire with no
522 // start before it.
523 if (!lisp_is_created()) {
524 return;
525 }
526
527 if (mStopHook) {
528 mStopHook(reason);
529 }
530
531 lisp_destroy();
532 }
533
537 void _refreshIncomingEvents() {
538 mEventManager.clean();
540 }
541
547 void _pushIncomingEvent(const Bytes &eventData) {
548 // mEventManager.cleanupUnusedEvents();
549 mEventManager.pushEvent(eventData);
550 }
551
559 bool _isIncomingEventAvailable(const String &eventID) {
560 return mEventManager.isEventAvailable(eventID);
561 }
562
570 IncomingEventManager::IncomingEvent _popIncomingEvent(const String &eventID) {
571 return mEventManager.popEvent(eventID);
572 }
573
582 bool _pushOutgoingEvent(String eventID, int value) {
583 CBORObject event;
584 event.put("eventID", eventID.c_str());
585 event.put("value", value);
586
587 auto sent = this->sendDataToChannel(events::lisp::Channel::OUT_EVENT, event.build());
589 return sent;
590 }
591
603 inline Object _primTask(Root root, VarObject env, VarObject list) {
605 .init(root, env, list);
606 expeditor.assertDescribedArgs();
607
608 auto times = expeditor.getArgInt(0);
609 auto ms = expeditor.getArgInt(1);
610 auto obj = expeditor.getArg(2);
611
612 DEFINE1(t_obj);
613 *t_obj = get_variable(root, env, "#t_obj");
614 (*t_obj)->cdr = obj;
615
616 mTaskLispEval->attach(ms, times);
617
618 return expeditor.makeBool(true);
619 }
620
631 inline Object _primIsEventAvailable(Root root, VarObject env, VarObject list) {
632 auto expeditor = PrimitiveExpeditor::describe("is_event", Lisp::Bool, 1, Lisp::Symbol)
633 .init(root, env, list);
634 expeditor.assertDescribedArgs();
635
636 auto eventId = expeditor.getArgSymbol(0);
637 auto available = _isIncomingEventAvailable(eventId);
638
639 return expeditor.makeBool(available);
640 }
641
654 inline Object _primPopEvent(Root root, VarObject env, VarObject list) {
655 auto expeditor = PrimitiveExpeditor::describe("pop_event", Lisp::Bool, 1, Lisp::Symbol)
656 .init(root, env, list);
657 expeditor.assertDescribedArgs();
658
659 auto eventId = expeditor.getArgSymbol(0);
660 auto event = _popIncomingEvent(eventId);
661 UNIOT_LOG_WARN_IF(event.errorCode, "error popping event '%s': %d", eventId, event.errorCode);
662 return expeditor.makeInt(event.value);
663 }
664
676 inline Object _primPushEvent(Root root, VarObject env, VarObject list) {
677 auto expeditor = PrimitiveExpeditor::describe("push_event", Lisp::Bool, 2, Lisp::Symbol, Lisp::BoolInt)
678 .init(root, env, list);
679 expeditor.assertDescribedArgs();
680
681 auto eventId = expeditor.getArgSymbol(0);
682 auto value = expeditor.getArgInt(1);
683
684 auto sent = _pushOutgoingEvent(eventId, value);
685
686 return expeditor.makeBool(sent);
687 }
688
689 // Private member variables
690 Bytes mLastCode;
691 TaskScheduler::TaskPtr mTaskLispEval;
692 TaskScheduler::TaskPtr mTaskEventCleanup;
693 ClearQueue<Pair<String, Primitive *>> mUserPrimitives;
694
698 const Primitive *mPrimitiveTask = [](Root root, VarObject env, VarObject list) { return getInstance()._primTask(root, env, list); };
699 const Primitive *mPrimitiveIsEventAvailable = [](Root root, VarObject env, VarObject list) { return getInstance()._primIsEventAvailable(root, env, list); };
700 const Primitive *mPrimitivePopEvent = [](Root root, VarObject env, VarObject list) { return getInstance()._primPopEvent(root, env, list); };
701 const Primitive *mPrimitivePushEvent = [](Root root, VarObject env, VarObject list) { return getInstance()._primPushEvent(root, env, list); };
702
703 void *mLispEnvConstructor[3];
704 Root mLispRoot;
705 VarObject mLispEnv;
706
707 LispStartHook mStartHook;
708 LispStopHook mStopHook;
709 IncomingEventManager mEventManager;
710};
711
712} // namespace uniot
Lisp interpreter event definitions for the Uniot event system.
Definition Bytes.h:38
Bytes & terminate()
Ensures the byte array is null-terminated.
Definition Bytes.h:281
const char * c_str() const
Gets the byte array as a C string.
Definition Bytes.h:306
size_t size() const
Gets the size of the byte array.
Definition Bytes.h:343
Definition ClearQueue.h:38
void forEach(VoidCallback callback) const
Executes a callback function on each element in the queue.
Definition ClearQueue.h:325
void push(const T &value)
Adds an element to the end of the queue.
Definition ClearQueue.h:207
Definition LimitedQueue.h:36
size_t limit() const
Get the current size limit of the queue.
Definition LimitedQueue.h:51
Array & append(int value)
Append an integer to the array.
Definition CBORObject.h:603
Array appendArray()
Append a new array as an element.
Definition CBORObject.h:645
Definition CBORObject.h:40
Array putArray(int key)
Create or get an array at a specific integer key.
Definition CBORObject.h:131
String getString(int key) const
Get a string value at a specific integer key.
Definition CBORObject.h:429
String getValueAsString(int key) const
Get a value as a string at a specific integer key.
Definition CBORObject.h:450
void emitEvent(unsigned int topic, int msg)
void receiveDataFromChannel(T_topic channel, DataChannelCallback callback)
Receives data from a specific channel on all connected EventBus instances.
Definition EventEntity.h:117
bool sendDataToChannel(T_topic channel, T_data data)
Sends data to a specific channel on all connected EventBus instances.
Definition EventEntity.h:98
EventListener * listenToEvent(unsigned int topic)
Definition unLisp.h:55
IncomingEvent popEvent(const String &eventID)
Definition unLisp.h:113
void clean()
Definition unLisp.h:171
void cleanupUnusedEvents()
Definition unLisp.h:133
bool isEventAvailable(const String &eventID)
Definition unLisp.h:101
void pushEvent(const Bytes &eventData)
Definition unLisp.h:65
@ BoolInt
Definition LispHelper.h:100
@ Symbol
Definition LispHelper.h:101
@ Cell
Definition LispHelper.h:102
@ Bool
Definition LispHelper.h:99
@ Int
Definition LispHelper.h:98
static PrimitiveDescription extractDescription(Primitive *primitive)
Extracts description metadata from a primitive function.
Definition PrimitiveExpeditor.h:116
static PrimitiveExpeditorInitializer describe(const String &name, Lisp::Type returnType, int argsCount,...)
Describes a primitive function by setting up its metadata.
Definition PrimitiveExpeditor.h:84
void assertDescribedArgs()
Asserts arguments against the primitive's description.
Definition PrimitiveExpeditor.h:297
Singleton(const Singleton &)=delete
static unLisp & getInstance()
Definition Singleton.h:73
Definition unLisp.h:209
TaskScheduler::TaskPtr getCleanupTask()
Definition unLisp.h:221
void setStopHook(LispStopHook hook)
Set the hook called when a script stops.
Definition unLisp.h:319
void setStartHook(LispStartHook hook)
Set the hook called when a script starts.
Definition unLisp.h:301
virtual void onEventReceived(unsigned int topic, int msg) override
Event handler for received events.
Definition unLisp.h:384
void serializePrimitives(CBORObject &obj)
Serialize all registered primitive functions to CBOR format.
Definition unLisp.h:349
TaskScheduler::TaskPtr getTask()
Get the task associated with Lisp evaluation.
Definition unLisp.h:217
const Bytes & getLastCode()
Get the last executed Lisp code.
Definition unLisp.h:363
void cleanLastCode()
Clear the stored last executed code.
Definition unLisp.h:371
size_t memoryUsed()
Get the amount of memory used by the Lisp machine.
Definition unLisp.h:247
void runCode(const Bytes &data, LispStartReason reason=LispStartReason::Received)
Run Lisp code in the interpreter.
Definition unLisp.h:259
bool taskIsRunning()
Check if the Lisp evaluation task is currently running.
Definition unLisp.h:239
unLisp * pushPrimitive(Primitive *primitive)
Add a new primitive function to the Lisp environment.
Definition unLisp.h:329
bool isCreated()
Check if the Lisp machine has been created.
Definition unLisp.h:230
auto MakePair(Args &&...args) -> decltype(std::make_pair(std::forward< Args >(args)...))
Creates a pair instance, alias for std::make_pair.
Definition Common.h:337
std::shared_ptr< T > SharedPointer
Type alias for std::shared_ptr with cleaner syntax.
Definition Common.h:313
std::pair< T_First, T_Second > Pair
Type alias for std::pair with cleaner syntax.
Definition Common.h:322
#define UNIOT_LISP_HEAP
Bytes of heap the Lisp interpreter is given at startup.
Definition Common.h:130
#define UNIOT_LISP_MAX_EVAL_STACK
Bytes of C stack an evaluation may spend before a script is abandoned.
Definition Common.h:158
EventListener< unsigned int, int, Bytes > CoreEventListener
Type alias for the common EventListener configuration used in the core system.
Definition EventListener.h:100
#define UNIOT_LOG_INFO(...)
Log an INFO level message Used for general information about system operation. Only compiled if UNIOT...
Definition Logger.h:315
#define UNIOT_LOG_TRACE(...)
Log an TRACE level message Used for general information about system operation. Only compiled if UNIO...
Definition Logger.h:361
#define UNIOT_LOG_WARN(...)
Log an WARN level message Used for warnings about potentially problematic situations....
Definition Logger.h:294
#define UNIOT_LOG_WARN_IF(log_cond, log...)
Conditionally log an WARN level message Used for warnings about potentially problematic situations....
Definition Logger.h:302
#define UNIOT_LOG_DEBUG(...)
Log an DEBUG level message Used for general information about system operation. Only compiled if UNIO...
Definition Logger.h:340
SharedPointer< SchedulerTask > TaskPtr
Shared pointer type for scheduler tasks.
Definition TaskScheduler.h:190
static TaskPtr make(SchedulerTask::SchedulerTaskCallback callback)
Static factory method to create a task with a callback.
Definition TaskScheduler.h:212
LispStartReason
Why a script started running.
Definition LispHelper.h:166
struct Obj * Object
A pointer to a Lisp object structure.
Definition LispHelper.h:63
void * Root
A generic pointer representing the root of a Lisp environment.
Definition LispHelper.h:78
LispStopReason
Why a script stopped running.
Definition LispHelper.h:175
std::function< void(LispStartReason)> LispStartHook
Called after the interpreter is built and before the script is evaluated.
Definition LispHelper.h:186
struct Obj ** VarObject
A pointer to a pointer to a Lisp object structure.
Definition LispHelper.h:71
std::function< void(LispStopReason)> LispStopHook
Called before the interpreter is destroyed.
Definition LispHelper.h:192
@ Received
A script that arrived over MQTT.
Definition LispHelper.h:168
@ Completed
The script ran to the end, or a finite task used up its passes.
Definition LispHelper.h:176
@ Cleared
An empty script arrived, which means "run nothing".
Definition LispHelper.h:178
@ Replaced
A new script arrived and took its place.
Definition LispHelper.h:177
@ Failed
A Lisp error tore the machine down.
Definition LispHelper.h:179
@ OUT_LISP_REQUEST
Topic for Lisp requests to the application services.
Definition LispEvents.h:89
@ OUT_LISP_MSG
Topic for Lisp output messages and notifications.
Definition LispEvents.h:88
@ IN_LISP_EVENT
Topic for incoming events from application to Lisp.
Definition LispEvents.h:91
@ OUT_LISP_EVENT
Topic for outgoing events from Lisp to application.
Definition LispEvents.h:90
@ IN_NEW_EVENT
New incoming event received from application for Lisp processing.
Definition LispEvents.h:107
@ OUT_MSG_ADDED
Standard output message was added to the output buffer.
Definition LispEvents.h:102
@ OUT_MSG_LOG
Log message was generated by the Lisp interpreter.
Definition LispEvents.h:103
@ OUT_NEW_EVENT
New outgoing event generated by Lisp for the application.
Definition LispEvents.h:106
@ OUT_REFRESH_EVENTS
Request to refresh the event queue and process pending events.
Definition LispEvents.h:105
@ OUT_MSG_ERROR
Error message was generated due to Lisp execution failure.
Definition LispEvents.h:104
@ OUT_LISP_LOG
Channel for Lisp log messages and debug information.
Definition LispEvents.h:74
@ IN_EVENT
Channel for incoming events from the application to Lisp.
Definition LispEvents.h:77
@ OUT_LISP
Channel for standard Lisp output (stdout equivalent)
Definition LispEvents.h:73
@ OUT_LISP_ERR
Channel for Lisp error messages and exceptions.
Definition LispEvents.h:75
@ OUT_EVENT
Channel for outgoing events from Lisp to the application.
Definition LispEvents.h:76
Contains type definitions and utilities for interacting with the Lisp interpreter.
Contains descriptions and implementations of primitive functions for hardware interaction.
Definition LispPrimitives.cpp:21
Contains all classes and functions related to the Uniot Core.
int32_t value
Definition unLisp.h:58
IncomingEvent(int32_t v, int8_t err=0)
Definition unLisp.h:62
int8_t errorCode
Definition unLisp.h:59