diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e26937ce..60f3e2b1bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ### 6.06 -#### TBD +#### 2025-08-18 * LispBM: * New core extansions, optimization and much more unit testing. * Many bug fixes in the reader. diff --git a/ChibiOS_3.0.5/os/common/ports/ARMCMx/compilers/GCC/rules.mk b/ChibiOS_3.0.5/os/common/ports/ARMCMx/compilers/GCC/rules.mk index 44c1298d41..46d93f7f05 100644 --- a/ChibiOS_3.0.5/os/common/ports/ARMCMx/compilers/GCC/rules.mk +++ b/ChibiOS_3.0.5/os/common/ports/ARMCMx/compilers/GCC/rules.mk @@ -142,11 +142,7 @@ else LDFLAGS += -mno-thumb-interwork endif -ifeq ($(OS),Windows_NT) - DEPPATH = build\$(PROJECT)\.dep -else - DEPPATH = build/$(PROJECT)/.dep -endif +DEPPATH = build/$(PROJECT)/.dep # Generate dependency information ASFLAGS += -MD -MP -MF $(DEPPATH)/$(@F).d @@ -318,11 +314,7 @@ clean: # # Include the dependency files, should be the last of the makefile # -ifeq ($(OS),Windows_NT) - $(shell cmd /C if not exist "$(DEPPATH)" mkdir "$(DEPPATH)") -else - $(shell mkdir $(DEPPATH) 2>/dev/null) -endif +$(shell mkdir -p $(DEPPATH) 2>/dev/null) -include $(wildcard $(DEPPATH)/*) diff --git a/arm_sdk_install.log b/arm_sdk_install.log new file mode 100644 index 0000000000..8ebe4abf6a Binary files /dev/null and b/arm_sdk_install.log differ diff --git a/blackbox/SEGGER_RTT.c b/blackbox/SEGGER_RTT.c new file mode 100644 index 0000000000..070ef9610a --- /dev/null +++ b/blackbox/SEGGER_RTT.c @@ -0,0 +1,2057 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* https://github.com/SEGGERMicro/RTT * +* * +********************************************************************** + +---------------------------END-OF-HEADER------------------------------ +Purpose : Implementation of SEGGER real-time transfer (RTT) which + allows real-time communication on targets which support + debugger memory accesses while the CPU is running. + + SEGGER strongly recommends to not make any changes to or + modify the source code of this software in order to stay + compatible with the RTT protocol and J-Link. + +Additional information: + Type "int" is assumed to be 32-bits in size + H->T Host to target communication + T->H Target to host communication + + RTT channel 0 is always present and reserved for Terminal usage. + Name is fixed to "Terminal" + + Effective buffer size: SizeOfBuffer - 1 + + WrOff == RdOff: Buffer is empty + WrOff == (RdOff - 1): Buffer is full + WrOff > RdOff: Free space includes wrap-around + WrOff < RdOff: Used space includes wrap-around + (WrOff == (SizeOfBuffer - 1)) && (RdOff == 0): + Buffer full and wrap-around after next byte + +---------------------------------------------------------------------- +*/ + +#include "SEGGER_RTT.h" + +#include // for memcpy + +/********************************************************************* +* +* Configuration, default values +* +********************************************************************** +*/ + +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #ifdef SEGGER_RTT_CB_ALIGN + #error "Custom SEGGER_RTT_CB_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_BUFFER_ALIGN + #error "Custom SEGGER_RTT_BUFFER_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_PUT_CB_SECTION + #error "Custom SEGGER_RTT_PUT_CB_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_PUT_BUFFER_SECTION + #error "Custom SEGGER_RTT_PUT_BUFFER_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_BUFFER_ALIGNMENT + #error "Custom SEGGER_RTT_BUFFER_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_ALIGNMENT + #error "Custom SEGGER_RTT_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif +#endif + +#ifndef BUFFER_SIZE_UP + #define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host +#endif + +#ifndef BUFFER_SIZE_DOWN + #define BUFFER_SIZE_DOWN 16 // Size of the buffer for terminal input to target from host (Usually keyboard input) +#endif + +#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS + #define SEGGER_RTT_MAX_NUM_UP_BUFFERS 2 // Number of up-buffers (T->H) available on this target +#endif + +#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS + #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS 2 // Number of down-buffers (H->T) available on this target +#endif + +#ifndef SEGGER_RTT_ALIGNMENT + #define SEGGER_RTT_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE +#endif + +#ifndef SEGGER_RTT_BUFFER_ALIGNMENT + #define SEGGER_RTT_BUFFER_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE +#endif + +#ifndef SEGGER_RTT_MODE_DEFAULT + #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP +#endif + +#ifndef SEGGER_RTT_LOCK + #define SEGGER_RTT_LOCK() +#endif + +#ifndef SEGGER_RTT_UNLOCK + #define SEGGER_RTT_UNLOCK() +#endif + +#ifndef STRLEN + #define STRLEN(a) strlen((a)) +#endif + +#ifndef STRCPY + #define STRCPY(pDest, pSrc) strcpy((pDest), (pSrc)) +#endif + +#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP + #define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 +#endif + +#ifndef SEGGER_RTT_MEMCPY + #ifdef MEMCPY + #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) MEMCPY((pDest), (pSrc), (NumBytes)) + #else + #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) memcpy((pDest), (pSrc), (NumBytes)) + #endif +#endif + +#ifndef MIN + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ +#if (defined __ICCARM__) || (defined __ICCRX__) + #define RTT_PRAGMA(P) _Pragma(#P) +#endif + +#if SEGGER_RTT_ALIGNMENT || SEGGER_RTT_BUFFER_ALIGNMENT + #if ((defined __GNUC__) || (defined __clang__)) + #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment))) + #elif (defined __ICCARM__) || (defined __ICCRX__) + #define PRAGMA(A) _Pragma(#A) +#define SEGGER_RTT_ALIGN(Var, Alignment) RTT_PRAGMA(data_alignment=Alignment) \ + Var + #elif (defined __CC_ARM) + #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment))) + #else + #error "Alignment not supported for this compiler." + #endif +#else + #define SEGGER_RTT_ALIGN(Var, Alignment) Var +#endif + +#if defined(SEGGER_RTT_SECTION) || defined (SEGGER_RTT_BUFFER_SECTION) + #if ((defined __GNUC__) || (defined __clang__)) + #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section))) Var + #elif (defined __ICCARM__) || (defined __ICCRX__) +#define SEGGER_RTT_PUT_SECTION(Var, Section) RTT_PRAGMA(location=Section) \ + Var + #elif (defined __CC_ARM) + #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section))) Var + #else + #error "Section placement not supported for this compiler." + #endif +#else + #define SEGGER_RTT_PUT_SECTION(Var, Section) Var +#endif + +#if SEGGER_RTT_ALIGNMENT + #define SEGGER_RTT_CB_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_ALIGNMENT) +#else + #define SEGGER_RTT_CB_ALIGN(Var) Var +#endif + +#if SEGGER_RTT_BUFFER_ALIGNMENT + #define SEGGER_RTT_BUFFER_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_BUFFER_ALIGNMENT) +#else + #define SEGGER_RTT_BUFFER_ALIGN(Var) Var +#endif + + +#if defined(SEGGER_RTT_SECTION) + #define SEGGER_RTT_PUT_CB_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_SECTION) +#else + #define SEGGER_RTT_PUT_CB_SECTION(Var) Var +#endif + +#if defined(SEGGER_RTT_BUFFER_SECTION) + #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_BUFFER_SECTION) +#else + #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) Var +#endif + +/********************************************************************* +* +* Static const data +* +********************************************************************** +*/ + +static const unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/********************************************************************* +* +* Static data +* +********************************************************************** +*/ + +// +// RTT Control Block and allocate buffers for channel 0 +// +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #if ((defined __GNUC__) || (defined __clang__)) + SEGGER_RTT_CB _SEGGER_RTT __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + static char _acUpBuffer [SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)] __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)] __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + #elif (defined __ICCARM__) + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + SEGGER_RTT_CB _SEGGER_RTT; + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _acUpBuffer [SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)]; + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)]; + #else + #error "Don't know how to place _SEGGER_RTT, _acUpBuffer, _acDownBuffer cache-line aligned" + #endif +#else + SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); + SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer [BUFFER_SIZE_UP])); + SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN])); +#endif + +static unsigned char _ActiveTerminal; + +/********************************************************************* +* +* Static functions +* +********************************************************************** +*/ + +/********************************************************************* +* +* _DoInit() +* +* Function description +* Initializes the control block an buffers. +* +* Notes +* (1) May only be called via INIT() to avoid overriding settings. +* The only exception is SEGGER_RTT_Init(), to make an intentional override possible. +*/ + #define INIT() \ + do { \ + volatile SEGGER_RTT_CB* pRTTCBInit; \ + pRTTCBInit = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); \ + if (pRTTCBInit->acID[0] != 'S') { \ + _DoInit(); \ + } \ + } while (0) + +static void _DoInit(void) { + volatile SEGGER_RTT_CB* p; // Volatile to make sure that compiler cannot change the order of accesses to the control block + static const char _aInitStr[] = "\0\0\0\0\0\0TTR REGGES"; // Init complete ID string to make sure that things also work if RTT is linked to a no-init memory area + unsigned i; + // + // Initialize control block + // + p = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access control block uncached so that nothing in the cache ever becomes dirty and all changes are visible in HW directly + memset((SEGGER_RTT_CB*)p, 0, sizeof(_SEGGER_RTT)); // Make sure that the RTT CB is always zero initialized. + p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; + p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; + // + // Initialize up buffer 0 + // + p->aUp[0].sName = "Terminal"; + p->aUp[0].pBuffer = _acUpBuffer; + p->aUp[0].SizeOfBuffer = BUFFER_SIZE_UP; + p->aUp[0].RdOff = 0u; + p->aUp[0].WrOff = 0u; + p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Initialize down buffer 0 + // + p->aDown[0].sName = "Terminal"; + p->aDown[0].pBuffer = _acDownBuffer; + p->aDown[0].SizeOfBuffer = BUFFER_SIZE_DOWN; + p->aDown[0].RdOff = 0u; + p->aDown[0].WrOff = 0u; + p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Finish initialization of the control block. + // Copy Id string backwards to make sure that "SEGGER RTT" is not found in initializer memory (usually flash), + // as this would cause J-Link to "find" the control block at a wrong address. + // + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory accesses + for (i = 0; i < sizeof(_aInitStr) - 1; ++i) { + p->acID[i] = _aInitStr[sizeof(_aInitStr) - 2 - i]; // Skip terminating \0 at the end of the array + } + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory accesses +} + +/********************************************************************* +* +* _WriteBlocking() +* +* Function description +* Stores a specified number of characters in SEGGER RTT ring buffer +* and updates the associated write pointer which is periodically +* read by the host. +* The caller is responsible for managing the write chunk sizes as +* _WriteBlocking() will block until all data has been posted successfully. +* +* Parameters +* pRing Ring buffer to post to. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* >= 0 - Number of bytes written into buffer. +*/ +static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, unsigned NumBytes) { + unsigned NumBytesToWrite; + unsigned NumBytesWritten; + unsigned RdOff; + unsigned WrOff; + volatile char* pDst; + // + // Write data to buffer and handle wrap-around if necessary + // + NumBytesWritten = 0u; + WrOff = pRing->WrOff; + do { + RdOff = pRing->RdOff; // May be changed by host (debug probe) in the meantime + if (RdOff > WrOff) { + NumBytesToWrite = RdOff - WrOff - 1u; + } else { + NumBytesToWrite = pRing->SizeOfBuffer - (WrOff - RdOff + 1u); + } + NumBytesToWrite = MIN(NumBytesToWrite, (pRing->SizeOfBuffer - WrOff)); // Number of bytes that can be written until buffer wrap-around + NumBytesToWrite = MIN(NumBytesToWrite, NumBytes); + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesWritten += NumBytesToWrite; + NumBytes -= NumBytesToWrite; + WrOff += NumBytesToWrite; + while (NumBytesToWrite--) { + *pDst++ = *pBuffer++; + }; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pBuffer, NumBytesToWrite); + NumBytesWritten += NumBytesToWrite; + pBuffer += NumBytesToWrite; + NumBytes -= NumBytesToWrite; + WrOff += NumBytesToWrite; +#endif + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0u; + } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + } while (NumBytes); + return NumBytesWritten; +} + +/********************************************************************* +* +* _WriteNoCheck() +* +* Function description +* Stores a specified number of characters in SEGGER RTT ring buffer +* and updates the associated write pointer which is periodically +* read by the host. +* It is callers responsibility to make sure data actually fits in buffer. +* +* Parameters +* pRing Ring buffer to post to. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Notes +* (1) If there might not be enough space in the "Up"-buffer, call _WriteBlocking +*/ +static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsigned NumBytes) { + unsigned NumBytesAtOnce; + unsigned WrOff; + unsigned Rem; + volatile char* pDst; + + WrOff = pRing->WrOff; + Rem = pRing->SizeOfBuffer - WrOff; + if (Rem > NumBytes) { + // + // All data fits before wrap around + // + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + WrOff += NumBytes; + while (NumBytes--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; +#endif + } else { + // + // We reach the end of the buffer, so need to wrap around + // +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + NumBytesAtOnce = Rem; + while (NumBytesAtOnce--) { + *pDst++ = *pData++; + }; + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + NumBytesAtOnce = NumBytes - Rem; + while (NumBytesAtOnce--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = NumBytes - Rem; +#else + NumBytesAtOnce = Rem; + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytesAtOnce); + NumBytesAtOnce = NumBytes - Rem; + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData + Rem, NumBytesAtOnce); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = NumBytesAtOnce; +#endif + } +} + +/********************************************************************* +* +* _PostTerminalSwitch() +* +* Function description +* Switch terminal to the given terminal ID. It is the caller's +* responsibility to ensure the terminal ID is correct and there is +* enough space in the buffer for this to complete successfully. +* +* Parameters +* pRing Ring buffer to post to. +* TerminalId Terminal ID to switch to. +*/ +static void _PostTerminalSwitch(SEGGER_RTT_BUFFER_UP* pRing, unsigned char TerminalId) { + unsigned char ac[2]; + + ac[0] = 0xFFu; + ac[1] = _aTerminalId[TerminalId]; // Caller made already sure that TerminalId does not exceed our terminal limit + _WriteBlocking(pRing, (const char*)ac, 2u); +} + +/********************************************************************* +* +* _GetAvailWriteSpace() +* +* Function description +* Returns the number of bytes that can be written to the ring +* buffer without blocking. +* +* Parameters +* pRing Ring buffer to check. +* +* Return value +* Number of bytes that are free in the buffer. +*/ +static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP* pRing) { + unsigned RdOff; + unsigned WrOff; + unsigned r; + // + // Avoid warnings regarding volatile access order. It's not a problem + // in this case, but dampen compiler enthusiasm. + // + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + if (RdOff <= WrOff) { + r = pRing->SizeOfBuffer - 1u - WrOff + RdOff; + } else { + r = RdOff - WrOff - 1u; + } + return r; +} + +/********************************************************************* +* +* Public code +* +********************************************************************** +*/ + +/********************************************************************* +* +* SEGGER_RTT_ReadUpBufferNoLock() +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the application. +* Do not lock against interrupts and multiple access. +* Used to do the same operation that J-Link does, to transfer +* RTT data via other channels, such as TCP/IP or UART. +* +* Parameters +* BufferIndex Index of Up-buffer to be used. +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-up-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +*/ +unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { + unsigned NumBytesRem; + unsigned NumBytesRead; + unsigned RdOff; + unsigned WrOff; + unsigned char* pBuffer; + SEGGER_RTT_BUFFER_UP* pRing; + volatile char* pSrc; + + INIT(); + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + pBuffer = (unsigned char*)pData; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + NumBytesRead = 0u; + // + // Read from current read position to wrap-around of buffer, first + // + if (RdOff > WrOff) { + NumBytesRem = pRing->SizeOfBuffer - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + // + // Handle wrap-around of buffer + // + if (RdOff == pRing->SizeOfBuffer) { + RdOff = 0u; + } + } + // + // Read remaining items of buffer + // + NumBytesRem = WrOff - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + if (NumBytesRem > 0u) { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + } + // + // Update read offset of buffer + // + if (NumBytesRead) { + pRing->RdOff = RdOff; + } + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_ReadNoLock() +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the host. +* Do not lock against interrupts and multiple access. +* +* Parameters +* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +*/ +unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { + unsigned NumBytesRem; + unsigned NumBytesRead; + unsigned RdOff; + unsigned WrOff; + unsigned char* pBuffer; + SEGGER_RTT_BUFFER_DOWN* pRing; + volatile char* pSrc; + // + INIT(); + pRing = (SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + pBuffer = (unsigned char*)pData; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + NumBytesRead = 0u; + // + // Read from current read position to wrap-around of buffer, first + // + if (RdOff > WrOff) { + NumBytesRem = pRing->SizeOfBuffer - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + // + // Handle wrap-around of buffer + // + if (RdOff == pRing->SizeOfBuffer) { + RdOff = 0u; + } + } + // + // Read remaining items of buffer + // + NumBytesRem = WrOff - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + if (NumBytesRem > 0u) { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + } + if (NumBytesRead) { + pRing->RdOff = RdOff; + } + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_ReadUpBuffer +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the application. +* Used to do the same operation that J-Link does, to transfer +* RTT data via other channels, such as TCP/IP or UART. +* +* Parameters +* BufferIndex Index of Up-buffer to be used. +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-up-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +* This function locks against all other RTT operations. I.e. during +* the read operation, writing is also locked. +* If only one consumer reads from the up buffer, +* call sEGGER_RTT_ReadUpBufferNoLock() instead. +*/ +unsigned SEGGER_RTT_ReadUpBuffer(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { + unsigned NumBytesRead; + + SEGGER_RTT_LOCK(); + // + // Call the non-locking read function + // + NumBytesRead = SEGGER_RTT_ReadUpBufferNoLock(BufferIndex, pBuffer, BufferSize); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_Read +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the host. +* +* Parameters +* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +*/ +unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { + unsigned NumBytesRead; + + SEGGER_RTT_LOCK(); + // + // Call the non-locking read function + // + NumBytesRead = SEGGER_RTT_ReadNoLock(BufferIndex, pBuffer, BufferSize); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteWithOverwriteNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block. +* SEGGER_RTT_WriteWithOverwriteNoLock does not lock the application +* and overwrites data if the data does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, data is overwritten. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +* (3) Do not use SEGGER_RTT_WriteWithOverwriteNoLock if a J-Link +* connection reads RTT data. +*/ +void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + volatile char* pDst; + // + // Get "to-host" ring buffer and copy some elements into local variables. + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Check if we will overwrite data and need to adjust the RdOff. + // + if (pRing->WrOff == pRing->RdOff) { + Avail = pRing->SizeOfBuffer - 1u; + } else if ( pRing->WrOff < pRing->RdOff) { + Avail = pRing->RdOff - pRing->WrOff - 1u; + } else { + Avail = pRing->RdOff - pRing->WrOff - 1u + pRing->SizeOfBuffer; + } + if (NumBytes > Avail) { + pRing->RdOff += (NumBytes - Avail); + while (pRing->RdOff >= pRing->SizeOfBuffer) { + pRing->RdOff -= pRing->SizeOfBuffer; + } + } + // + // Write all data, no need to check the RdOff, but possibly handle multiple wrap-arounds + // + Avail = pRing->SizeOfBuffer - pRing->WrOff; + do { + if (Avail > NumBytes) { + // + // Last round + // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + Avail = NumBytes; + while (NumBytes--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff += Avail; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff += NumBytes; +#endif + break; + } else { + // + // Wrap-around necessary, write until wrap-around and reset WrOff + // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytes -= Avail; + while (Avail--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = 0; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, Avail); + pData += Avail; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = 0; + NumBytes -= Avail; +#endif + Avail = (pRing->SizeOfBuffer - 1); + } + } while (NumBytes); +} + +/********************************************************************* +* +* SEGGER_RTT_WriteSkipNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* SEGGER_RTT_WriteSkipNoLock does not lock the application and +* skips all data, if the data does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* MUST be > 0!!! +* This is done for performance reasons, so no initial check has do be done. +* +* Return value +* 1: Data has been copied +* 0: No space, data has not been copied +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, all data is dropped. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ +#if (RTT_USE_ASM == 0) +unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + unsigned RdOff; + unsigned WrOff; + unsigned Rem; + volatile char* pDst; + // + // Cases: + // 1) RdOff <= WrOff => Space until wrap-around is sufficient + // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks) + // 3) RdOff < WrOff => No space in buf + // 4) RdOff > WrOff => Space is sufficient + // 5) RdOff > WrOff => No space in buf + // + // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + if (RdOff <= WrOff) { // Case 1), 2) or 3) + Avail = pRing->SizeOfBuffer - WrOff - 1u; // Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) + if (Avail >= NumBytes) { // Case 1)? + memcpy((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; + return 1; + } + Avail += RdOff; // Space incl. wrap-around + if (Avail >= NumBytes) { // Case 2? => If not, we have case 3) (does not fit) + Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer + memcpy((void*)pDst, pData, Rem); // Copy 1st chunk + NumBytes -= Rem; + // + // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used + // But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element + // In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks + // Therefore, check if 2nd memcpy is necessary at all + // + if (NumBytes) { + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + memcpy((void*)pDst, pData + Rem, NumBytes); + } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = NumBytes; + return 1; + } + } else { // Potential case 4) + Avail = RdOff - WrOff - 1u; + if (Avail >= NumBytes) { // Case 4)? => If not, we have case 5) (does not fit) + memcpy((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; + return 1; + } + } + return 0; // No space in buffer +} +#endif + +/********************************************************************* +* +* SEGGER_RTT_WriteDownBufferNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block inside a buffer. +* SEGGER_RTT_WriteDownBufferNoLock does not lock the application. +* Used to do the same operation that J-Link does, to transfer +* RTT data from other channels, such as TCP/IP or UART. +* +* Parameters +* BufferIndex Index of "Down"-buffer to be used. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Down"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +*/ +unsigned SEGGER_RTT_WriteDownBufferNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + unsigned Avail; + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + // + // Get "to-target" ring buffer. + // It is save to cast that to a "to-host" buffer. Up and Down buffer differ in volatility of offsets that might be modified by J-Link. + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // How we output depends upon the mode... + // + switch (pRing->Flags) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother. + // + Avail = _GetAvailWriteSpace(pRing); + if (Avail < NumBytes) { + Status = 0u; + } else { + Status = NumBytes; + _WriteNoCheck(pRing, pData, NumBytes); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode, trim to what we can output without blocking. + // + Avail = _GetAvailWriteSpace(pRing); + Status = Avail < NumBytes ? Avail : NumBytes; + _WriteNoCheck(pRing, pData, Status); + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + Status = _WriteBlocking(pRing, pData, NumBytes); + break; + default: + Status = 0u; + break; + } + // + // Finish up. + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* SEGGER_RTT_WriteNoLock does not lock the application. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ +unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + unsigned Avail; + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + // + // Get "to-host" ring buffer. + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // How we output depends upon the mode... + // + switch (pRing->Flags) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother. + // + Avail = _GetAvailWriteSpace(pRing); + if (Avail < NumBytes) { + Status = 0u; + } else { + Status = NumBytes; + _WriteNoCheck(pRing, pData, NumBytes); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode, trim to what we can output without blocking. + // + Avail = _GetAvailWriteSpace(pRing); + Status = Avail < NumBytes ? Avail : NumBytes; + _WriteNoCheck(pRing, pData, Status); + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + Status = _WriteBlocking(pRing, pData, NumBytes); + break; + default: + Status = 0u; + break; + } + // + // Finish up. + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteDownBuffer +* +* Function description +* Stores a specified number of characters in SEGGER RTT control block in a buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Down"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +* This function locks against all other RTT operations. I.e. during +* the write operation, writing from the application is also locked. +* If only one consumer writes to the down buffer, +* call SEGGER_RTT_WriteDownBufferNoLock() instead. +*/ +unsigned SEGGER_RTT_WriteDownBuffer(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + + INIT(); + SEGGER_RTT_LOCK(); + Status = SEGGER_RTT_WriteDownBufferNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_Write +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +*/ +unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + + INIT(); + SEGGER_RTT_LOCK(); + Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteString +* +* Function description +* Stores string in SEGGER RTT control block. +* This data is read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* s Pointer to string. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* (2) String passed to this function has to be \0 terminated +* (3) \0 termination character is *not* stored in RTT buffer +*/ +unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s) { + unsigned Len; + + Len = STRLEN(s); + return SEGGER_RTT_Write(BufferIndex, s, Len); +} + +/********************************************************************* +* +* SEGGER_RTT_PutCharSkipNoLock +* +* Function description +* Stores a single character/byte in SEGGER RTT buffer. +* SEGGER_RTT_PutCharSkipNoLock does not lock the application and +* skips the byte, if it does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* c Byte to be stored. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, the character is dropped. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ + +unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0; + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } else { + Status = 0; + } + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_PutCharSkip +* +* Function description +* Stores a single character/byte in SEGGER RTT buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* c Byte to be stored. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, the character is dropped. +*/ + +unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Prepare + // + INIT(); + SEGGER_RTT_LOCK(); + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0; + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } else { + Status = 0; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return Status; +} + + /********************************************************************* +* +* SEGGER_RTT_PutChar +* +* Function description +* Stores a single character/byte in SEGGER RTT buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* c Byte to be stored. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +*/ + +unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Prepare + // + INIT(); + SEGGER_RTT_LOCK(); + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0; + } + // + // Wait for free space if mode is set to blocking + // + if (pRing->Flags == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { + while (WrOff == pRing->RdOff) { + ; + } + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } else { + Status = 0; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_GetKey +* +* Function description +* Reads one character from the SEGGER RTT buffer. +* Host has previously stored data there. +* +* Return value +* < 0 - No character available (buffer empty). +* >= 0 - Character which has been read. (Possible values: 0 - 255) +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0. +*/ +int SEGGER_RTT_GetKey(void) { + char c; + int r; + + r = (int)SEGGER_RTT_Read(0u, &c, 1u); + if (r == 1) { + r = (int)(unsigned char)c; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_WaitKey +* +* Function description +* Waits until at least one character is avaible in the SEGGER RTT buffer. +* Once a character is available, it is read and this function returns. +* +* Return value +* >=0 - Character which has been read. +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0 +* (2) This function is blocking if no character is present in RTT buffer +*/ +int SEGGER_RTT_WaitKey(void) { + int r; + + do { + r = SEGGER_RTT_GetKey(); + } while (r < 0); + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_HasKey +* +* Function description +* Checks if at least one character for reading is available in the SEGGER RTT buffer. +* +* Return value +* == 0 - No characters are available to read. +* == 1 - At least one character is available. +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0 +*/ +int SEGGER_RTT_HasKey(void) { + SEGGER_RTT_BUFFER_DOWN* pRing; + unsigned RdOff; + int r; + + INIT(); + pRing = (SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRing->RdOff; + if (RdOff != pRing->WrOff) { + r = 1; + } else { + r = 0; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_HasData +* +* Function description +* Check if there is data from the host in the given buffer. +* +* Return value: +* ==0: No data +* !=0: Data in buffer +* +*/ +unsigned SEGGER_RTT_HasData(unsigned BufferIndex) { + SEGGER_RTT_BUFFER_DOWN* pRing; + unsigned v; + + pRing = (SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + v = pRing->WrOff; + return v - pRing->RdOff; +} + +/********************************************************************* +* +* SEGGER_RTT_HasDataUp +* +* Function description +* Check if there is data remaining to be sent in the given buffer. +* +* Return value: +* ==0: No data +* !=0: Data in buffer +* +*/ +unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned v; + + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + v = pRing->RdOff; + return pRing->WrOff - v; +} + +/********************************************************************* +* +* SEGGER_RTT_AllocDownBuffer +* +* Function description +* Run-time configuration of the next down-buffer (H->T). +* The next buffer, which is not used yet is configured. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 - O.K. Buffer Index +* < 0 - Error +*/ +int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; + + INIT(); + SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + BufferIndex = 0; + do { + if (pRTTCB->aDown[BufferIndex].pBuffer == NULL) { + break; + } + BufferIndex++; + } while (BufferIndex < pRTTCB->MaxNumDownBuffers); + if (BufferIndex < pRTTCB->MaxNumDownBuffers) { + pRTTCB->aDown[BufferIndex].sName = sName; + pRTTCB->aDown[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aDown[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aDown[BufferIndex].RdOff = 0u; + pRTTCB->aDown[BufferIndex].WrOff = 0u; + pRTTCB->aDown[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + } else { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* +* +* SEGGER_RTT_AllocUpBuffer +* +* Function description +* Run-time configuration of the next up-buffer (T->H). +* The next buffer, which is not used yet is configured. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 - O.K. Buffer Index +* < 0 - Error +*/ +int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; + + INIT(); + SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + BufferIndex = 0; + do { + if (pRTTCB->aUp[BufferIndex].pBuffer == NULL) { + break; + } + BufferIndex++; + } while (BufferIndex < pRTTCB->MaxNumUpBuffers); + if (BufferIndex < pRTTCB->MaxNumUpBuffers) { + pRTTCB->aUp[BufferIndex].sName = sName; + pRTTCB->aUp[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aUp[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aUp[BufferIndex].RdOff = 0u; + pRTTCB->aUp[BufferIndex].WrOff = 0u; + pRTTCB->aUp[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + } else { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* +* +* SEGGER_RTT_ConfigUpBuffer +* +* Function description +* Run-time configuration of a specific up-buffer (T->H). +* Buffer to be configured is specified by index. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* BufferIndex Index of the buffer to configure. +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 - O.K. +* < 0 - Error +* +* Additional information +* Buffer 0 is configured on compile-time. +* May only be called once per buffer. +* Buffer name and flags can be reconfigured using the appropriate functions. +*/ +int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + if (BufferIndex) { + pUp->sName = sName; + pUp->pBuffer = (char*)pBuffer; + pUp->SizeOfBuffer = BufferSize; + pUp->RdOff = 0u; + pUp->WrOff = 0u; + } + pUp->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_ConfigDownBuffer +* +* Function description +* Run-time configuration of a specific down-buffer (H->T). +* Buffer to be configured is specified by index. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* BufferIndex Index of the buffer to configure. +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 O.K. +* < 0 Error +* +* Additional information +* Buffer 0 is configured on compile-time. +* May only be called once per buffer. +* Buffer name and flags can be reconfigured using the appropriate functions. +*/ +int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + if (BufferIndex) { + pDown->sName = sName; + pDown->pBuffer = (char*)pBuffer; + pDown->SizeOfBuffer = BufferSize; + pDown->RdOff = 0u; + pDown->WrOff = 0u; + } + pDown->Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetNameUpBuffer +* +* Function description +* Run-time configuration of a specific up-buffer name (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* sName Pointer to a constant name string. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetNameDownBuffer +* +* Function description +* Run-time configuration of a specific Down-buffer name (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* sName Pointer to a constant name string. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetFlagsUpBuffer +* +* Function description +* Run-time configuration of specific up-buffer flags (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer. +* Flags Flags to set for the buffer. +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetFlagsDownBuffer +* +* Function description +* Run-time configuration of specific Down-buffer flags (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* Flags Flags to set for the buffer. +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_Init +* +* Function description +* Initializes the RTT Control Block. +* Should be used in RAM targets, at start of the application. +* +*/ +void SEGGER_RTT_Init (void) { + _DoInit(); +} + +/********************************************************************* +* +* SEGGER_RTT_SetTerminal +* +* Function description +* Sets the terminal to be used for output on channel 0. +* +* Parameters +* TerminalId Index of the terminal. +* +* Return value +* >= 0 O.K. +* < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the buffer to set the new terminal Id) +* +* Notes +* (1) Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed +*/ +int SEGGER_RTT_SetTerminal (unsigned char TerminalId) { + unsigned char ac[2]; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + int r; + + INIT(); + r = 0; + ac[0] = 0xFFu; + if (TerminalId < sizeof(_aTerminalId)) { // We only support a certain number of channels + ac[1] = _aTerminalId[TerminalId]; + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing + if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { + _ActiveTerminal = TerminalId; + _WriteBlocking(pRing, (const char*)ac, 2u); + } else { // Skipping mode or trim mode? => We cannot trim this command so handling is the same for both modes + Avail = _GetAvailWriteSpace(pRing); + if (Avail >= 2) { + _ActiveTerminal = TerminalId; // Only change active terminal in case of success + _WriteNoCheck(pRing, (const char*)ac, 2u); + } else { + r = -1; + } + } + SEGGER_RTT_UNLOCK(); + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_TerminalOut +* +* Function description +* Writes a string to the given terminal +* without changing the terminal for channel 0. +* +* Parameters +* TerminalId Index of the terminal. +* s String to be printed on the terminal. +* +* Return value +* >= 0 - Number of bytes written. +* < 0 - Error. +* +*/ +int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s) { + int Status; + unsigned FragLen; + unsigned Avail; + SEGGER_RTT_BUFFER_UP* pRing; + // + INIT(); + // + // Validate terminal ID. + // + if (TerminalId < (char)sizeof(_aTerminalId)) { // We only support a certain number of channels + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Need to be able to change terminal, write data, change back. + // Compute the fixed and variable sizes. + // + FragLen = STRLEN(s); + // + // How we output depends upon the mode... + // + SEGGER_RTT_LOCK(); + Avail = _GetAvailWriteSpace(pRing); + switch (pRing->Flags & SEGGER_RTT_MODE_MASK) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother switching terminals at all. + // + if (Avail < (FragLen + 4u)) { + Status = 0; + } else { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode and there is not enough space for everything, + // trim the output but always include the terminal switch. If no room + // for terminal switch, skip that totally. + // + if (Avail < 4u) { + Status = -1; + } else { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, (FragLen < (Avail - 4u)) ? FragLen : (Avail - 4u)); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + break; + default: + Status = -1; + break; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + } else { + Status = -1; + } + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_GetAvailWriteSpace +* +* Function description +* Returns the number of bytes available in the ring buffer. +* +* Parameters +* BufferIndex Index of the up buffer. +* +* Return value +* Number of bytes that are free in the selected up buffer. +*/ +unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex) { + SEGGER_RTT_BUFFER_UP* pRing; + + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + return _GetAvailWriteSpace(pRing); +} + + +/********************************************************************* +* +* SEGGER_RTT_GetBytesInBuffer() +* +* Function description +* Returns the number of bytes currently used in the up buffer. +* +* Parameters +* BufferIndex Index of the up buffer. +* +* Return value +* Number of bytes that are used in the buffer. +*/ +unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex) { + unsigned RdOff; + unsigned WrOff; + unsigned r; + volatile SEGGER_RTT_CB* pRTTCB; + // + // Avoid warnings regarding volatile access order. It's not a problem + // in this case, but dampen compiler enthusiasm. + // + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRTTCB->aUp[BufferIndex].RdOff; + WrOff = pRTTCB->aUp[BufferIndex].WrOff; + if (RdOff <= WrOff) { + r = WrOff - RdOff; + } else { + r = pRTTCB->aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); + } + return r; +} + +/*************************** End of file ****************************/ diff --git a/blackbox/SEGGER_RTT.h b/blackbox/SEGGER_RTT.h new file mode 100644 index 0000000000..478b4ead99 --- /dev/null +++ b/blackbox/SEGGER_RTT.h @@ -0,0 +1,486 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* https://github.com/SEGGERMicro/RTT * +* * +********************************************************************** + +---------------------------END-OF-HEADER------------------------------ +Purpose : Implementation of SEGGER real-time transfer which allows + real-time communication on targets which support debugger + memory accesses while the CPU is running. + + SEGGER strongly recommends to not make any changes to or + modify the source code of this software in order to stay + compatible with the RTT protocol and J-Link. + +---------------------------------------------------------------------- +*/ + +#ifndef SEGGER_RTT_H +#define SEGGER_RTT_H + +#include "SEGGER_RTT_ConfDefaults.h" + +/********************************************************************* +* +* Defines, defaults +* +********************************************************************** +*/ + +#ifndef RTT_USE_ASM + // + // Some cores support out-of-order memory accesses (reordering of memory accesses in the core) + // For such cores, we need to define a memory barrier to guarantee the order of certain accesses to the RTT ring buffers. + // Needed for: + // Cortex-M7 (ARMv7-M) + // Cortex-M23 (ARM-v8M) + // Cortex-M33 (ARM-v8M) + // Cortex-A/R (ARM-v7A/R) + // + // We do not explicitly check for "Embedded Studio" as the compiler in use determines what we support. + // You can use an external toolchain like IAR inside ES. So there is no point in checking for "Embedded Studio" + // + #if (defined __CROSSWORKS_ARM) // Rowley Crossworks + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #if (defined __ARM_ARCH_7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined(__ARM_ARCH_8_1M_MAIN__)) // Cortex-M85 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #else + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + #elif (defined __ARMCC_VERSION) + // + // ARM compiler + // ARM compiler V6.0 and later is clang based. + // Our ASM part is compatible to clang. + // + #if (__ARMCC_VERSION >= 6000000) + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #else + #define _CC_HAS_RTT_ASM_SUPPORT 0 + #endif + #if (defined __ARM_ARCH_6M__) // Cortex-M0 / M1 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 // No ASM support for this architecture + #elif (defined __ARM_ARCH_7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif \ + ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) || \ + ((defined __ARM_ARCH_8A__) || (defined __ARM_ARCH_8R__)) + // + // Cortex-A/R ARMv7-A/R & ARMv8-A/R + // + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #else + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + #elif ((defined __GNUC__) || (defined __clang__)) + // + // GCC / Clang + // + #define _CC_HAS_RTT_ASM_SUPPORT 1 + // ARM 7/9: __ARM_ARCH_5__ / __ARM_ARCH_5E__ / __ARM_ARCH_5T__ / __ARM_ARCH_5T__ / __ARM_ARCH_5TE__ + #if (defined __ARM_ARCH_7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 // Only Cortex-M7 needs a DMB but we cannot distinguish M4 and M7 here... + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif \ + (defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__) || \ + (defined __ARM_ARCH_8A__) || (defined __ARM_ARCH_8R__) + // + // Cortex-A/R ARMv7-A/R & ARMv8-A/R + // + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #else + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + #elif ((defined __IASMARM__) || (defined __ICCARM__)) + // + // IAR assembler/compiler + // + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #if (__VER__ < 6300000) + #define VOLATILE + #else + #define VOLATILE volatile + #endif + #if (defined __ARM7M__) // Needed for old versions that do not know the define yet + #if (__CORE__ == __ARM7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #endif + #endif + #if (defined __ARM7EM__) + #if (__CORE__ == __ARM7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8M_BASELINE__) + #if (__CORE__ == __ARM8M_BASELINE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8M_MAINLINE__) + #if (__CORE__ == __ARM8M_MAINLINE__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8EM_MAINLINE__) + #if (__CORE__ == __ARM8EM_MAINLINE__) // Cortex-??? + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if\ + ((defined __ARM7A__) && (__CORE__ == __ARM7A__)) || \ + ((defined __ARM7R__) && (__CORE__ == __ARM7R__)) || \ + ((defined __ARM8A__) && (__CORE__ == __ARM8A__)) || \ + ((defined __ARM8R__) && (__CORE__ == __ARM8R__)) + // + // Cortex-A/R ARMv7-A/R & ARMv8-A/R + // + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #else + // + // Other compilers + // + #define _CC_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + // + // If IDE and core support the ASM version, enable ASM version by default + // + #ifndef _CORE_HAS_RTT_ASM_SUPPORT + #define _CORE_HAS_RTT_ASM_SUPPORT 0 // Default for unknown cores + #endif + #if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT) + #define RTT_USE_ASM (1) + #else + #define RTT_USE_ASM (0) + #endif +#endif + +#ifndef _CORE_NEEDS_DMB + #define _CORE_NEEDS_DMB 0 +#endif + +#ifndef RTT__DMB + #if _CORE_NEEDS_DMB + #error "Don't know how to place inline assembly for DMB" + #else + #define RTT__DMB() + #endif +#endif + +#ifndef SEGGER_RTT_CPU_CACHE_LINE_SIZE + #define SEGGER_RTT_CPU_CACHE_LINE_SIZE (0) // On most target systems where RTT is used, we do not have a CPU cache, therefore 0 is a good default here +#endif + +#ifndef SEGGER_RTT_UNCACHED_OFF + #if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #error "SEGGER_RTT_UNCACHED_OFF must be defined when setting SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #else + #define SEGGER_RTT_UNCACHED_OFF (0) + #endif +#endif +#if RTT_USE_ASM + #if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #error "RTT_USE_ASM is not available if SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif +#endif + +#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file +#include +#include +#include + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ + +// +// Determine how much we must pad the control block to make it a multiple of a cache line in size +// Assuming: U8 = 1B +// U16 = 2B +// U32 = 4B +// U8/U16/U32* = 4B +// +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE // Avoid division by zero in case we do not have any cache + #define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (((NumBytes + SEGGER_RTT_CPU_CACHE_LINE_SIZE - 1) / SEGGER_RTT_CPU_CACHE_LINE_SIZE) * SEGGER_RTT_CPU_CACHE_LINE_SIZE) +#else + #define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (NumBytes) +#endif +#define SEGGER_RTT__CB_SIZE (16 + 4 + 4 + (SEGGER_RTT_MAX_NUM_UP_BUFFERS * 24) + (SEGGER_RTT_MAX_NUM_DOWN_BUFFERS * 24)) +#define SEGGER_RTT__CB_PADDING (SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(SEGGER_RTT__CB_SIZE) - SEGGER_RTT__CB_SIZE) + +/********************************************************************* +* +* Types +* +********************************************************************** +*/ + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as up-buffer (T->H) +// +typedef struct { + const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. + unsigned WrOff; // Position of next item to be written by either target. + volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host. + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +} SEGGER_RTT_BUFFER_UP; + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as down-buffer (H->T) +// +typedef struct { + const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. + volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host. + unsigned RdOff; // Position of next item to be read by target (down-buffer). + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +} SEGGER_RTT_BUFFER_DOWN; + +// +// RTT control block which describes the number of buffers available +// as well as the configuration for each buffer +// +// +typedef struct { + char acID[16]; // Initialized to "SEGGER RTT" + int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2) + int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2) + SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host + SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target +#if SEGGER_RTT__CB_PADDING + unsigned char aDummy[SEGGER_RTT__CB_PADDING]; +#endif +} SEGGER_RTT_CB; + +/********************************************************************* +* +* Global data +* +********************************************************************** +*/ +extern SEGGER_RTT_CB _SEGGER_RTT; + +/********************************************************************* +* +* RTT API functions +* +********************************************************************** +*/ +#ifdef __cplusplus + extern "C" { +#endif +int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_GetKey (void); +unsigned SEGGER_RTT_HasData (unsigned BufferIndex); +int SEGGER_RTT_HasKey (void); +unsigned SEGGER_RTT_HasDataUp (unsigned BufferIndex); +void SEGGER_RTT_Init (void); +unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize); +unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize); +int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName); +int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName); +int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags); +int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags); +int SEGGER_RTT_WaitKey (void); +unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_ASM_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s); +void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_PutChar (unsigned BufferIndex, char c); +unsigned SEGGER_RTT_PutCharSkip (unsigned BufferIndex, char c); +unsigned SEGGER_RTT_PutCharSkipNoLock (unsigned BufferIndex, char c); +unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex); +unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex); +// +// Function macro for performance optimization +// +#define SEGGER_RTT_HASDATA(n) (((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) + +#if RTT_USE_ASM + #define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock +#endif + +/********************************************************************* +* +* RTT transfer functions to send RTT data via other channels. +* +********************************************************************** +*/ +unsigned SEGGER_RTT_ReadUpBuffer (unsigned BufferIndex, void* pBuffer, unsigned BufferSize); +unsigned SEGGER_RTT_ReadUpBufferNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize); +unsigned SEGGER_RTT_WriteDownBuffer (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteDownBufferNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); + +#define SEGGER_RTT_HASDATA_UP(n) (((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + +/********************************************************************* +* +* RTT "Terminal" API functions +* +********************************************************************** +*/ +int SEGGER_RTT_SetTerminal (unsigned char TerminalId); +int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s); + +/********************************************************************* +* +* RTT printf functions (require SEGGER_RTT_printf.c) +* +********************************************************************** +*/ +int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...); +int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList); + +#ifdef __cplusplus + } +#endif + +#endif // ifndef(SEGGER_RTT_ASM) + +// +// For some environments, NULL may not be defined until certain headers are included +// +#ifndef NULL + #define NULL ((void*)0) +#endif + +/********************************************************************* +* +* Defines +* +********************************************************************** +*/ + +// +// Operating modes. Define behavior if buffer is full (not enough space for entire message) +// +#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default) +#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits. +#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer. +#define SEGGER_RTT_MODE_MASK (3) + +// +// Control sequences, based on ANSI. +// Can be used to control color, and clear the screen +// +#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors +#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left + +#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m" +#define RTT_CTRL_TEXT_RED "\x1B[2;31m" +#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m" +#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m" +#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m" +#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m" +#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m" +#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m" + +#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m" +#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m" +#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m" +#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m" +#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m" +#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m" +#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m" +#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m" + +#define RTT_CTRL_BG_BLACK "\x1B[24;40m" +#define RTT_CTRL_BG_RED "\x1B[24;41m" +#define RTT_CTRL_BG_GREEN "\x1B[24;42m" +#define RTT_CTRL_BG_YELLOW "\x1B[24;43m" +#define RTT_CTRL_BG_BLUE "\x1B[24;44m" +#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m" +#define RTT_CTRL_BG_CYAN "\x1B[24;46m" +#define RTT_CTRL_BG_WHITE "\x1B[24;47m" + +#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m" +#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m" +#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m" +#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m" +#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m" +#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m" +#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m" +#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m" + + +#endif + +/*************************** End of file ****************************/ diff --git a/blackbox/SEGGER_RTT_Conf.h b/blackbox/SEGGER_RTT_Conf.h new file mode 100644 index 0000000000..03f038361e --- /dev/null +++ b/blackbox/SEGGER_RTT_Conf.h @@ -0,0 +1,40 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* https://github.com/SEGGERMicro/RTT * +* * +********************************************************************** + +---------------------------END-OF-HEADER------------------------------ +Purpose : User configuration file for RTT. + For available configuration, + refer to SEGGER_RTT_ConfDefaults.h. + +---------------------------------------------------------------------- +*/ + +#ifndef SEGGER_RTT_CONF_H +#define SEGGER_RTT_CONF_H + + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ + +// VESC blackbox: minimal RTT setup. One up buffer (target -> host), +// non-blocking so the FOC ISR / threads are never stalled by a slow host. +#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (1) +#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (1) +#define BUFFER_SIZE_UP (3072) +#define BUFFER_SIZE_DOWN (16) +#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP + +#endif +/*************************** End of file ****************************/ diff --git a/blackbox/SEGGER_RTT_ConfDefaults.h b/blackbox/SEGGER_RTT_ConfDefaults.h new file mode 100644 index 0000000000..29b1c467a1 --- /dev/null +++ b/blackbox/SEGGER_RTT_ConfDefaults.h @@ -0,0 +1,476 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* https://github.com/SEGGERMicro/RTT * +* * +********************************************************************** + +---------------------------END-OF-HEADER------------------------------ +Purpose : Default configuration for RTT. + Do not change this file! Use SEGGER_RTT_Conf.h instead. +---------------------------------------------------------------------- +*/ + +#ifndef SEGGER_RTT_CONF_DEFAULTS_H +#define SEGGER_RTT_CONF_DEFAULTS_H + +#include "SEGGER_RTT_Conf.h" + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ + +// +// Take in and set to correct values for Cortex-A systems with CPU cache +// +//#define SEGGER_RTT_CPU_CACHE_LINE_SIZE (32) // Largest cache line size (in bytes) in the current system +//#define SEGGER_RTT_UNCACHED_OFF (0xFB000000) // Address alias where RTT CB and buffers can be accessed uncached +// +/********************************************************************* +* +* SEGGER_RTT_MAX_NUM_UP_BUFFERS +* +* Description +* Maximum number of RTT up-buffers (Target -> Host). +* +* Additional information +* Common use case: +* Up-buffer channel 0: RTT Terminal I/O. +* Up-buffer channel 1: SystemView. +*/ +#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS + #define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) +#endif +/********************************************************************* +* +* SEGGER_RTT_MAX_NUM_DOWN_BUFFERS +* +* Description +* Maximum number of RTT down-buffers (Host -> Target). +* +* Additional information +* Common use case: +* Down-buffer channel 0: RTT Terminal I/O. +* Down-buffer channel 1: SystemView. +* +* The number of up- and down-buffers may differ. +*/ +#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS + #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) +#endif + +/********************************************************************* +* +* BUFFER_SIZE_UP +* +* Description +* Size of (auto-installed) up-buffer channel 0. +* +* Additional information +* Channel 0 is commonly used for Terminal I/O. +* Buffer should be large enough for all terminal (to host) output +* messages. +*/ +#ifndef BUFFER_SIZE_UP + #define BUFFER_SIZE_UP (1024) +#endif + +/********************************************************************* +* +* BUFFER_SIZE_DOWN +* +* Description +* Size of (auto-installed) down-buffer channel 0. +* +* Additional information +* Channel 0 is commonly used for Terminal I/O. +* Buffer should be large enough to receive all terminal +* (from host) input. +*/ +#ifndef BUFFER_SIZE_DOWN + #define BUFFER_SIZE_DOWN (16) +#endif + +/********************************************************************* +* +* SEGGER_RTT_MODE_DEFAULT +* +* Description +* RTT Mode for channel 0. +*/ +#ifndef SEGGER_RTT_MODE_DEFAULT + #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP +#endif + +/********************************************************************* +* +* SEGGER_RTT_PRINTF_BUFFER_SIZE +* +* Description +* Size of temporary buffer for RTT printf bulk-send. +*/ +#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE + #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) +#endif + +/********************************************************************* +* +* RTT memcpy configuration +* +* memcpy() is good for large amounts of data, +* but the overhead is big for small amounts, which are usually stored via RTT. +* With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead. +* +* SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions. +* This is may be required with memory access restrictions, +* such as on Cortex-A devices with MMU. +*/ +#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP + #define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop +#endif +// +// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets +// +//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__)) +// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes)) +//#endif + +// +// Target is not allowed to perform other RTT operations while string still has not been stored completely. +// Otherwise we would probably end up with a mixed string in the buffer. +// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here. +// +// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4. +// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches. +// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly. +// (Higher priority = lower priority number) +// Default value for embOS: 128u +// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC +// or define SEGGER_RTT_LOCK() to completely disable interrupts. +// +#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20) +#endif + +/********************************************************************* +* +* RTT lock configuration for SEGGER Embedded Studio, +* Rowley CrossStudio and GCC +*/ +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32)) + #if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs %0, primask \n\t" \ + "movs r1, #1 \n\t" \ + "msr primask, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : \ + ); \ + } + #elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs %0, basepri \n\t" \ + "mov r1, %1 \n\t" \ + "msr basepri, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : \ + ); \ + } + + #elif (defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc" \ + ); \ + } + #elif defined(__riscv) || defined(__riscv_xlen) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("csrr %0, mstatus \n\t" \ + "csrci mstatus, 8 \n\t" \ + "andi %0, %0, 8 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("csrr a1, mstatus \n\t" \ + "or %0, %0, a1 \n\t" \ + "csrs mstatus, %0 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : "a1" \ + ); \ + } + #endif + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR EWARM +*/ +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #ifdef __ICCARM__ + #ifdef __IAR_SYSTEMS_ICC__ + #include + #endif + #if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) || \ + (defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ + __set_PRIMASK(1); + + #define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \ + } + #elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \ + (defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || \ + (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) || \ + (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_BASEPRI(); \ + __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + + #define SEGGER_RTT_UNLOCK() __set_BASEPRI(_SEGGER_RTT__LockState); \ + } + #elif (defined (__ARM7A__) && (__CORE__ == __ARM7A__)) || \ + (defined (__ARM7R__) && (__CORE__ == __ARM7R__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc" \ + ); \ + } + #endif + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR RX +*/ +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #ifdef __ICCRX__ + #ifdef __IAR_SYSTEMS_ICC__ + #include + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ + __disable_interrupt(); + + #define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR RL78 +*/ +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #ifdef __ICCRL78__ + #ifdef __IAR_SYSTEMS_ICC__ + #include + #endif + #define SEGGER_RTT_LOCK() { \ + __istate_t _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ + __disable_interrupt(); + + #define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for KEIL ARM +*/ +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #ifdef __CC_ARM + #if (defined __TARGET_ARCH_6S_M) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + register unsigned char _SEGGER_RTT__PRIMASK __asm( "primask"); \ + _SEGGER_RTT__LockState = _SEGGER_RTT__PRIMASK; \ + _SEGGER_RTT__PRIMASK = 1u; \ + __schedule_barrier(); + + #define SEGGER_RTT_UNLOCK() _SEGGER_RTT__PRIMASK = _SEGGER_RTT__LockState; \ + __schedule_barrier(); \ + } + #elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + register unsigned char BASEPRI __asm( "basepri"); \ + _SEGGER_RTT__LockState = BASEPRI; \ + BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \ + __schedule_barrier(); + + #define SEGGER_RTT_UNLOCK() BASEPRI = _SEGGER_RTT__LockState; \ + __schedule_barrier(); \ + } + #endif + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for TI ARM +*/ +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #ifdef __TI_ARM__ + #if defined (__TI_ARM_V6M0__) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ + __set_PRIMASK(1); + + #define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \ + } + #elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + + #define SEGGER_RTT_UNLOCK() _set_interrupt_priority(_SEGGER_RTT__LockState); \ + } + #endif + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for CCRX +*/ +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #ifdef __RX + #include + #define SEGGER_RTT_LOCK() { \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = get_psw() & 0x010000; \ + clrpsw_i(); + + #define SEGGER_RTT_UNLOCK() set_psw(get_psw() | _SEGGER_RTT__LockState); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for embOS Simulation on Windows +* (Can also be used for generic RTT locking with embOS) +*/ + +#if !defined(SEGGER_RTT_LOCK) || !defined (SEGGER_RTT_UNLOCK) + #if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS) + + void OS_SIM_EnterCriticalSection(void); + void OS_SIM_LeaveCriticalSection(void); + + #define SEGGER_RTT_LOCK() { \ + OS_SIM_EnterCriticalSection(); + + #define SEGGER_RTT_UNLOCK() OS_SIM_LeaveCriticalSection(); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration fallback +*/ +#ifndef SEGGER_RTT_LOCK + #define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts) +#endif + +#ifndef SEGGER_RTT_UNLOCK + #define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state) +#endif + +/********************************************************************* +* +* If SEGGER_RTT_SECTION is defined but SEGGER_RTT_BUFFER_SECTION +* is not, use the same section for SEGGER_RTT_BUFFER_SECTION. +*/ +#ifndef SEGGER_RTT_BUFFER_SECTION + #if defined(SEGGER_RTT_SECTION) + #define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION + #endif +#endif + +#endif +/*************************** End of file ****************************/ diff --git a/blackbox/SEGGER_RTT_printf.c b/blackbox/SEGGER_RTT_printf.c new file mode 100644 index 0000000000..9f7ceeaefa --- /dev/null +++ b/blackbox/SEGGER_RTT_printf.c @@ -0,0 +1,483 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* https://github.com/SEGGERMicro/RTT * +* * +********************************************************************** + +---------------------------END-OF-HEADER------------------------------ +Purpose : Replacement for printf to write formatted data via RTT + +---------------------------------------------------------------------- +*/ +#include "SEGGER_RTT.h" + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ + +#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE + #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) +#endif + +#include +#include + + +#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0) +#define FORMAT_FLAG_PAD_ZERO (1u << 1) +#define FORMAT_FLAG_PRINT_SIGN (1u << 2) +#define FORMAT_FLAG_ALTERNATE (1u << 3) + +/********************************************************************* +* +* Types +* +********************************************************************** +*/ + +typedef struct { + char* pBuffer; + unsigned BufferSize; + unsigned Cnt; + + int ReturnValue; + + unsigned RTTBufferIndex; +} SEGGER_RTT_PRINTF_DESC; + +/********************************************************************* +* +* Function prototypes +* +********************************************************************** +*/ + +/********************************************************************* +* +* Static code +* +********************************************************************** +*/ +/********************************************************************* +* +* _StoreChar +*/ +static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) { + unsigned Cnt; + + Cnt = p->Cnt; + if ((Cnt + 1u) <= p->BufferSize) { + *(p->pBuffer + Cnt) = c; + p->Cnt = Cnt + 1u; + p->ReturnValue++; + } + // + // Write part of string, when the buffer is full + // + if (p->Cnt == p->BufferSize) { + if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) { + p->ReturnValue = -1; + } else { + p->Cnt = 0u; + } + } +} + +/********************************************************************* +* +* _PrintUnsigned +*/ +static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { + static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + unsigned Div; + unsigned Digit; + unsigned Number; + unsigned Width; + char c; + + Number = v; + Digit = 1u; + // + // Get actual field width + // + Width = 1u; + while (Number >= Base) { + Number = (Number / Base); + Width++; + } + if (NumDigits > Width) { + Width = NumDigits; + } + // + // Print leading chars if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) { + if (FieldWidth != 0u) { + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) { + c = '0'; + } else { + c = ' '; + } + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, c); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + if (pBufferDesc->ReturnValue >= 0) { + // + // Compute Digit. + // Loop until Digit has the value of the highest digit required. + // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100. + // + while (1) { + if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned) + NumDigits--; + } else { + Div = v / Digit; + if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done + break; + } + } + Digit *= Base; + } + // + // Output digits + // + do { + Div = v / Digit; + v -= Div * Digit; + _StoreChar(pBufferDesc, _aV2C[Div]); + if (pBufferDesc->ReturnValue < 0) { + break; + } + Digit /= Base; + } while (Digit); + // + // Print trailing spaces if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + } +} + +/********************************************************************* +* +* _PrintInt +*/ +static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { + unsigned Width; + int Number; + + Number = (v < 0) ? -v : v; + + // + // Get actual field width + // + Width = 1u; + while (Number >= (int)Base) { + Number = (Number / (int)Base); + Width++; + } + if (NumDigits > Width) { + Width = NumDigits; + } + if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) { + FieldWidth--; + } + + // + // Print leading spaces if necessary + // + if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + // + // Print sign if necessary + // + if (pBufferDesc->ReturnValue >= 0) { + if (v < 0) { + v = -v; + _StoreChar(pBufferDesc, '-'); + } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) { + _StoreChar(pBufferDesc, '+'); + } else { + + } + if (pBufferDesc->ReturnValue >= 0) { + // + // Print leading zeros if necessary + // + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, '0'); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + if (pBufferDesc->ReturnValue >= 0) { + // + // Print number without sign + // + _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags); + } + } + } +} + +/********************************************************************* +* +* Public code +* +********************************************************************** +*/ +/********************************************************************* +* +* SEGGER_RTT_vprintf +* +* Function description +* Stores a formatted string in SEGGER RTT control block. +* This data is read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") +* sFormat Pointer to format string +* pParamList Pointer to the list of arguments for the format string +* +* Return values +* >= 0: Number of bytes which have been stored in the "Up"-buffer. +* < 0: Error +*/ +int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) { + char c; + SEGGER_RTT_PRINTF_DESC BufferDesc; + int v; + unsigned char PrecisionSet; + unsigned Precision; + unsigned FormatFlags; + unsigned FieldWidth; + char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE]; + + BufferDesc.pBuffer = acBuffer; + BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE; + BufferDesc.Cnt = 0u; + BufferDesc.RTTBufferIndex = BufferIndex; + BufferDesc.ReturnValue = 0; + + do { + c = *sFormat; + sFormat++; + if (c == 0u) { + break; + } + if (c == '%') { + // + // Filter out flags + // + FormatFlags = 0u; + v = 1; + do { + c = *sFormat; + switch (c) { + case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break; + case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break; + case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break; + case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break; + default: v = 0; break; + } + } while (v); + // + // filter out field with + // + FieldWidth = 0u; + do { + c = *sFormat; + if ((c < '0') || (c > '9')) { + break; + } + sFormat++; + FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0'); + } while (1); + + // + // Filter out precision (number of digits to display) + // + PrecisionSet = 0; + Precision = 0u; + c = *sFormat; + if (c == '.') { + sFormat++; + if (*sFormat == '*') { + sFormat++; + PrecisionSet = 1; + Precision = va_arg(*pParamList, int); + } else { + do { + c = *sFormat; + if ((c < '0') || (c > '9')) { + break; + } + PrecisionSet = 1; + sFormat++; + Precision = Precision * 10u + ((unsigned)c - '0'); + } while (1); + } + } + // + // Filter out length modifier + // + c = *sFormat; + do { + if ((c == 'l') || (c == 'h')) { + sFormat++; + c = *sFormat; + } else { + break; + } + } while (1); + // + // Handle specifiers + // + switch (c) { + case 'c': { + char c0; + v = va_arg(*pParamList, int); + c0 = (char)v; + _StoreChar(&BufferDesc, c0); + break; + } + case 'd': + v = va_arg(*pParamList, int); + _PrintInt(&BufferDesc, v, 10u, Precision, FieldWidth, FormatFlags); + break; + case 'u': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, Precision, FieldWidth, FormatFlags); + break; + case 'x': + case 'X': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, Precision, FieldWidth, FormatFlags); + break; + case 's': + { + const char * s = va_arg(*pParamList, const char *); + if (s == NULL) { + s = "(NULL)"; // Print (NULL) instead of crashing or breaking, as it is more informative to the user. + PrecisionSet = 0; // Make sure (NULL) is printed, even when precision was set. + } + do { + c = *s; + s++; + if (c == '\0') { + break; + } + if ((PrecisionSet != 0) && (Precision == 0)) { + break; + } + _StoreChar(&BufferDesc, c); + Precision--; + } while (BufferDesc.ReturnValue >= 0); + } + break; + case 'p': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u); + break; + case '%': + _StoreChar(&BufferDesc, '%'); + break; + default: + break; + } + sFormat++; + } else { + _StoreChar(&BufferDesc, c); + } + } while (BufferDesc.ReturnValue >= 0); + + if (BufferDesc.ReturnValue > 0) { + // + // Write remaining data, if any + // + if (BufferDesc.Cnt != 0u) { + SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt); + } + BufferDesc.ReturnValue += (int)BufferDesc.Cnt; + } + return BufferDesc.ReturnValue; +} + +/********************************************************************* +* +* SEGGER_RTT_printf +* +* Function description +* Stores a formatted string in SEGGER RTT control block. +* This data is read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") +* sFormat Pointer to format string, followed by the arguments for conversion +* +* Return values +* >= 0: Number of bytes which have been stored in the "Up"-buffer. +* < 0: Error +* +* Notes +* (1) Conversion specifications have following syntax: +* %[flags][FieldWidth][.Precision]ConversionSpecifier +* (2) Supported flags: +* -: Left justify within the field width +* +: Always print sign extension for signed conversions +* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision +* Supported conversion specifiers: +* c: Print the argument as one char +* d: Print the argument as a signed integer +* u: Print the argument as an unsigned integer +* x: Print the argument as an hexadecimal integer +* s: Print the string pointed to by the argument +* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.) +*/ +int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) { + int r; + va_list ParamList; + + va_start(ParamList, sFormat); + r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList); + va_end(ParamList); + return r; +} +/*************************** End of file ****************************/ diff --git a/blackbox/blackbox.c b/blackbox/blackbox.c new file mode 100644 index 0000000000..b34f049cc3 --- /dev/null +++ b/blackbox/blackbox.c @@ -0,0 +1,453 @@ +/* + * blackbox.c + * + * See blackbox.h for the design notes. + */ + +#include "blackbox.h" +#include "SEGGER_RTT.h" +#include "conf_general.h" +#include "mcpwm_foc.h" +#include "mc_interface.h" +#include "ch.h" + +#include +#include +#include + +#ifndef BB_STREAM_DECIMATION +#define BB_STREAM_DECIMATION 1 +#endif + +#ifndef BB_STREAM_BATCH +#define BB_STREAM_BATCH 32 +#endif + +#ifndef BB_STREAM_MAX_PACKETS_PER_LOOP +#define BB_STREAM_MAX_PACKETS_PER_LOOP 8 +#endif + +#define BB_STREAM_MAGIC "BBIN" +#define BB_STREAM_VERSION 11 + +// Compact binary stream fixed-point scales. Currents are int16 at +// 0.02 A/LSB (+-655 A range). Duty is int16 at 0.0001/LSB. Electrical +// phase is int16 mapping a full turn (0..2*pi) onto the int16 range. +#define BB_STREAM_I_LSB_PER_A 50.0f +#define BB_STREAM_DUTY_LSB 10000.0f +#define BB_STREAM_ANG_LSB (32768.0f / (2.0f * (float)M_PI)) +#define BB_STREAM_I16_MAX 32767.0f +#define BB_STREAM_I16_MIN (-32768.0f) + +// 14 bytes per record (no padding): 7 x int16. The per-record tick is not +// transmitted; the host reconstructs it as header.first_tick + record_index. +// This assumes BB_STREAM_DECIMATION == 1 so records in a batch are consecutive. +typedef struct __attribute__((packed)) { + int16_t ia; // Phase currents: int16, BB_STREAM_I_LSB_PER_A LSB per amp + int16_t ib; + int16_t ic; + int16_t id; // dq currents: int16, BB_STREAM_I_LSB_PER_A LSB per amp + int16_t iq; + int16_t theta; // Electrical phase used by FOC: int16, BB_STREAM_ANG_LSB LSB per rad + int16_t duty_now; // Duty cycle: int16, BB_STREAM_DUTY_LSB LSB per duty +} bb_stream_record_t; + +static inline int16_t bb_stream_clamp_i16(float v) { + if (v > BB_STREAM_I16_MAX) { + v = BB_STREAM_I16_MAX; + } else if (v < BB_STREAM_I16_MIN) { + v = BB_STREAM_I16_MIN; + } + return (int16_t)v; +} + +typedef struct __attribute__((packed)) { + char magic[4]; + uint8_t version; + uint8_t record_size; + uint16_t count; + uint32_t first_tick; // ISR tick of the first record in this batch + uint32_t checksum; +} bb_stream_header_t; + +// Ring buffer in main SRAM (.bss). Intentionally NOT in CCM (.ram4): CCM is +// nearly full (ADC sample buffers + LispBM) and the J-Link RTT/memory tools +// work best on the 0x20000000 region. +static volatile bb_record_t m_buf[BB_BUF_LEN]; + +static volatile uint32_t m_head = 0; // Next write index +static volatile uint32_t m_count = 0; // Total committed records since clear +static volatile uint32_t m_isr_tick = 0; // Counts every ISR call, incl. skipped +static volatile bool m_triggered = false; // Fault notified, post-trigger running +static volatile bool m_frozen = false; // Writing stopped +static volatile uint32_t m_post_remaining = 0; // Records left to write after trigger +static volatile uint8_t m_fault_code = 0; +static volatile bool m_dump_request = false; + +// Freeze-on-fault is disabled by default for now (RTT bring-up phase); +// toggle with 'f' on the RTT down channel. +static volatile bool m_freeze_enabled = false; +// Periodic live telemetry over RTT, toggle with 'l'. +static volatile bool m_live_print = false; +// Binary live stream over RTT. The host parser ignores other text. +static volatile bool m_stream_enabled = false; +static volatile uint32_t m_stream_next_count = 0; +static uint8_t m_stream_packet[sizeof(bb_stream_header_t) + BB_STREAM_BATCH * sizeof(bb_stream_record_t)]; + +static THD_WORKING_AREA(dump_thread_wa, 2048); +static THD_FUNCTION(dump_thread, arg); + +void blackbox_init(void) { + SEGGER_RTT_Init(); + SEGGER_RTT_printf(0, "VESC FW %d.%02d blackbox up. Build " __DATE__ " " __TIME__ "\r\n", + FW_VERSION_MAJOR, FW_VERSION_MINOR); + SEGGER_RTT_printf(0, "BB buf: %d rec x %d B, decimation %d, post-trigger %d\r\n", + BB_BUF_LEN, sizeof(bb_record_t), BB_DECIMATION, BB_POST_TRIGGER); + + chThdCreateStatic(dump_thread_wa, sizeof(dump_thread_wa), LOWPRIO, dump_thread, NULL); +} + +void blackbox_request_dump(void) { + m_dump_request = true; +} + +// Wait (in thread context) until the RTT up buffer has room for len bytes, +// then write. Gives up after ~2 s so a missing host reader never wedges us. +static bool rtt_write_chunk(const char *buf, unsigned int len) { + int timeout_ms = 2000; + while (SEGGER_RTT_GetAvailWriteSpace(0) < len) { + if (timeout_ms-- <= 0) { + return false; + } + chThdSleepMilliseconds(1); + } + SEGGER_RTT_Write(0, buf, len); + return true; +} + +static void dump_csv(void) { + char line[224]; + int len; + + // Snapshot the indices. For a torn-free dump trigger it on a frozen + // buffer; a live dump may contain a few records overwritten mid-read. + uint32_t count = m_count; + uint32_t head = m_head; + uint32_t n = (count < BB_BUF_LEN) ? count : BB_BUF_LEN; + + len = snprintf(line, sizeof(line), + "#BB_DUMP_BEGIN,ver=1,f_isr_hz=%.1f,decimation=%d,buflen=%d,records=%lu,frozen=%d,fault=%d\r\n", + (double)mcpwm_foc_get_sampling_frequency_now(), BB_DECIMATION, BB_BUF_LEN, + (unsigned long)n, m_frozen ? 1 : 0, m_fault_code); + if (!rtt_write_chunk(line, len)) { + return; + } + + len = snprintf(line, sizeof(line), + "tick,ia,ib,ic,id,iq,i_abs,i_abs_filter,duty,v_bus,phase,speed_rad_s,fault,state,mode,flags\r\n"); + if (!rtt_write_chunk(line, len)) { + return; + } + + for (uint32_t i = 0; i < n; i++) { + uint32_t idx = (head + BB_BUF_LEN - n + i) % BB_BUF_LEN; + volatile bb_record_t *r = &m_buf[idx]; + + len = snprintf(line, sizeof(line), + "%lu,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.4f,%.2f,%.4f,%.2f,%u,%u,%u,%u\r\n", + (unsigned long)r->tick, + (double)r->ia, (double)r->ib, (double)r->ic, + (double)r->id, (double)r->iq, + (double)r->i_abs, (double)r->i_abs_filter, + (double)r->duty_now, (double)r->v_bus, + (double)r->phase, (double)r->speed_rad_s, + (unsigned int)r->fault_code, (unsigned int)r->state, + (unsigned int)r->control_mode, (unsigned int)r->flags); + if (!rtt_write_chunk(line, len)) { + return; + } + } + + len = snprintf(line, sizeof(line), "#BB_DUMP_END\r\n"); + rtt_write_chunk(line, len); +} + +// Periodic live telemetry line. Written in skip mode: if the RTT buffer is +// full (no host attached) the line is simply dropped, nothing blocks. +static void live_print(void) { + char line[224]; + + int len = snprintf(line, sizeof(line), + "BB t=%lu iq=%.2f id=%.2f iabs=%.2f duty=%.3f vbus=%.1f erpm=%.0f " + "ang_used=%.1f ang_obs=%.1f ang_enc=%.1f ang_hall=%.1f fault=%d\r\n", + (unsigned long)m_isr_tick, + (double)mcpwm_foc_get_iq(), (double)mcpwm_foc_get_id(), + (double)mcpwm_foc_get_abs_motor_current(), + (double)mcpwm_foc_get_duty_cycle_now(), + (double)mc_interface_get_input_voltage_filtered(), + (double)mcpwm_foc_get_rpm(), + (double)mcpwm_foc_get_phase(), // angle actually used by FOC (deg) + (double)mcpwm_foc_get_phase_observer(), // observer angle (deg) + (double)mcpwm_foc_get_phase_encoder(), // encoder angle (deg) + (double)mcpwm_foc_get_phase_hall(), // hall angle (deg) + (int)mc_interface_get_fault()); + + if (len > 0) { + SEGGER_RTT_Write(0, line, (unsigned int)len); + } +} + +static uint32_t stream_checksum(const uint8_t *data, uint32_t len) { + uint32_t sum = 0x9E3779B9; + for (uint32_t i = 0; i < len; i++) { + sum = (sum << 5) | (sum >> 27); + sum ^= data[i]; + sum += 0x7F4A7C15; + } + return sum; +} + +static void stream_binary(void) { + uint32_t available = m_count; + + if (m_stream_next_count == 0 || m_stream_next_count > (available + 1)) { + m_stream_next_count = available + 1; + return; + } + + uint32_t min_count = 1; + if (available > BB_BUF_LEN) { + min_count = available - BB_BUF_LEN + 1; + } + + if (m_stream_next_count < min_count) { + m_stream_next_count = min_count; + } + + if (m_stream_next_count > available) { + return; + } + + uint16_t rec_count = 0; + uint32_t next = m_stream_next_count; + + uint32_t scan = next; + while (scan <= available && rec_count < BB_STREAM_BATCH) { + uint32_t idx = (scan - 1) % BB_BUF_LEN; + volatile bb_record_t *r = &m_buf[idx]; + + if ((r->tick % BB_STREAM_DECIMATION) == 0) { + rec_count++; + } + + scan++; + } + + if (rec_count == 0) { + m_stream_next_count = scan; + return; + } + + uint32_t payload_len = rec_count * sizeof(bb_stream_record_t); + uint32_t packet_len = sizeof(bb_stream_header_t) + payload_len; + if (SEGGER_RTT_GetAvailWriteSpace(0) < packet_len) { + // Keep the control thread non-blocking. Retry from the same record next loop. + return; + } + + bb_stream_header_t *header = (bb_stream_header_t*)m_stream_packet; + memcpy(header->magic, BB_STREAM_MAGIC, 4); + header->version = BB_STREAM_VERSION; + header->record_size = (uint8_t)sizeof(bb_stream_record_t); + header->count = rec_count; + header->first_tick = 0; + + uint8_t *payload = &m_stream_packet[sizeof(bb_stream_header_t)]; + uint32_t payload_ofs = 0; + while (next < scan) { + uint32_t idx = (next - 1) % BB_BUF_LEN; + volatile bb_record_t *r = &m_buf[idx]; + + if ((r->tick % BB_STREAM_DECIMATION) == 0) { + if (payload_ofs == 0) { + header->first_tick = r->tick; + } + bb_stream_record_t *out = (bb_stream_record_t*)&payload[payload_ofs]; + out->ia = bb_stream_clamp_i16(r->ia * BB_STREAM_I_LSB_PER_A); + out->ib = bb_stream_clamp_i16(r->ib * BB_STREAM_I_LSB_PER_A); + out->ic = bb_stream_clamp_i16(r->ic * BB_STREAM_I_LSB_PER_A); + out->id = bb_stream_clamp_i16(r->id * BB_STREAM_I_LSB_PER_A); + out->iq = bb_stream_clamp_i16(r->iq * BB_STREAM_I_LSB_PER_A); + out->theta = bb_stream_clamp_i16(r->phase * BB_STREAM_ANG_LSB); + out->duty_now = bb_stream_clamp_i16(r->duty_now * BB_STREAM_DUTY_LSB); + payload_ofs += sizeof(bb_stream_record_t); + } + + next++; + } + + m_stream_next_count = next; + header->checksum = stream_checksum(payload, payload_len); + SEGGER_RTT_Write(0, m_stream_packet, packet_len); +} + +static THD_FUNCTION(dump_thread, arg) { + (void)arg; + chRegSetThreadName("blackbox dump"); + + int live_div = 0; + + for (;;) { + // Host-side control over the RTT down channel: + // 'd' = dump, 'c' = clear, 'l' = toggle live print, 's' = start binary stream, + // 'x' = stop binary stream, + // 'f' = toggle freeze-on-fault. + char cmd; + while (SEGGER_RTT_Read(0, &cmd, 1) > 0) { + if (cmd == 'd' || cmd == 'D') { + m_dump_request = true; + } else if (cmd == 'c' || cmd == 'C') { + blackbox_clear(); + SEGGER_RTT_WriteString(0, "#BB_CLEARED\r\n"); + } else if (cmd == 'l' || cmd == 'L') { + m_live_print = !m_live_print; + SEGGER_RTT_WriteString(0, m_live_print ? "#BB_LIVE_ON\r\n" : "#BB_LIVE_OFF\r\n"); + } else if (cmd == 's' || cmd == 'S') { + m_stream_enabled = true; + m_stream_next_count = m_count + 1; + SEGGER_RTT_WriteString(0, "#BB_STREAM_ON\r\n"); + } else if (cmd == 'x' || cmd == 'X') { + m_stream_enabled = false; + SEGGER_RTT_WriteString(0, "#BB_STREAM_OFF\r\n"); + } else if (cmd == 'f' || cmd == 'F') { + m_freeze_enabled = !m_freeze_enabled; + SEGGER_RTT_WriteString(0, m_freeze_enabled ? "#BB_FREEZE_ON\r\n" : "#BB_FREEZE_OFF\r\n"); + } + } + + if (m_dump_request) { + m_dump_request = false; + dump_csv(); + } + + if (m_stream_enabled) { + for (int i = 0; i < BB_STREAM_MAX_PACKETS_PER_LOOP; i++) { + uint32_t before = m_stream_next_count; + stream_binary(); + if (m_stream_next_count == before) { + break; + } + } + } + + // 10 ms loop, live line every 20th iteration = 5 Hz. + if (m_live_print && ++live_div >= 20) { + live_div = 0; + live_print(); + } + + chThdSleepMilliseconds(1); + } +} + +volatile bb_record_t *blackbox_next_record_isr(void) { + uint32_t tick = m_isr_tick; + m_isr_tick = tick + 1; + + if (m_frozen) { + return 0; + } + +#if BB_DECIMATION > 1 + if ((tick % BB_DECIMATION) != 0) { + return 0; + } +#endif + + volatile bb_record_t *rec = &m_buf[m_head]; + rec->tick = tick; + rec->fault_code = m_fault_code; + rec->flags = m_triggered ? BB_FLAG_FAULT_ACTIVE : 0; + return rec; +} + +void blackbox_commit_isr(void) { + uint32_t head = m_head + 1; + if (head >= BB_BUF_LEN) { + head = 0; + } + m_head = head; + m_count++; + + if (m_triggered) { + if (m_post_remaining > 0) { + m_post_remaining--; + } + if (m_post_remaining == 0) { + m_frozen = true; + } + } +} + +void blackbox_notify_fault(uint8_t fault_code) { + if (m_triggered || m_frozen) { + return; + } + m_fault_code = fault_code; + + if (m_freeze_enabled) { + m_post_remaining = BB_POST_TRIGGER; + m_triggered = true; + } +} + +void blackbox_set_freeze_enabled(bool enabled) { + m_freeze_enabled = enabled; +} + +bool blackbox_freeze_enabled(void) { + return m_freeze_enabled; +} + +void blackbox_clear(void) { + // Freeze first so the ISR writer stays out while we reset. + m_frozen = true; + m_triggered = false; + m_post_remaining = 0; + m_fault_code = 0; + m_head = 0; + m_count = 0; + m_frozen = false; +} + +bool blackbox_is_frozen(void) { + return m_frozen; +} + +bool blackbox_is_triggered(void) { + return m_triggered; +} + +uint8_t blackbox_fault_code(void) { + return m_fault_code; +} + +uint32_t blackbox_sample_count(void) { + return m_count; +} + +uint32_t blackbox_isr_tick(void) { + return m_isr_tick; +} + +const volatile bb_record_t *blackbox_get_record(uint32_t age) { + uint32_t count = m_count; + uint32_t head = m_head; + + if (count == 0 || age >= count || age >= BB_BUF_LEN) { + return 0; + } + + uint32_t idx = (head + BB_BUF_LEN - 1 - age) % BB_BUF_LEN; + return &m_buf[idx]; +} diff --git a/blackbox/blackbox.h b/blackbox/blackbox.h new file mode 100644 index 0000000000..b2b11cd993 --- /dev/null +++ b/blackbox/blackbox.h @@ -0,0 +1,87 @@ +/* + * blackbox.h + * + * RAM ring-buffer "black box" for capturing FOC state around faults + * (primarily FAULT_CODE_ABS_OVER_CURRENT). Written from the FOC ADC ISR, + * read from thread context (terminal / RTT export). + * + * Design constraints: + * - Single writer (FOC ADC ISR), no locks, no malloc, no formatting in ISR. + * - On fault the buffer keeps writing BB_POST_TRIGGER more records and then + * freezes, preserving data from before and after the trigger. + */ + +#ifndef BLACKBOX_H_ +#define BLACKBOX_H_ + +#include +#include + +// Number of records in the ring buffer. 256 x 56 B = 14 KB in main SRAM. +// Stock 75_300 has ~25 KB of ram0 left for .bss + heap, so this leaves +// roughly 10 KB of heap headroom. Verify with the terminal "mem" command. +#ifndef BB_BUF_LEN +#define BB_BUF_LEN 256 +#endif + +// Record every BB_DECIMATION:th FOC ADC ISR (1 = every ISR, ~12.5 kHz). +#ifndef BB_DECIMATION +#define BB_DECIMATION 1 +#endif + +// Records still written after a fault notification before freezing (25 %). +#ifndef BB_POST_TRIGGER +#define BB_POST_TRIGGER (BB_BUF_LEN / 4) +#endif + +// bb_record_t::flags bits +#define BB_FLAG_FAULT_ACTIVE (1 << 0) // Fault was already notified when this record was written + +typedef struct { + uint32_t tick; // FOC ADC ISR counter (counts every ISR, also skipped ones) + float ia; // Phase currents (A) + float ib; + float ic; + float id; // dq currents (A) + float iq; + float i_abs; // sqrt(id^2 + iq^2), the ABS_OVER_CURRENT comparison variable + float i_abs_filter; // Filtered version (used when l_slow_abs_current is true) + float duty_now; + float v_bus; // Input voltage (V) + float phase; // Electrical phase (rad) + float speed_rad_s; // PLL speed (electrical rad/s) + uint8_t fault_code; // mc_fault_code that triggered the freeze (0 = none) + uint8_t state; // mc_state + uint8_t control_mode; // mc_control_mode + uint8_t flags; // BB_FLAG_* +} bb_record_t; + +// Thread context API +void blackbox_init(void); +void blackbox_clear(void); +// Ask the dump thread to stream the whole ring buffer over RTT as CSV. +// Also triggerable from the host by sending 'd' on RTT down channel 0. +void blackbox_request_dump(void); +// Enable/disable freezing the buffer after a fault (default: disabled). +// Also toggleable from the host with 'f' on the RTT down channel. +void blackbox_set_freeze_enabled(bool enabled); +bool blackbox_freeze_enabled(void); +bool blackbox_is_frozen(void); +bool blackbox_is_triggered(void); +uint8_t blackbox_fault_code(void); +uint32_t blackbox_sample_count(void); // Total records written since last clear +uint32_t blackbox_isr_tick(void); +// Get record by age; age 0 = newest, age 1 = previous, ... Returns NULL if not available. +const volatile bb_record_t *blackbox_get_record(uint32_t age); + +// ISR context API (FOC ADC ISR only) +// Returns the slot to fill for this ISR cycle, or NULL when skipped +// (decimation) or frozen. Must be paired with blackbox_commit_isr(). +volatile bb_record_t *blackbox_next_record_isr(void); +void blackbox_commit_isr(void); + +// Callable from ISR or thread context. Arms the post-trigger countdown, +// after which the buffer freezes. Only the first notification counts. +void blackbox_notify_fault(uint8_t fault_code); + +#endif /* BLACKBOX_H_ */ diff --git a/blackbox/blackbox.mk b/blackbox/blackbox.mk new file mode 100644 index 0000000000..db002d13a2 --- /dev/null +++ b/blackbox/blackbox.mk @@ -0,0 +1,5 @@ +BLACKBOXSRC = blackbox/SEGGER_RTT.c \ + blackbox/SEGGER_RTT_printf.c \ + blackbox/blackbox.c + +BLACKBOXINC = blackbox diff --git a/blackbox/host/__pycache__/bb_csv_view.cpython-312.pyc b/blackbox/host/__pycache__/bb_csv_view.cpython-312.pyc new file mode 100644 index 0000000000..aafa9786d6 Binary files /dev/null and b/blackbox/host/__pycache__/bb_csv_view.cpython-312.pyc differ diff --git a/blackbox/host/__pycache__/bb_live.cpython-312.pyc b/blackbox/host/__pycache__/bb_live.cpython-312.pyc new file mode 100644 index 0000000000..49b09c7c3b Binary files /dev/null and b/blackbox/host/__pycache__/bb_live.cpython-312.pyc differ diff --git a/blackbox/host/bb_capture.py b/blackbox/host/bb_capture.py new file mode 100644 index 0000000000..ef8ffa6573 --- /dev/null +++ b/blackbox/host/bb_capture.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +"""Capture a VESC blackbox dump over J-Link RTT. + +Connects to the target via J-Link, optionally triggers a dump by sending +'d' on RTT down channel 0, then records everything from RTT up channel 0 +until the #BB_DUMP_END marker (or timeout) and writes it to a log file. + +Requires: pip install pylink-square + +Usage: + python bb_capture.py --out dump.log # trigger + capture + python bb_capture.py --out dump.log --no-trigger # just listen (use the + # bb_dump terminal cmd) + python bb_capture.py --clear # send 'c' (bb_clear) + +The captured log can be plotted with bb_plot.py. +""" + +import argparse +import sys +import time + +try: + import pylink +except ImportError: + sys.exit("pylink not installed. Run: pip install pylink-square") + +END_MARKER = b"#BB_DUMP_END" + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--device", default="STM32F407VG", help="J-Link device name") + parser.add_argument("--speed", type=int, default=4000, help="SWD speed in kHz") + parser.add_argument("--out", default="bb_dump.log", help="Output log file") + parser.add_argument("--timeout", type=float, default=15.0, help="Capture timeout in seconds") + parser.add_argument("--no-trigger", action="store_true", + help="Do not send 'd'; wait for a dump triggered elsewhere") + parser.add_argument("--clear", action="store_true", + help="Send 'c' (blackbox clear) instead of capturing a dump") + args = parser.parse_args() + + jlink = pylink.JLink() + jlink.open() + jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) + jlink.connect(args.device, speed=args.speed) + jlink.rtt_start(None) + + # Wait for the RTT control block to be located. + for _ in range(50): + try: + if jlink.rtt_get_num_up_buffers() > 0: + break + except pylink.errors.JLinkRTTException: + pass + time.sleep(0.1) + else: + sys.exit("RTT control block not found. Is the blackbox firmware running?") + + if args.clear: + jlink.rtt_write(0, list(b"c")) + time.sleep(0.3) + data = jlink.rtt_read(0, 4096) + if data: + sys.stdout.write(bytes(data).decode(errors="replace")) + print("Clear command sent.") + jlink.close() + return + + if not args.no_trigger: + jlink.rtt_write(0, list(b"d")) + print("Dump trigger sent.") + + print(f"Capturing to {args.out} (timeout {args.timeout:.0f} s)...") + captured = bytearray() + t_start = time.time() + t_last_data = t_start + + while True: + data = jlink.rtt_read(0, 4096) + now = time.time() + if data: + captured.extend(bytes(data)) + t_last_data = now + if END_MARKER in captured: + # Drain the remaining bytes of the END line. + time.sleep(0.2) + tail = jlink.rtt_read(0, 4096) + if tail: + captured.extend(bytes(tail)) + break + else: + time.sleep(0.02) + + if now - t_start > args.timeout: + print("Warning: timeout reached before #BB_DUMP_END.", file=sys.stderr) + break + # Give up early if a dump started but stalled. + if captured and now - t_last_data > 3.0: + print("Warning: data stream stalled.", file=sys.stderr) + break + + jlink.close() + + with open(args.out, "wb") as f: + f.write(captured) + + n_lines = captured.count(b"\n") + print(f"Captured {len(captured)} bytes, {n_lines} lines -> {args.out}") + if END_MARKER in captured: + print("Dump complete. Plot it with: python bb_plot.py " + args.out) + + +if __name__ == "__main__": + main() diff --git a/blackbox/host/bb_csv_view.py b/blackbox/host/bb_csv_view.py new file mode 100644 index 0000000000..d8db1d35f3 --- /dev/null +++ b/blackbox/host/bb_csv_view.py @@ -0,0 +1,509 @@ +#!/usr/bin/env python3 +"""View saved bb_live CSV files with multi-panel zoom controls. + +Usage: + python bb_csv_view.py blackbox/host/bb_live_20260612_120355.csv + python bb_csv_view.py # open empty, then pick a file with "打开 CSV…" + +The window starts without requiring a file; use the "打开 CSV…" button to +load or switch CSV files at any time without restarting from the command line. +""" + +import argparse +import bisect +import csv +import os +import tkinter as tk +from tkinter import filedialog, messagebox, ttk + +import matplotlib as mpl + +mpl.rcParams["path.simplify"] = True +mpl.rcParams["path.simplify_threshold"] = 1.0 +mpl.rcParams["agg.path.chunksize"] = 10000 +mpl.rcParams["axes.unicode_minus"] = False + +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk +from matplotlib.figure import Figure +from matplotlib.widgets import RectangleSelector + + +# Panels whose columns are absent in the loaded CSV are dropped automatically, +# so this default works for both the trimmed live stream (ia/ib/ic/id/iq/ +# theta_used) and the full 'd' dump (which still carries duty/fault/v_bus). +DEFAULT_PANELS = [ + {"title": "Phase currents", "cols": ["ia", "ib", "ic"]}, + {"title": "dq currents", "cols": ["id", "iq"]}, + {"title": "Theta used", "cols": ["theta", "theta_used", "phase"]}, + {"title": "Duty", "cols": ["duty"]}, + {"title": "Fault", "cols": ["fault"]}, +] + + +def get_unit(col): + if col in ("ia", "ib", "ic", "id", "iq", "i_abs", "i_abs_filter"): + return "A" + if col == "duty": + return "" + if col == "fault": + return "code" + if col == "v_bus": + return "V" + if col in ("theta", "theta_used", "phase"): + return "rad" + return "" + + +class CsvData: + def __init__(self, path): + self.path = path + self.columns = [] + self.data = {} + self.load(path) + + def load(self, path): + with open(path, newline="") as f: + reader = csv.DictReader(f) + self.columns = [c for c in (reader.fieldnames or []) if c] + for col in self.columns: + self.data[col] = [] + for row in reader: + for col in self.columns: + try: + self.data[col].append(float(row[col])) + except (ValueError, TypeError, KeyError): + self.data[col].append(float("nan")) + + if "t_s" not in self.data: + raise ValueError("CSV does not contain t_s") + + self.plot_columns = [c for c in self.columns if c not in ("wall_time_s", "t_s", "tick")] + + def x(self): + return self.data["t_s"] + + def y(self, col): + return self.data[col] + + +class CsvScopeApp: + def __init__(self, root, data=None): + self.root = root + self.root.title("Blackbox CSV Viewer") + self.root.geometry("1450x900") + + self.data = None + self.panels = [] + self.current_panel = 0 + self.axes = [] + self.lines = {} + self.selectors = [] + self.box_zoom_mode = None + self.wheel_mode = tk.StringVar(value="XY") + self.status_text = tk.StringVar(value="未加载数æ®ï¼Œè¯·ç‚¹å‡»â€œæ‰“å¼€ CSV…â€") + + # Vertical cursor placed by a left click, snapped to the nearest sample. + self.cursor_x = None + self.cursor_lines = [] + + self.build_ui() + + if data is not None: + self.apply_data(data) + else: + self.rebuild_figure(keep_xlim=False) + + def apply_data(self, data): + self.data = data + self.root.title(f"Blackbox CSV Viewer - {os.path.basename(data.path)}") + self.path_label.config(text=os.path.basename(data.path)) + + self.panels = [] + for panel in DEFAULT_PANELS: + cols = [c for c in panel["cols"] if c in data.plot_columns] + if cols: + self.panels.append({"title": panel["title"], "cols": cols}) + if not self.panels: + self.panels.append({"title": "Panel 1", "cols": data.plot_columns[:3]}) + + self.current_panel = 0 + self.status_text.set(f"{len(data.x())} rows") + self.rebuild_figure(keep_xlim=False) + + def open_csv(self): + path = filedialog.askopenfilename( + title="选择 bb_live CSV", + filetypes=[("CSV files", "*.csv"), ("All files", "*.*")], + ) + if not path: + return + try: + data = CsvData(path) + except Exception as e: + messagebox.showerror("加载失败", str(e)) + return + self.apply_data(data) + + def build_ui(self): + main = ttk.Frame(self.root) + main.pack(fill=tk.BOTH, expand=True) + + left = ttk.Frame(main, width=285) + left.pack(side=tk.LEFT, fill=tk.Y, padx=8, pady=8) + left.pack_propagate(False) + + right = ttk.Frame(main) + right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) + + ttk.Label(left, text="Blackbox CSV Viewer", font=("", 12, "bold")).pack(anchor="w") + self.path_label = ttk.Label(left, text="(未加载)", wraplength=260) + self.path_label.pack(anchor="w", pady=(2, 8)) + + ttk.Button(left, text="打开 CSV…", command=self.open_csv).pack(fill=tk.X) + ttk.Button(left, text="é‡ç½®è§†å›¾", command=self.reset_view).pack(fill=tk.X, pady=(4, 0)) + ttk.Button(left, text="å½“å‰ X 范围内自动缩放 Y", command=self.autoscale_all_y_to_visible_x).pack(fill=tk.X, pady=(4, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Label(left, text="å­å›¾åˆ—表").pack(anchor="w") + self.panel_list = tk.Listbox(left, height=7, exportselection=False) + self.panel_list.pack(fill=tk.X, pady=(2, 6)) + self.panel_list.bind("<>", self.on_panel_select) + + row = ttk.Frame(left) + row.pack(fill=tk.X, pady=2) + ttk.Button(row, text="新增å­å›¾", command=self.add_panel_dialog).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 2)) + ttk.Button(row, text="编辑å­å›¾", command=self.edit_panel_dialog).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(2, 0)) + ttk.Button(left, text="删除å­å›¾", command=self.delete_panel).pack(fill=tk.X, pady=(2, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Label(left, text="滚轮缩放模å¼").pack(anchor="w") + ttk.Combobox(left, textvariable=self.wheel_mode, values=["XY", "X", "Y"], state="readonly").pack(fill=tk.X) + ttk.Label( + left, + text="é è¿‘ X 轴滚轮åªç¼©æ”¾ Xï¼›é è¿‘ Y è½´åªç¼©æ”¾ Y;图内按上方模å¼ç¼©æ”¾ã€‚", + wraplength=260, + ).pack(anchor="w", pady=(4, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Label(left, text="框选缩放").pack(anchor="w") + row = ttk.Frame(left) + row.pack(fill=tk.X, pady=2) + ttk.Button(row, text="XY", command=lambda: self.set_box_zoom("XY")).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 2)) + ttk.Button(row, text="X", command=lambda: self.set_box_zoom("X")).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=2) + ttk.Button(row, text="Y", command=lambda: self.set_box_zoom("Y")).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(2, 0)) + ttk.Button(left, text="关闭框选", command=lambda: self.set_box_zoom(None)).pack(fill=tk.X, pady=(2, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Label(left, textvariable=self.status_text, wraplength=260).pack(anchor="w") + + self.fig = Figure(figsize=(12, 8), dpi=100) + self.canvas = FigureCanvasTkAgg(self.fig, master=right) + self.toolbar = NavigationToolbar2Tk(self.canvas, right, pack_toolbar=False) + self.toolbar.update() + self.toolbar.pack(side=tk.TOP, fill=tk.X) + self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) + self.canvas.mpl_connect("scroll_event", self.on_scroll) + self.canvas.mpl_connect("button_press_event", self.on_button_press) + + def choose_columns_dialog(self, title, initial=None): + initial = set(initial or []) + win = tk.Toplevel(self.root) + win.title(title) + win.geometry("360x500") + win.transient(self.root) + win.grab_set() + + result = {"cols": None} + lb = tk.Listbox(win, selectmode=tk.EXTENDED, exportselection=False) + lb.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + for col in self.data.plot_columns: + lb.insert(tk.END, col) + if col in initial: + lb.selection_set(tk.END) + + btns = ttk.Frame(win) + btns.pack(fill=tk.X, padx=10, pady=(0, 10)) + + def ok(): + cols = [self.data.plot_columns[i] for i in lb.curselection()] + if not cols: + messagebox.showwarning("未选择å˜é‡", "至少选择一个å˜é‡ã€‚", parent=win) + return + result["cols"] = cols + win.destroy() + + ttk.Button(btns, text="确定", command=ok).pack(side=tk.RIGHT, padx=(5, 0)) + ttk.Button(btns, text="å–æ¶ˆ", command=win.destroy).pack(side=tk.RIGHT) + self.root.wait_window(win) + return result["cols"] + + def add_panel_dialog(self): + if self.data is None: + return + cols = self.choose_columns_dialog("新增å­å›¾") + if cols: + self.panels.append({"title": f"Panel {len(self.panels) + 1}", "cols": cols}) + self.current_panel = len(self.panels) - 1 + self.rebuild_figure(keep_xlim=True) + + def edit_panel_dialog(self): + if self.data is None or not self.panels: + return + cols = self.choose_columns_dialog("编辑å­å›¾", self.panels[self.current_panel]["cols"]) + if cols: + self.panels[self.current_panel]["cols"] = cols + self.rebuild_figure(keep_xlim=True) + + def delete_panel(self): + if len(self.panels) <= 1: + return + del self.panels[self.current_panel] + self.current_panel = max(0, min(self.current_panel, len(self.panels) - 1)) + self.rebuild_figure(keep_xlim=True) + + def on_panel_select(self, _event=None): + sel = self.panel_list.curselection() + if sel: + self.current_panel = int(sel[0]) + + def refresh_panel_list(self): + self.panel_list.delete(0, tk.END) + for i, panel in enumerate(self.panels): + self.panel_list.insert(tk.END, f"{i + 1}: {', '.join(panel['cols'])}") + if self.panels: + self.panel_list.selection_set(self.current_panel) + + def rebuild_figure(self, keep_xlim=True): + old_xlim = self.axes[0].get_xlim() if keep_xlim and self.axes else None + self.fig.clear() + self.axes = [] + self.lines = {} + # The cleared figure dropped any previous cursor artists. + self.cursor_lines = [] + + n = len(self.panels) + first_ax = None + for i, panel in enumerate(self.panels): + ax = self.fig.add_subplot(n, 1, i + 1, sharex=first_ax) + if first_ax is None: + first_ax = ax + self.axes.append(ax) + for col in panel["cols"]: + line, = ax.plot(self.data.x(), self.data.y(col), lw=1.0, label=col) + self.lines[(i, col)] = line + ax.grid(True, linestyle="--", alpha=0.3) + ax.set_ylabel(self.panel_ylabel(panel["cols"])) + ax.set_title(panel["title"], loc="left", fontsize=10) + ax.legend(loc="upper right", fontsize=8) + + if self.axes: + self.axes[-1].set_xlabel("time / s") + if old_xlim: + self.axes[0].set_xlim(old_xlim) + else: + xs = self.data.x() + self.axes[0].set_xlim(xs[0], xs[-1] if xs[-1] > xs[0] else xs[0] + 1.0) + + if self.axes: + self.fig.tight_layout(rect=[0, 0, 1, 0.97]) + self.refresh_panel_list() + self.create_selectors() + self.autoscale_all_y_to_visible_x(redraw=False) + if self.cursor_x is not None: + self.draw_cursor(redraw=False) + self.canvas.draw_idle() + + def panel_ylabel(self, cols): + units = {get_unit(c) for c in cols if get_unit(c)} + return "/".join(sorted(units)) if units else "value" + + def autoscale_all_y_to_visible_x(self, redraw=True): + if not self.axes: + return + xs = self.data.x() + if not xs: + return + x0, x1 = self.axes[0].get_xlim() + if x0 > x1: + x0, x1 = x1, x0 + i0 = max(0, bisect.bisect_left(xs, x0) - 1) + i1 = min(len(xs), bisect.bisect_right(xs, x1) + 1) + if i1 <= i0: + i0, i1 = 0, len(xs) + + for panel_idx, ax in enumerate(self.axes): + ys_all = [] + for col in self.panels[panel_idx]["cols"]: + ys_all.extend(y for y in self.data.y(col)[i0:i1] if y == y) + if not ys_all: + continue + y_min = min(ys_all) + y_max = max(ys_all) + pad = (y_max - y_min) * 0.08 if y_max != y_min else (abs(y_min) * 0.1 or 1.0) + ax.set_ylim(y_min - pad, y_max + pad) + if redraw: + self.canvas.draw_idle() + + def reset_view(self): + if self.data is None: + return + xs = self.data.x() + if xs and self.axes: + self.axes[0].set_xlim(xs[0], xs[-1] if xs[-1] > xs[0] else xs[0] + 1.0) + self.autoscale_all_y_to_visible_x(redraw=False) + self.canvas.draw_idle() + + def create_selectors(self): + for selector in self.selectors: + selector.set_active(False) + self.selectors = [] + for ax in self.axes: + selector = RectangleSelector( + ax, self.on_box_select, useblit=True, button=[1], + minspanx=5, minspany=5, spancoords="pixels", interactive=False, + ) + selector.set_active(self.box_zoom_mode is not None) + self.selectors.append(selector) + + def set_box_zoom(self, mode): + self.box_zoom_mode = mode + for selector in self.selectors: + selector.set_active(mode is not None) + self.status_text.set(f"框选缩放: {mode}" if mode else "框选缩放关闭") + + def on_box_select(self, eclick, erelease): + if self.box_zoom_mode is None or eclick.inaxes != erelease.inaxes: + return + ax = eclick.inaxes + mode = self.box_zoom_mode.upper() + if mode in ("X", "XY") and eclick.xdata is not None and erelease.xdata is not None: + x0, x1 = sorted([eclick.xdata, erelease.xdata]) + if abs(x1 - x0) > 1e-12: + self.axes[0].set_xlim(x0, x1) + if mode in ("Y", "XY") and eclick.ydata is not None and erelease.ydata is not None: + y0, y1 = sorted([eclick.ydata, erelease.ydata]) + if abs(y1 - y0) > 1e-12: + ax.set_ylim(y0, y1) + if mode == "X": + self.autoscale_all_y_to_visible_x(redraw=False) + self.canvas.draw_idle() + + def on_button_press(self, event): + # Left click places a snapped vertical cursor across all subplots. + # Skip while box-zoom or the toolbar pan/zoom tools own the left button. + if event.button != 1 or self.data is None or not self.axes: + return + if self.box_zoom_mode is not None: + return + if getattr(self.toolbar, "mode", ""): + return + if event.inaxes not in self.axes or event.xdata is None: + return + panel_idx = self.axes.index(event.inaxes) + self.set_cursor(event.xdata, panel_idx) + + def set_cursor(self, x, panel_idx=None): + xs = self.data.x() + if not xs: + return + idx = self.nearest_index(xs, x) + self.cursor_x = xs[idx] + self.draw_cursor() + self.update_cursor_status(idx, panel_idx if panel_idx is not None else self.current_panel) + + @staticmethod + def nearest_index(xs, x): + i = bisect.bisect_left(xs, x) + if i <= 0: + return 0 + if i >= len(xs): + return len(xs) - 1 + return i if (xs[i] - x) < (x - xs[i - 1]) else i - 1 + + def clear_cursor_lines(self): + for line in self.cursor_lines: + try: + line.remove() + except (ValueError, NotImplementedError): + pass + self.cursor_lines = [] + + def draw_cursor(self, redraw=True): + self.clear_cursor_lines() + if self.cursor_x is None: + return + for ax in self.axes: + line = ax.axvline(self.cursor_x, color="0.35", linestyle="--", linewidth=0.9, zorder=5) + self.cursor_lines.append(line) + if redraw: + self.canvas.draw_idle() + + def update_cursor_status(self, idx, panel_idx): + parts = [f"t={self.data.x()[idx]:.6f}s"] + if "tick" in self.data.data: + parts.append(f"tick={int(self.data.data['tick'][idx])}") + for col in self.panels[panel_idx]["cols"]: + parts.append(f"{col}={self.data.y(col)[idx]:.3f}") + self.status_text.set(" ".join(parts)) + + def on_scroll(self, event): + if not self.axes: + return + ax = self.axis_from_event(event) + if ax is None: + return + + mode = self.wheel_mode_from_event(event, ax) + scale = 0.8 if event.button == "up" else 1.25 + + if mode in ("X", "XY"): + center = event.xdata + if center is None: + center = ax.transData.inverted().transform((event.x, event.y))[0] + x0, x1 = self.axes[0].get_xlim() + self.axes[0].set_xlim(center - (center - x0) * scale, center + (x1 - center) * scale) + + if mode in ("Y", "XY"): + center = event.ydata + if center is None: + center = ax.transData.inverted().transform((event.x, event.y))[1] + y0, y1 = ax.get_ylim() + ax.set_ylim(center - (center - y0) * scale, center + (y1 - center) * scale) + + self.canvas.draw_idle() + + def axis_from_event(self, event): + if event.inaxes in self.axes: + return event.inaxes + for ax in self.axes: + box = ax.bbox + if box.x0 - 70 <= event.x <= box.x1 + 10 and box.y0 - 45 <= event.y <= box.y1 + 10: + return ax + return None + + def wheel_mode_from_event(self, event, ax): + box = ax.bbox + if box.x0 <= event.x <= box.x1 and box.y0 - 45 <= event.y <= box.y0 + 8: + return "X" + if box.x0 - 70 <= event.x <= box.x0 + 8 and box.y0 <= event.y <= box.y1: + return "Y" + return self.wheel_mode.get().upper() + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("csvfile", nargs="?", help="Saved bb_live CSV (optional)") + args = parser.parse_args() + + root = tk.Tk() + app = CsvScopeApp(root) + if args.csvfile: + try: + app.apply_data(CsvData(args.csvfile)) + except Exception as e: + messagebox.showerror("加载失败", str(e)) + root.mainloop() + + +if __name__ == "__main__": + main() diff --git a/blackbox/host/bb_live.py b/blackbox/host/bb_live.py new file mode 100644 index 0000000000..d1f6383c43 --- /dev/null +++ b/blackbox/host/bb_live.py @@ -0,0 +1,848 @@ +#!/usr/bin/env python3 +"""Live VESC blackbox scope over J-Link RTT. + +Requires: + pip install pylink-square matplotlib + +Usage: + python bb_live.py --out live.csv + python bb_live.py --speed 8000 --out live.csv +""" + +import argparse +import bisect +import csv +import datetime as dt +import math +import os +import struct +import sys +import tempfile +import threading +import time +import tkinter as tk +from tkinter import filedialog, messagebox, ttk + +import matplotlib as mpl + +mpl.rcParams["path.simplify"] = True +mpl.rcParams["path.simplify_threshold"] = 1.0 +mpl.rcParams["agg.path.chunksize"] = 10000 +mpl.rcParams["axes.unicode_minus"] = False + +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk +from matplotlib.figure import Figure +from matplotlib.widgets import RectangleSelector + +try: + import pylink +except ImportError: + sys.exit("pylink not installed. Run: pip install pylink-square") + +MAGIC = b"BBIN" +# Header carries the ISR tick of the first record so the wire records can omit +# the per-record tick (records in a batch are consecutive, decimation == 1). +HEADER = struct.Struct("<4sBBHII") +# Firmware wire record (BB_STREAM_VERSION 11), 14 bytes, no tick: +# ia, ib, ic, id, iq (int16, 50 LSB/A), +# theta (int16, full turn over int16 range), duty (int16, 10000 LSB/duty). +WIRE = struct.Struct(" 0: + return + except pylink.errors.JLinkRTTException: + pass + time.sleep(0.1) + raise RuntimeError("RTT control block not found. Is the blackbox firmware running?") + + +def parse_frames(buffer): + records = [] + payloads = [] + bad_frames = 0 + + while True: + start = buffer.find(MAGIC) + if start < 0: + del buffer[:-3] + return records, payloads, bad_frames + + if start > 0: + del buffer[:start] + + if len(buffer) < HEADER.size: + return records, payloads, bad_frames + + magic, version, record_size, count, first_tick, checksum = HEADER.unpack(buffer[:HEADER.size]) + if magic != MAGIC or version != STREAM_VERSION or record_size != WIRE.size: + del buffer[0] + bad_frames += 1 + continue + + frame_len = HEADER.size + record_size * count + if len(buffer) < frame_len: + return records, payloads, bad_frames + + payload = buffer[HEADER.size:frame_len] + if stream_checksum(payload) != checksum: + next_magic = buffer.find(MAGIC, 1) + if next_magic >= 0: + del buffer[:next_magic] + else: + del buffer[:-3] + bad_frames += 1 + continue + + disk_chunk = bytearray() + pos = HEADER.size + for i in range(count): + wire = WIRE.unpack(buffer[pos:pos + record_size]) + tick = first_tick + i + records.append(decode_record((tick,) + wire)) + disk_chunk += RECORD.pack(tick, *wire) + pos += record_size + payloads.append(bytes(disk_chunk)) + + del buffer[:frame_len] + + +def stream_checksum(data): + total = 0x9E3779B9 + for byte in data: + total = ((total << 5) | (total >> 27)) & 0xFFFFFFFF + total ^= byte + total = (total + 0x7F4A7C15) & 0xFFFFFFFF + return total + + +def get_unit(col): + if col in ("ia", "ib", "ic", "id", "iq", "i_abs", "i_abs_filter"): + return "A" + if col == "v_bus": + return "V" + if col == "erpm": + return "ERPM" + if col == "speed_rad_s": + return "rad/s" + if col in ("phase", "theta", "theta_used"): + return "rad" + return "" + + +class LiveStore: + def __init__(self, sample_rate): + self.sample_rate = sample_rate + self.tick0 = None + self.wall0 = None + self.last_tick = None + self.missing_ticks = 0 + self.row_count = 0 + self.data = {"t_s": []} + for col in PLOT_COLUMNS: + self.data[col] = [] + + def append_record(self, rec, wall_now=None): + values = dict(zip(RAW_COLUMNS, rec)) + if self.tick0 is None: + self.tick0 = values["tick"] + if self.wall0 is None: + self.wall0 = wall_now if wall_now is not None else time.time() + + if self.last_tick is not None and values["tick"] > self.last_tick + 1: + self.missing_ticks += values["tick"] - self.last_tick - 1 + self.last_tick = values["tick"] + + t_s = (values["tick"] - self.tick0) / self.sample_rate + wall_time_s = (wall_now if wall_now is not None else time.time()) - self.wall0 + row = {"wall_time_s": wall_time_s, "t_s": t_s, **values} + self.row_count += 1 + + self.data["t_s"].append(t_s) + for col in PLOT_COLUMNS: + self.data[col].append(row[col]) + + return row + + def clear(self): + self.tick0 = None + self.wall0 = None + self.last_tick = None + self.missing_ticks = 0 + self.row_count = 0 + for values in self.data.values(): + values.clear() + + def x(self): + return self.data["t_s"] + + def y(self, col): + return self.data[col] + + def nearest_index(self, x_val): + xs = self.x() + if not xs: + return 0 + return min(range(len(xs)), key=lambda i: abs(xs[i] - x_val)) + + +class RttScopeApp: + def __init__(self, root, args): + self.root = root + self.args = args + self.store = LiveStore(args.sample_rate) + self.buffer = bytearray() + self.data_lock = threading.RLock() + self.rtt_lock = threading.Lock() + self.raw_lock = threading.Lock() + self.reader_stop = threading.Event() + self.reader_thread = None + + self.jlink = None + self.streaming = False + self.connected = False + self.auto_follow = True + self.last_plot_update = 0.0 + self.last_status_update = 0.0 + self.bad_frames = 0 + self.raw_file = None + self.raw_path = None + self.raw_record_count = 0 + self.raw_tick0 = None + self.last_raw_tick = None + self.missing_ticks = 0 + + self.panels = [dict(title=p["title"], cols=list(p["cols"])) for p in DEFAULT_PANELS] + self.current_panel = 0 + self.axes = [] + self.lines = {} + self.selectors = [] + self.box_zoom_mode = None + self.wheel_mode = tk.StringVar(value="XY") + self.window_s = tk.DoubleVar(value=args.window) + self.status_text = tk.StringVar(value="未连接") + + self.root.title("VESC RTT Live Scope") + self.root.geometry("1450x900") + self.root.protocol("WM_DELETE_WINDOW", self.on_close) + + self.build_ui() + self.connect_rtt() + self.rebuild_figure(keep_xlim=False) + self.start_reader_thread() + self.root.after(50, self.gui_tick) + + if args.auto_start: + self.start_stream() + + def build_ui(self): + main = ttk.Frame(self.root) + main.pack(fill=tk.BOTH, expand=True) + + left = ttk.Frame(main, width=285) + left.pack(side=tk.LEFT, fill=tk.Y, padx=8, pady=8) + left.pack_propagate(False) + + right = ttk.Frame(main) + right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) + + ttk.Label(left, text="RTT Live Scope", font=("", 12, "bold")).pack(anchor="w") + ttk.Label(left, text=f"CSV ä¿å­˜åŸºå: {self.args.out}", wraplength=260).pack(anchor="w", pady=(2, 8)) + + row = ttk.Frame(left) + row.pack(fill=tk.X, pady=2) + ttk.Button(row, text="Start", command=self.start_stream).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 2)) + ttk.Button(row, text="Stop", command=self.stop_stream).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=2) + ttk.Button(row, text="Save", command=self.save_now).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(2, 0)) + + row = ttk.Frame(left) + row.pack(fill=tk.X, pady=2) + ttk.Button(row, text="清空数æ®", command=self.clear_data).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 2)) + ttk.Button(row, text="é‡ç½®è§†å›¾", command=self.reset_view).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(2, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Label(left, text="å­å›¾åˆ—表").pack(anchor="w") + self.panel_list = tk.Listbox(left, height=7, exportselection=False) + self.panel_list.pack(fill=tk.X, pady=(2, 6)) + self.panel_list.bind("<>", self.on_panel_select) + + row = ttk.Frame(left) + row.pack(fill=tk.X, pady=2) + ttk.Button(row, text="新增å­å›¾", command=self.add_panel_dialog).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 2)) + ttk.Button(row, text="编辑å­å›¾", command=self.edit_panel_dialog).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(2, 0)) + ttk.Button(left, text="删除å­å›¾", command=self.delete_panel).pack(fill=tk.X, pady=(2, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Button(left, text="å½“å‰ X 范围内自动缩放 Y", command=self.autoscale_all_y_to_visible_x).pack(fill=tk.X) + + ttk.Label(left, text="显示窗å£ç§’æ•°(è¿è¡Œæ—¶è‡ªåŠ¨è·Ÿéš)").pack(anchor="w", pady=(8, 2)) + ttk.Entry(left, textvariable=self.window_s).pack(fill=tk.X) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Label(left, text="滚轮缩放模å¼").pack(anchor="w") + ttk.Combobox(left, textvariable=self.wheel_mode, values=["XY", "X", "Y"], state="readonly").pack(fill=tk.X) + ttk.Label( + left, + text="é¼ æ ‡é è¿‘ X 轴滚轮åªç¼©æ”¾ Xï¼›é è¿‘ Y è½´åªç¼©æ”¾ Y;图内按上方模å¼ç¼©æ”¾ã€‚", + wraplength=260, + ).pack(anchor="w", pady=(4, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Label(left, text="框选缩放").pack(anchor="w") + row = ttk.Frame(left) + row.pack(fill=tk.X, pady=2) + ttk.Button(row, text="XY", command=lambda: self.set_box_zoom("XY")).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 2)) + ttk.Button(row, text="X", command=lambda: self.set_box_zoom("X")).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=2) + ttk.Button(row, text="Y", command=lambda: self.set_box_zoom("Y")).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(2, 0)) + ttk.Button(left, text="关闭框选", command=lambda: self.set_box_zoom(None)).pack(fill=tk.X, pady=(2, 0)) + + ttk.Separator(left).pack(fill=tk.X, pady=10) + ttk.Checkbutton(left, text="è¿è¡Œæ—¶è‡ªåŠ¨è·Ÿéšæœ€æ–°æ•°æ®", variable=tk.BooleanVar(value=True), command=self.toggle_follow).pack(anchor="w") + ttk.Label(left, textvariable=self.status_text, wraplength=260).pack(anchor="w", pady=(8, 0)) + + self.fig = Figure(figsize=(12, 8), dpi=100) + self.canvas = FigureCanvasTkAgg(self.fig, master=right) + self.toolbar = NavigationToolbar2Tk(self.canvas, right, pack_toolbar=False) + self.toolbar.update() + self.toolbar.pack(side=tk.TOP, fill=tk.X) + self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) + + self.canvas.mpl_connect("scroll_event", self.on_scroll) + + def connect_rtt(self): + try: + self.jlink = pylink.JLink() + self.jlink.open() + self.jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) + self.jlink.connect(self.args.device, speed=self.args.speed) + self.jlink.rtt_start(None) + wait_for_rtt(self.jlink) + self.jlink.rtt_read(0, 4096) + self.connected = True + self.status_text.set(f"RTT 已连接,SWD {self.args.speed} kHz") + except Exception as e: + messagebox.showerror("RTT 连接失败", str(e), parent=self.root) + self.status_text.set("RTT 连接失败") + + def start_stream(self): + if not self.connected or self.streaming: + return + self.reset_raw_capture() + self.buffer.clear() + with self.rtt_lock: + self.jlink.rtt_read(0, 4096) + self.jlink.rtt_write(0, list(b"s")) + self.streaming = True + self.auto_follow = True + self.status_text.set("Streaming") + + def stop_stream(self): + if not self.connected: + return + with self.rtt_lock: + self.jlink.rtt_write(0, list(b"x")) + self.streaming = False + self.buffer.clear() + self.status_text.set("Stopped,图åƒå·²å†»ç»“,å¯ç¼©æ”¾æŸ¥çœ‹") + self.canvas.draw_idle() + + def toggle_follow(self): + self.auto_follow = not self.auto_follow + + def reset_raw_capture(self): + if self.raw_file: + self.raw_file.close() + if self.raw_path and os.path.exists(self.raw_path): + try: + os.remove(self.raw_path) + except OSError: + pass + self.raw_file = tempfile.NamedTemporaryFile(prefix="bb_live_", suffix=".bin", delete=False) + self.raw_path = self.raw_file.name + self.raw_record_count = 0 + self.raw_tick0 = None + self.last_raw_tick = None + self.missing_ticks = 0 + + def save_now(self): + if not self.raw_path or self.raw_record_count == 0: + self.status_text.set("没有å¯ä¿å­˜çš„æ•°æ®") + return + + with self.raw_lock: + if self.raw_file: + self.raw_file.flush() + out_path = self.timestamped_csv_path(self.args.out) + rows = self.export_raw_to_csv(out_path) + + self.status_text.set(f"å·²ä¿å­˜ CSV: {out_path} ({rows} rows)") + + def timestamped_csv_path(self, path): + root, ext = os.path.splitext(path) + if not ext: + ext = ".csv" + stamp = dt.datetime.now().strftime("%Y%m%d_%H%M%S") + return f"{root}_{stamp}{ext}" + + def export_raw_to_csv(self, out_path): + rows = 0 + tick0 = None + with open(self.raw_path, "rb") as raw, open(out_path, "w", newline="") as out: + writer = csv.DictWriter(out, fieldnames=["wall_time_s", "t_s"] + RAW_COLUMNS) + writer.writeheader() + while True: + data = raw.read(RECORD.size) + if not data: + break + if len(data) != RECORD.size: + break + values = dict(zip(RAW_COLUMNS, decode_record(RECORD.unpack(data)))) + if tick0 is None: + tick0 = values["tick"] + t_s = (values["tick"] - tick0) / self.args.sample_rate + writer.writerow({"wall_time_s": t_s, "t_s": t_s, **values}) + rows += 1 + return rows + + def clear_data(self): + if self.streaming: + self.stop_stream() + with self.data_lock: + self.store.clear() + self.bad_frames = 0 + self.buffer.clear() + self.reset_raw_capture() + self.rebuild_figure(keep_xlim=False) + self.status_text.set("已清空数æ®") + + def start_reader_thread(self): + self.reader_thread = threading.Thread(target=self.reader_loop, name="rtt-reader", daemon=True) + self.reader_thread.start() + + def reader_loop(self): + last_flush = time.time() + while not self.reader_stop.is_set(): + if not self.connected or not self.streaming: + time.sleep(0.002) + continue + + drained = False + for _ in range(64): + with self.rtt_lock: + data = self.jlink.rtt_read(0, 8192) + if not data: + break + drained = True + self.buffer.extend(bytes(data)) + + if drained: + records, payloads, bad_frames = parse_frames(self.buffer) + if bad_frames: + self.bad_frames += bad_frames + if payloads and self.raw_file: + with self.raw_lock: + for payload in payloads: + self.raw_file.write(payload) + + if records: + wall_now = time.time() + plot_records = [] + for rec in records: + tick = rec[0] + if self.raw_tick0 is None: + self.raw_tick0 = tick + if self.last_raw_tick is not None and tick > self.last_raw_tick + 1: + self.missing_ticks += tick - self.last_raw_tick - 1 + self.last_raw_tick = tick + self.raw_record_count += 1 + if (self.raw_record_count % self.args.plot_decimation) == 0: + plot_records.append(rec) + + with self.data_lock: + for rec in plot_records: + self.store.append_record(rec, wall_now=wall_now) + else: + time.sleep(0.0005) + + now = time.time() + if self.raw_file and now - last_flush > 0.25: + with self.raw_lock: + self.raw_file.flush() + last_flush = now + + def gui_tick(self): + if self.streaming: + self.update_plot_live() + self.update_stream_status() + self.root.after(50, self.gui_tick) + + def update_stream_status(self): + raw_count = self.raw_record_count + if self.raw_tick0 is not None and self.last_raw_tick is not None: + t_s = (self.last_raw_tick - self.raw_tick0) / self.args.sample_rate + else: + t_s = 0.0 + saved_hz = raw_count / t_s if t_s > 0 else 0.0 + self.status_text.set( + f"Streaming | raw={raw_count} | rate≈{saved_hz:.0f} Hz | " + f"missing_ticks={self.missing_ticks} | bad_frames={self.bad_frames}" + ) + + def choose_columns_dialog(self, title, initial=None): + initial = set(initial or []) + win = tk.Toplevel(self.root) + win.title(title) + win.geometry("360x500") + win.transient(self.root) + win.grab_set() + + result = {"cols": None} + lb = tk.Listbox(win, selectmode=tk.EXTENDED, exportselection=False) + lb.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + for col in PLOT_COLUMNS: + lb.insert(tk.END, col) + if col in initial: + lb.selection_set(tk.END) + + btns = ttk.Frame(win) + btns.pack(fill=tk.X, padx=10, pady=(0, 10)) + + def ok(): + cols = [PLOT_COLUMNS[i] for i in lb.curselection()] + if not cols: + messagebox.showwarning("未选择å˜é‡", "至少选择一个å˜é‡ã€‚", parent=win) + return + result["cols"] = cols + win.destroy() + + ttk.Button(btns, text="确定", command=ok).pack(side=tk.RIGHT, padx=(5, 0)) + ttk.Button(btns, text="å–æ¶ˆ", command=win.destroy).pack(side=tk.RIGHT) + self.root.wait_window(win) + return result["cols"] + + def add_panel_dialog(self): + cols = self.choose_columns_dialog("新增å­å›¾") + if cols: + self.panels.append({"title": f"Panel {len(self.panels) + 1}", "cols": cols}) + self.current_panel = len(self.panels) - 1 + self.rebuild_figure(keep_xlim=True) + + def edit_panel_dialog(self): + if not self.panels: + return + cols = self.choose_columns_dialog("编辑å­å›¾", self.panels[self.current_panel]["cols"]) + if cols: + self.panels[self.current_panel]["cols"] = cols + self.rebuild_figure(keep_xlim=True) + + def delete_panel(self): + if len(self.panels) <= 1: + return + del self.panels[self.current_panel] + self.current_panel = max(0, min(self.current_panel, len(self.panels) - 1)) + self.rebuild_figure(keep_xlim=True) + + def on_panel_select(self, _event=None): + sel = self.panel_list.curselection() + if sel: + self.current_panel = int(sel[0]) + + def refresh_panel_list(self): + self.panel_list.delete(0, tk.END) + for i, panel in enumerate(self.panels): + self.panel_list.insert(tk.END, f"{i + 1}: {', '.join(panel['cols'])}") + if self.panels: + self.panel_list.selection_set(self.current_panel) + + def rebuild_figure(self, keep_xlim=True): + old_xlim = self.axes[0].get_xlim() if keep_xlim and self.axes else None + self.fig.clear() + self.axes = [] + self.lines = {} + + n = len(self.panels) + first_ax = None + for i, panel in enumerate(self.panels): + ax = self.fig.add_subplot(n, 1, i + 1, sharex=first_ax) + if first_ax is None: + first_ax = ax + self.axes.append(ax) + for col in panel["cols"]: + line, = ax.plot([], [], lw=1.1, label=col) + self.lines[(i, col)] = line + ax.grid(True, linestyle="--", alpha=0.3) + ax.set_ylabel(self.panel_ylabel(panel["cols"])) + ax.set_title(panel["title"], loc="left", fontsize=10) + ax.legend(loc="upper right", fontsize=8) + + if self.axes: + self.axes[-1].set_xlabel("time / s") + if old_xlim: + self.axes[0].set_xlim(old_xlim) + + self.fig.tight_layout(rect=[0, 0, 1, 0.97]) + self.refresh_panel_list() + self.create_selectors() + self.update_all_line_data() + self.canvas.draw_idle() + + def panel_ylabel(self, cols): + units = {get_unit(c) for c in cols if get_unit(c)} + return "/".join(sorted(units)) if units else "value" + + def update_all_line_data(self): + with self.data_lock: + xs = list(self.store.x()) + ys_by_col = {col: list(self.store.y(col)) for col in PLOT_COLUMNS} + for (_panel_idx, col), line in self.lines.items(): + line.set_data(xs, ys_by_col[col]) + + def update_visible_line_data(self, x0, x1): + with self.data_lock: + xs = self.store.x() + if not xs: + return + + i0 = max(0, bisect.bisect_left(xs, x0) - 1) + i1 = min(len(xs), bisect.bisect_right(xs, x1) + 1) + x_view = list(xs[i0:i1]) + y_view = {col: list(self.store.y(col)[i0:i1]) for col in PLOT_COLUMNS} + + for (_panel_idx, col), line in self.lines.items(): + line.set_data(x_view, y_view[col]) + + def update_plot_live(self): + with self.data_lock: + xs = list(self.store.x()) + if not xs: + self.canvas.draw_idle() + return + + if self.auto_follow: + window = max(0.05, float(self.window_s.get() or 2.0)) + xmax = xs[-1] + xmin = max(0.0, xmax - window) + self.axes[0].set_xlim(xmin, max(window, xmax)) + self.update_visible_line_data(xmin, max(window, xmax)) + self.autoscale_all_y_to_visible_x(redraw=False) + else: + x0, x1 = self.axes[0].get_xlim() + self.update_visible_line_data(min(x0, x1), max(x0, x1)) + for ax in self.axes: + ax.relim() + ax.autoscale_view() + + self.canvas.draw_idle() + + def autoscale_all_y_to_visible_x(self, redraw=True): + if not self.axes: + return + with self.data_lock: + xs = list(self.store.x()) + ys_by_col = {col: list(self.store.y(col)) for col in PLOT_COLUMNS} + if not xs: + return + x0, x1 = self.axes[0].get_xlim() + if x0 > x1: + x0, x1 = x1, x0 + i0 = max(0, bisect.bisect_left(xs, x0) - 1) + i1 = min(len(xs), bisect.bisect_right(xs, x1) + 1) + if i1 <= i0: + i0, i1 = 0, len(xs) + + for panel_idx, ax in enumerate(self.axes): + ys_all = [] + for col in self.panels[panel_idx]["cols"]: + ys = ys_by_col[col] + if ys: + ys_all.extend(y for y in ys[i0:i1] if math.isfinite(y)) + if not ys_all: + continue + y_min = min(ys_all) + y_max = max(ys_all) + if y_min == y_max: + pad = abs(y_min) * 0.1 or 1.0 + else: + pad = (y_max - y_min) * 0.08 + ax.set_ylim(y_min - pad, y_max + pad) + if redraw: + self.canvas.draw_idle() + + def reset_view(self): + with self.data_lock: + xs = list(self.store.x()) + if xs and self.axes: + self.axes[0].set_xlim(xs[0], xs[-1] if xs[-1] > xs[0] else xs[0] + 1.0) + self.autoscale_all_y_to_visible_x(redraw=False) + self.canvas.draw_idle() + + def create_selectors(self): + for selector in self.selectors: + selector.set_active(False) + self.selectors = [] + for ax in self.axes: + selector = RectangleSelector( + ax, self.on_box_select, useblit=True, button=[1], + minspanx=5, minspany=5, spancoords="pixels", interactive=False, + ) + selector.set_active(self.box_zoom_mode is not None) + self.selectors.append(selector) + + def set_box_zoom(self, mode): + self.box_zoom_mode = mode + for selector in self.selectors: + selector.set_active(mode is not None) + self.status_text.set(f"框选缩放: {mode}" if mode else "框选缩放关闭") + + def on_box_select(self, eclick, erelease): + if self.box_zoom_mode is None or eclick.inaxes != erelease.inaxes: + return + ax = eclick.inaxes + mode = self.box_zoom_mode.upper() + if mode in ("X", "XY") and eclick.xdata is not None and erelease.xdata is not None: + x0, x1 = sorted([eclick.xdata, erelease.xdata]) + if abs(x1 - x0) > 1e-12: + self.axes[0].set_xlim(x0, x1) + if mode in ("Y", "XY") and eclick.ydata is not None and erelease.ydata is not None: + y0, y1 = sorted([eclick.ydata, erelease.ydata]) + if abs(y1 - y0) > 1e-12: + ax.set_ylim(y0, y1) + if mode == "X": + self.autoscale_all_y_to_visible_x(redraw=False) + self.auto_follow = False + self.canvas.draw_idle() + + def on_scroll(self, event): + if not self.axes: + return + ax = self.axis_from_event(event) + if ax is None: + return + + mode = self.wheel_mode_from_event(event, ax) + scale = 0.8 if event.button == "up" else 1.25 + + if mode in ("X", "XY"): + center = event.xdata + if center is None: + center = ax.transData.inverted().transform((event.x, event.y))[0] + x0, x1 = self.axes[0].get_xlim() + self.axes[0].set_xlim(center - (center - x0) * scale, center + (x1 - center) * scale) + + if mode in ("Y", "XY"): + center = event.ydata + if center is None: + center = ax.transData.inverted().transform((event.x, event.y))[1] + y0, y1 = ax.get_ylim() + ax.set_ylim(center - (center - y0) * scale, center + (y1 - center) * scale) + + self.auto_follow = False + self.canvas.draw_idle() + + def axis_from_event(self, event): + if event.inaxes in self.axes: + return event.inaxes + for ax in self.axes: + box = ax.bbox + if box.x0 - 70 <= event.x <= box.x1 + 10 and box.y0 - 45 <= event.y <= box.y1 + 10: + return ax + return None + + def wheel_mode_from_event(self, event, ax): + box = ax.bbox + if box.x0 <= event.x <= box.x1 and box.y0 - 45 <= event.y <= box.y0 + 8: + return "X" + if box.x0 - 70 <= event.x <= box.x0 + 8 and box.y0 <= event.y <= box.y1: + return "Y" + return self.wheel_mode.get().upper() + + def on_close(self): + try: + self.stop_stream() + except Exception: + pass + self.reader_stop.set() + if self.reader_thread and self.reader_thread.is_alive(): + self.reader_thread.join(timeout=1.0) + if self.raw_file: + self.raw_file.flush() + self.raw_file.close() + if self.raw_path and os.path.exists(self.raw_path): + try: + os.remove(self.raw_path) + except OSError: + pass + if self.jlink: + try: + self.jlink.close() + except Exception: + pass + self.root.destroy() + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--device", default="STM32F407VG", help="J-Link device name") + parser.add_argument("--speed", type=int, default=8000, help="SWD speed in kHz") + parser.add_argument("--out", default="bb_live.csv", help="CSV output file") + parser.add_argument("--png", help="Save figure to this PNG") + parser.add_argument("--sample-rate", type=float, default=15000.0, + help="FOC ADC ISR frequency in Hz; 75_300 low-side V0 default is 15000") + parser.add_argument("--window", type=float, default=2.0, help="Auto-follow window in seconds") + parser.add_argument("--plot-decimation", type=int, default=10, + help="Only every Nth raw sample is kept for GUI plotting; CSV export keeps all raw samples") + parser.add_argument("--auto-start", action="store_true", help="Start streaming immediately") + args = parser.parse_args() + args.plot_decimation = max(1, args.plot_decimation) + + root = tk.Tk() + try: + RttScopeApp(root, args) + root.mainloop() + except Exception as e: + messagebox.showerror("bb_live failed", str(e)) + raise + + +if __name__ == "__main__": + main() diff --git a/blackbox/host/bb_plot.py b/blackbox/host/bb_plot.py new file mode 100644 index 0000000000..81136e50ea --- /dev/null +++ b/blackbox/host/bb_plot.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +"""Parse and plot a VESC blackbox dump captured over RTT. + +Accepts the raw capture from bb_capture.py or a J-Link RTT Viewer log; +everything outside the #BB_DUMP_BEGIN / #BB_DUMP_END markers is ignored. +If the file contains several dumps the last complete one is used. + +Requires: pip install matplotlib + +Usage: + python bb_plot.py dump.log # show plots + python bb_plot.py dump.log --png out.png # also save a PNG + python bb_plot.py dump.log --csv out.csv # also save the clean CSV +""" + +import argparse +import math +import re +import sys + +COLUMNS = ["tick", "ia", "ib", "ic", "id", "iq", "i_abs", "i_abs_filter", + "duty", "v_bus", "phase", "speed_rad_s", "fault", "state", "mode", "flags"] + +FAULT_NAMES = { + 0: "NONE", 1: "OVER_VOLTAGE", 2: "UNDER_VOLTAGE", 3: "DRV", + 4: "ABS_OVER_CURRENT", 5: "OVER_TEMP_FET", 6: "OVER_TEMP_MOTOR", +} + + +def parse_dump(path): + with open(path, "rb") as f: + text = f.read().decode(errors="replace") + + # Take the last complete BEGIN...END block. + blocks = re.findall(r"#BB_DUMP_BEGIN,([^\r\n]*)\r?\n(.*?)#BB_DUMP_END", + text, re.DOTALL) + if not blocks: + sys.exit("No complete #BB_DUMP_BEGIN/#BB_DUMP_END block found in " + path) + meta_str, body = blocks[-1] + + meta = {} + for kv in meta_str.split(","): + if "=" in kv: + k, v = kv.split("=", 1) + meta[k.strip()] = v.strip() + + rows = [] + for line in body.splitlines(): + line = line.strip() + if not line or line.startswith("#") or line.startswith("tick,"): + continue + parts = line.split(",") + if len(parts) != len(COLUMNS): + continue # torn/interleaved line, skip + try: + rows.append([float(x) for x in parts]) + except ValueError: + continue + + if not rows: + sys.exit("Dump block found but contained no valid data rows.") + + data = {c: [r[i] for r in rows] for i, c in enumerate(COLUMNS)} + return meta, data + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("logfile", help="Captured RTT log file") + parser.add_argument("--png", help="Save figure to this PNG file") + parser.add_argument("--csv", help="Save the clean CSV to this file") + parser.add_argument("--no-show", action="store_true", help="Do not open a plot window") + args = parser.parse_args() + + meta, d = parse_dump(args.logfile) + + f_isr = float(meta.get("f_isr_hz", 0)) or None + decimation = int(meta.get("decimation", 1)) + fault = int(meta.get("fault", 0)) + + tick0 = d["tick"][0] + if f_isr: + t = [(tk - tick0) / f_isr * 1000.0 for tk in d["tick"]] # ms + x_label = "t (ms)" + else: + t = [tk - tick0 for tk in d["tick"]] + x_label = "ISR ticks" + + n = len(t) + print(f"Records: {n}, f_isr: {f_isr} Hz, decimation: {decimation}, " + f"fault: {fault} ({FAULT_NAMES.get(fault, '?')}), frozen: {meta.get('frozen')}") + + if args.csv: + with open(args.csv, "w") as f: + f.write("t_ms," + ",".join(COLUMNS) + "\n") + for i in range(n): + f.write(f"{t[i]:.4f}," + ",".join(str(d[c][i]) for c in COLUMNS) + "\n") + print("CSV written to", args.csv) + + try: + import matplotlib.pyplot as plt + except ImportError: + sys.exit("matplotlib not installed. Run: pip install matplotlib") + + fig, axes = plt.subplots(6, 1, sharex=True, figsize=(12, 14)) + fig.suptitle(f"VESC blackbox dump - fault {fault} ({FAULT_NAMES.get(fault, '?')})") + + # Mark where the fault flag first became active. + t_fault = None + for i in range(n): + if int(d["flags"][i]) & 0x01: + t_fault = t[i] + break + + ax = axes[0] + ax.plot(t, d["i_abs"], label="i_abs (raw)") + ax.plot(t, d["i_abs_filter"], label="i_abs_filter") + ax.set_ylabel("A") + ax.legend(loc="upper left") + ax.set_title("ABS current (fault comparison variable)") + + ax = axes[1] + ax.plot(t, d["ia"], label="ia") + ax.plot(t, d["ib"], label="ib") + ax.plot(t, d["ic"], label="ic") + ax.set_ylabel("A") + ax.legend(loc="upper left") + ax.set_title("Phase currents") + + ax = axes[2] + ax.plot(t, d["id"], label="id") + ax.plot(t, d["iq"], label="iq") + ax.set_ylabel("A") + ax.legend(loc="upper left") + ax.set_title("dq currents") + + ax = axes[3] + ax.plot(t, d["phase"], label="phase (rad)") + erpm = [w * 60.0 / (2.0 * math.pi) for w in d["speed_rad_s"]] + ax2 = ax.twinx() + ax2.plot(t, erpm, color="tab:orange", alpha=0.6, label="ERPM") + ax.set_ylabel("rad") + ax2.set_ylabel("ERPM") + ax.legend(loc="upper left") + ax2.legend(loc="upper right") + ax.set_title("Observer phase / speed") + + ax = axes[4] + ax.plot(t, d["v_bus"], label="v_bus") + ax2 = ax.twinx() + ax2.plot(t, d["duty"], color="tab:green", alpha=0.6, label="duty") + ax.set_ylabel("V") + ax2.set_ylabel("duty") + ax.legend(loc="upper left") + ax2.legend(loc="upper right") + ax.set_title("Bus voltage / duty") + + ax = axes[5] + ax.step(t, d["fault"], where="post", label="fault_code") + ax.step(t, d["flags"], where="post", alpha=0.6, label="flags") + ax.set_ylabel("code") + ax.set_xlabel(x_label) + ax.legend(loc="upper left") + ax.set_title("Fault code / flags") + + if t_fault is not None: + for ax in axes: + ax.axvline(t_fault, color="red", linestyle="--", alpha=0.7) + axes[0].annotate("fault", xy=(t_fault, axes[0].get_ylim()[1]), + color="red", ha="left", va="top") + + fig.tight_layout(rect=(0, 0, 1, 0.97)) + + if args.png: + fig.savefig(args.png, dpi=150) + print("Figure written to", args.png) + + if not args.no_show: + plt.show() + + +if __name__ == "__main__": + main() diff --git a/blackbox/host/requirements.txt b/blackbox/host/requirements.txt new file mode 100644 index 0000000000..9d0e247a0f --- /dev/null +++ b/blackbox/host/requirements.txt @@ -0,0 +1,2 @@ +pylink-square +matplotlib diff --git a/build_75_300.log b/build_75_300.log new file mode 100644 index 0000000000..ae03c85f4a Binary files /dev/null and b/build_75_300.log differ diff --git a/conf_general.c b/conf_general.c index 28c4ed4de2..f7598b6d11 100644 --- a/conf_general.c +++ b/conf_general.c @@ -127,11 +127,26 @@ __attribute__((section(".text2"))) void conf_general_init(void) { if (g_backup.hw_config_init_flag == BACKUP_VAR_INIT_CODE) { memcpy((void*)backup_tmp.hw_config, (uint8_t*)g_backup.hw_config, sizeof(g_backup.hw_config)); } + + if (g_backup.enc_corr_init_flag == BACKUP_VAR_INIT_CODE) { + memcpy((void*)backup_tmp.enc_corr, (uint8_t*)g_backup.enc_corr, sizeof(g_backup.enc_corr)); + backup_tmp.enc_corr_en = g_backup.enc_corr_en; + } + + if (g_backup.can_init_flag == BACKUP_VAR_INIT_CODE) { + backup_tmp.can_baud = g_backup.can_baud; + backup_tmp.can_id = g_backup.can_id; + } else { + backup_tmp.can_baud = APPCONF_CAN_BAUD_RATE; + backup_tmp.can_id = HW_DEFAULT_ID; + } } backup_tmp.odometer_init_flag = BACKUP_VAR_INIT_CODE; backup_tmp.runtime_init_flag = BACKUP_VAR_INIT_CODE; backup_tmp.hw_config_init_flag = BACKUP_VAR_INIT_CODE; + backup_tmp.enc_corr_init_flag = BACKUP_VAR_INIT_CODE; + backup_tmp.can_init_flag = BACKUP_VAR_INIT_CODE; g_backup = backup_tmp; conf_general_store_backup_data(); @@ -149,7 +164,7 @@ __attribute__((section(".text2"))) bool conf_general_store_backup_data(void) { mc_interface_release_motor_override_both(); if (!mc_interface_wait_for_motor_release_both(3.0)) { - return 100; + return false; } utils_sys_lock_cnt(); @@ -347,6 +362,8 @@ __attribute__((section(".text2"))) void conf_general_read_app_configuration(app_ // Set the default configuration if (!is_ok) { confgenerator_set_defaults_appconf(conf); + conf->can_baud_rate = g_backup.can_baud; + conf->controller_id = g_backup.can_id; } } @@ -371,6 +388,13 @@ __attribute__((section(".text2"))) bool conf_general_store_app_configuration(app uint8_t *conf_addr = (uint8_t*)conf; uint16_t var; + // Some hardware does not have USB and/or UART broken out. On that hardware we always boot with + // VESC CAN mode to make it harder to lock yourself out of the device. +#ifdef HW_BOOT_VESC_CAN + CAN_MODE can_mode_before = conf->can_mode; + conf->can_mode = CAN_MODE_VESC; +#endif + conf->crc = app_calc_crc(conf); FLASH_Unlock(); @@ -387,11 +411,19 @@ __attribute__((section(".text2"))) bool conf_general_store_app_configuration(app } } +#ifdef HW_BOOT_VESC_CAN + conf->can_mode = can_mode_before; +#endif + FLASH_Lock(); timeout_configure_IWDT(); mc_interface_ignore_input_both(100); utils_sys_unlock_cnt(); + g_backup.can_id = conf->controller_id; + g_backup.can_baud = conf->can_baud_rate; + conf_general_store_backup_data(); + return is_ok; } @@ -1186,6 +1218,9 @@ __attribute__((section(".text2"))) int conf_general_measure_flux_linkage_openloo linkage_sum += mcpwm_foc_get_vq() / rad_s_now; + float phase_bemf = mcpwm_foc_get_phase_bemf(); +// float phase_bemf = mcpwm_foc_get_phase_observer(); + // Optionally use magnitude // linkage_sum += sqrtf(SQ(mcpwm_foc_get_vq()) + SQ(mcpwm_foc_get_vd())) / rad_s_now; @@ -1197,17 +1232,19 @@ __attribute__((section(".text2"))) int conf_general_measure_flux_linkage_openloo float diff_encoder = utils_angle_difference(encoder_read_deg(), enc_val_last); if (fabsf(diff_encoder) >= 5.0) { - float diff_observer = utils_angle_difference(mcpwm_foc_get_phase_observer(), phase_val_last); + float diff_observer = utils_angle_difference(phase_bemf, phase_val_last); enc_val_last = encoder_read_deg(); - phase_val_last = mcpwm_foc_get_phase_observer(); + phase_val_last = phase_bemf; enc_ratio_sum += diff_observer / diff_encoder; enc_samples += 1.0; enc_travel += fabsf(diff_encoder); } - if (enc_travel >= 20.0) { + const float travel_for_ratio = 40.0; + + if (enc_travel >= travel_for_ratio) { float ratio = roundf(SIGN(enc_ratio_sum) * enc_ratio_sum / enc_samples); bool inverted = enc_ratio_sum < 0.0; @@ -1218,11 +1255,11 @@ __attribute__((section(".text2"))) int conf_general_measure_flux_linkage_openloo phase_tmp *= ratio; float s, c; - sincosf(DEG2RAD_f(utils_angle_difference(phase_tmp, mcpwm_foc_get_phase_observer())), &s, &c); + sincosf(DEG2RAD_f(utils_angle_difference(phase_tmp, phase_bemf)), &s, &c); enc_diff_sin += s; enc_diff_cos += c; - if (enc_travel >= 380.0 && !enc_res_set) { + if (enc_travel >= (360.0 + travel_for_ratio) && !enc_res_set) { if (enc_offset) { *enc_offset = RAD2DEG_f(atan2f(enc_diff_sin, enc_diff_cos)); utils_norm_angle(enc_offset); diff --git a/conf_general.h b/conf_general.h index a72c65633d..4c8905611f 100755 --- a/conf_general.h +++ b/conf_general.h @@ -24,7 +24,7 @@ #define FW_VERSION_MAJOR 6 #define FW_VERSION_MINOR 06 // Set to 0 for building a release and iterate during beta test builds -#define FW_TEST_VERSION_NUMBER 4 +#define FW_TEST_VERSION_NUMBER 0 #include "datatypes.h" @@ -70,6 +70,7 @@ */ //#include "mcconf_default.h" //#include "mcconf_china_60kv.h" +#include "RTT_motor.h" /* * Select default user app configuration diff --git a/datatypes.h b/datatypes.h index c6a9c92ecf..be679843c0 100644 --- a/datatypes.h +++ b/datatypes.h @@ -1441,6 +1441,18 @@ typedef struct __attribute__((packed)) { // HW-specific data uint32_t hw_config_init_flag; uint8_t hw_config[128]; + + // Encoder correction table + uint32_t enc_corr_init_flag; + int8_t enc_corr_en; + int8_t enc_corr[360]; + + // CAN settings + uint32_t can_init_flag; + uint8_t can_baud; + uint8_t can_id; + + uint8_t dummy; } backup_data; #endif /* DATATYPES_H_ */ diff --git a/encoder/encoder.c b/encoder/encoder.c index 181583a873..882a89abaa 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -399,41 +399,44 @@ void encoder_set_custom_callbacks ( #pragma GCC pop_options float encoder_read_deg(void) { + float res = 0.0; + if (m_encoder_type_now == ENCODER_TYPE_AS504x) { - return AS504x_LAST_ANGLE(&encoder_cfg_as504x); + res = AS504x_LAST_ANGLE(&encoder_cfg_as504x); } else if (m_encoder_type_now == ENCODER_TYPE_MT6816) { - return MT6816_LAST_ANGLE(&encoder_cfg_mt6816); + res = MT6816_LAST_ANGLE(&encoder_cfg_mt6816); } else if (m_encoder_type_now == ENCODER_TYPE_TLE5012) { - return TLE5012_LAST_ANGLE(&encoder_cfg_tle5012); + res = TLE5012_LAST_ANGLE(&encoder_cfg_tle5012); } else if (m_encoder_type_now == ENCODER_TYPE_AD2S1205_SPI) { - return AD2S1205_LAST_ANGLE(&encoder_cfg_ad2s1205); + res = AD2S1205_LAST_ANGLE(&encoder_cfg_ad2s1205); } else if (m_encoder_type_now == ENCODER_TYPE_ABI) { - return enc_abi_read_deg(&encoder_cfg_ABI); + res = enc_abi_read_deg(&encoder_cfg_ABI); } else if (m_encoder_type_now == ENCODER_TYPE_SINCOS) { - return enc_sincos_read_deg(&encoder_cfg_sincos); + res = enc_sincos_read_deg(&encoder_cfg_sincos); } else if (m_encoder_type_now == ENCODER_TYPE_TS5700N8501) { - return enc_ts5700n8501_read_deg(&encoder_cfg_TS5700N8501); + res = enc_ts5700n8501_read_deg(&encoder_cfg_TS5700N8501); } else if (m_encoder_type_now == ENCODER_TYPE_AS5x47U) { - return AS5x47U_LAST_ANGLE(&encoder_cfg_as5x47u); + res = AS5x47U_LAST_ANGLE(&encoder_cfg_as5x47u); } else if (m_encoder_type_now == ENCODER_TYPE_BISSC) { - return BISSC_LAST_ANGLE(&encoder_cfg_bissc); + res = BISSC_LAST_ANGLE(&encoder_cfg_bissc); } else if (m_encoder_type_now == ENCODER_TYPE_CUSTOM) { if (m_enc_custom_read_deg) { - return m_enc_custom_read_deg(); + res = m_enc_custom_read_deg(); } else { - return m_enc_custom_pos; + res = m_enc_custom_pos; } } else if (m_encoder_type_now == ENCODER_TYPE_PWM) { - return enc_pwm_read_deg(); + res = enc_pwm_read_deg(); } else if (m_encoder_type_now == ENCODER_TYPE_PWM_ABI) { if (enc_pwm_update_cnt() >= 2) { encoder_cfg_ABI.state.index_found = true; enc_pwm_deinit(); } - return enc_abi_read_deg(&encoder_cfg_ABI); + res = enc_abi_read_deg(&encoder_cfg_ABI); } - return 0.0; + + return res; } float encoder_read_deg_multiturn(void) { diff --git a/hwconf/JetFleet/hw_JetFleetF6_core.c b/hwconf/JetFleet/hw_JetFleetF6_core.c index 1ba93bbaa4..18dec298f9 100644 --- a/hwconf/JetFleet/hw_JetFleetF6_core.c +++ b/hwconf/JetFleet/hw_JetFleetF6_core.c @@ -80,6 +80,21 @@ void hw_init_gpio(void) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + #ifdef HW_USE_BRK + // BRK Fault pin + palSetPadMode(BRK_GPIO, BRK_PIN, PAL_MODE_ALTERNATE(GPIO_AF_TIM1)); + #else + // Soft Lockout + palSetPadMode(BRK_GPIO, BRK_PIN, PAL_MODE_INPUT); + #endif + + + // AUX + AUX_OFF(); + palSetPadMode(AUX_GPIO, AUX_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + // LEDs palSetPadMode(LED_GREEN_GPIO, LED_GREEN_PIN, PAL_MODE_OUTPUT_PUSHPULL | diff --git a/hwconf/board.c b/hwconf/board.c index 4d546e3d65..1c7cabd5b0 100644 --- a/hwconf/board.c +++ b/hwconf/board.c @@ -15,6 +15,7 @@ */ #include "hal.h" +#include "hw.h" #if HAL_USE_PAL || defined(__DOXYGEN__) /** @@ -68,7 +69,7 @@ const PALConfig pal_default_config = { * and before any other initialization. */ void __early_init(void) { - + HW_VERY_EARLY_INIT(); stm32_clock_init(); } diff --git a/hwconf/hw.c b/hwconf/hw.c index fd019f1c09..a9898db191 100644 --- a/hwconf/hw.c +++ b/hwconf/hw.c @@ -30,7 +30,8 @@ uint8_t hw_id_from_uuid(void) { uint8_t id = utils_crc32c(STM32_UUID_8, 12) & 0x7F; // CAN ID 10 and 11 are often used by DieBieMS / FlexiBMS - uint8_t reserved[] = {10, 11}; + // ID 2 and 3 are usually express, vdisp and vbms + uint8_t reserved[] = {1, 2, 3, 4, 10, 11}; for (size_t i = 0; i < sizeof(reserved); ++i) { if (id == reserved[i]) { id = (id + 1) & 0x7F; diff --git a/hwconf/hw.h b/hwconf/hw.h index e69b9e2ac0..3f1e52d90d 100644 --- a/hwconf/hw.h +++ b/hwconf/hw.h @@ -551,6 +551,10 @@ #define HW_EARLY_INIT() #endif +#ifndef HW_VERY_EARLY_INIT +#define HW_VERY_EARLY_INIT() +#endif + // Default ID #ifndef HW_DEFAULT_ID #define HW_DEFAULT_ID (APPCONF_CONTROLLER_ID >= 0 ? APPCONF_CONTROLLER_ID : hw_id_from_uuid()) diff --git a/hwconf/shutdown.c b/hwconf/shutdown.c index 79c7fbfdb3..0853ba9520 100644 --- a/hwconf/shutdown.c +++ b/hwconf/shutdown.c @@ -74,17 +74,21 @@ void shutdown_hold(bool hold) { m_shutdown_hold = hold; } -bool do_shutdown(bool resample) { +void shutdown_save_and_hold(void) { #ifdef USE_LISPBM lispif_process_shutdown(); #endif + conf_general_store_backup_data(); + chThdSleepMilliseconds(100); + while (m_shutdown_hold) { chThdSleepMilliseconds(5); } +} - conf_general_store_backup_data(); - chThdSleepMilliseconds(100); +bool do_shutdown(bool resample) { + shutdown_save_and_hold(); bool disable_gates = true; if (resample) { @@ -150,8 +154,20 @@ static THD_FUNCTION(shutdown_thread, arg) { break; case SHUTDOWN_MODE_ALWAYS_ON: - m_inactivity_time += dt; HW_SHUTDOWN_HOLD_ON(); + break; + + default: + if (clicked) { + gates_disabled_here = do_shutdown(false); + } + break; + } + + switch (conf->shutdown_mode) { + case SHUTDOWN_MODE_ALWAYS_OFF: + case SHUTDOWN_MODE_ALWAYS_ON: { + m_inactivity_time += dt; // Without a shutdown switch use inactivity timer to estimate // when device is stopped. Check also distance between store // to prevent excessive flash write cycles. @@ -163,12 +179,8 @@ static THD_FUNCTION(shutdown_thread, arg) { odometer_old = mc_interface_get_odometer(); } } - break; - + } default: - if (clicked) { - gates_disabled_here = do_shutdown(false); - } break; } diff --git a/hwconf/shutdown.h b/hwconf/shutdown.h index 71d16ca551..f5e81b792d 100644 --- a/hwconf/shutdown.h +++ b/hwconf/shutdown.h @@ -28,17 +28,21 @@ #ifdef HW_SHUTDOWN_HOLD_ON #define SHUTDOWN_BUTTON_PRESSED shutdown_button_pressed() +#ifndef SHUTDOWN_SET_SAMPLING_DISABLED #define SHUTDOWN_SET_SAMPLING_DISABLED(d) shutdown_set_sampling_disabled(d) +#endif #else #define SHUTDOWN_BUTTON_PRESSED false +#ifndef SHUTDOWN_SET_SAMPLING_DISABLED #define SHUTDOWN_SET_SAMPLING_DISABLED(d) (void)d #endif +#endif -#define SHUTDOWN_SAVE_BACKUPDATA_TIMEOUT 60*3 // time of inactivity after wich backup data (odometer, running time, ...) is // stored to emulated eeprom when not using power switch. Must be greater than // average stopping time, usually semaphores require 120s max, so 60*3s or -// more should be pretty safe +// more should be pretty safe +#define SHUTDOWN_SAVE_BACKUPDATA_TIMEOUT (60 * 3) // Fucntions void shutdown_init(void); @@ -48,5 +52,6 @@ float shutdown_get_inactivity_time(void); void shutdown_set_sampling_disabled(bool disabled); void shutdown_hold(bool hold); bool do_shutdown(bool resample); +void shutdown_save_and_hold(void); #endif /* SHUTDOWN_H_ */ diff --git a/hwconf/trampa/75_300/hw_75_300_core.h b/hwconf/trampa/75_300/hw_75_300_core.h index a4f419480c..6ddb298b1f 100644 --- a/hwconf/trampa/75_300/hw_75_300_core.h +++ b/hwconf/trampa/75_300/hw_75_300_core.h @@ -32,7 +32,10 @@ // HW properties #define HW_HAS_3_SHUNTS -#define HW_HAS_PHASE_SHUNTS +// Custom board uses low-side shunts (not in series with the motor phases), +// so HW_HAS_PHASE_SHUNTS must NOT be defined. Current is only valid during +// the V0 vector and the firmware will skip sampling during V7. +//#define HW_HAS_PHASE_SHUNTS #define HW_HAS_PHASE_FILTERS // Macros @@ -68,7 +71,9 @@ #define AUX_ON() palSetPad(AUX_GPIO, AUX_PIN) #define AUX_OFF() palClearPad(AUX_GPIO, AUX_PIN) -#define CURRENT_FILTER_ON() palSetPad(GPIOD, 2) +// Force the hardware phase-current RC filter (GPIOD2) to stay disabled, +// even where the core code calls CURRENT_FILTER_ON(). +#define CURRENT_FILTER_ON() palClearPad(GPIOD, 2) #define CURRENT_FILTER_OFF() palClearPad(GPIOD, 2) /* diff --git a/hwconf/vesc/classic/hw_classic.h b/hwconf/vesc/classic/hw_classic.h new file mode 100644 index 0000000000..981b517021 --- /dev/null +++ b/hwconf/vesc/classic/hw_classic.h @@ -0,0 +1,27 @@ +/* + Copyright 2025 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_CLASSIC_H_ +#define HW_CLASSIC_H_ + +#define HWCLASSIC + +#include "hw_classic_core.h" + +#endif /* HW_CLASSIC_H_ */ diff --git a/hwconf/vesc/classic/hw_classic_core.c b/hwconf/vesc/classic/hw_classic_core.c new file mode 100644 index 0000000000..6337aeb1a6 --- /dev/null +++ b/hwconf/vesc/classic/hw_classic_core.c @@ -0,0 +1,536 @@ +/* + Copyright 2018 Benjamin Vedder benjamin@vedder.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "hw.h" +#include "ch.h" +#include "hal.h" +#include "stm32f4xx_conf.h" +#include "utils_math.h" +#include +#include "mc_interface.h" +#include "ledpwm.h" +#include "utils_math.h" +#include "main.h" +#include "app.h" +#include "comm_can.h" +#include "utils.h" +#include "shutdown.h" + +typedef enum { + SWITCH_BOOTED = 0, + SWITCH_TURN_ON_DELAY_ACTIVE, + SWITCH_HELD_AFTER_TURN_ON, + SWITCH_TURNED_ON, + SWITCH_SHUTTING_DOWN, +} switch_states; + +// Variables +static THD_WORKING_AREA(smart_switch_thread_wa, 256); +static THD_WORKING_AREA(switch_color_thread_wa, 256); +static THD_FUNCTION(switch_color_thread, arg); +static volatile switch_states switch_state = SWITCH_BOOTED; + +static volatile float switch_bright = 0.75; +static bool switch_color_thd_running = false; +static volatile bool i2c_running = false; + +// I2C configuration +static const I2CConfig i2cfg = { + OPMODE_I2C, + 100000, + STD_DUTY_CYCLE +}; + +void hw_init_gpio(void) { + // GPIO clock enable + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + + // LEDs + palSetPadMode(LED_GREEN_GPIO, LED_GREEN_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(LED_RED_GPIO, LED_RED_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + + // GPIOA Configuration: Channel 1 to 3 as alternate function push-pull + palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOA, 10, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + // Hall sensors + palSetPadMode(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3, PAL_MODE_INPUT_PULLUP); + + // Phase filters + palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(GPIOC, 14, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(GPIOC, 15, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + PHASE_FILTER_OFF(); + + palSetPadMode(CURRENT_FILTER_GPIO, CURRENT_FILTER_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + CURRENT_FILTER_OFF(); + + // AUX pins + AUX_OFF(); + palSetPadMode(AUX_GPIO, AUX_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + + // ADC Pins + palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 7, PAL_MODE_INPUT_ANALOG); + + palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOB, 1, PAL_MODE_INPUT_ANALOG); + + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG); +} + +void hw_setup_adc_channels(void) { + // ADC1 regular channels + ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); // 0 Curr 1 + ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_15Cycles); // 3 Volt 1 + ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, ADC_SampleTime_15Cycles); // 6 EXT + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_15Cycles); // 9 EXT4 + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_15Cycles); // 12 EXT4 + ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_15Cycles); // 15 TEMP_MOS + ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 7, ADC_SampleTime_15Cycles); // 18 Smart Switch + + // ADC2 regular channels + ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); // 1 Curr 2 + ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 2, ADC_SampleTime_15Cycles); // 4 Volt 2 + ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 3, ADC_SampleTime_15Cycles); // 7 EXT2 + ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 4, ADC_SampleTime_15Cycles); // 10 EXT5 + ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 5, ADC_SampleTime_15Cycles); // 13 EXT5 + ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 6, ADC_SampleTime_15Cycles); // 16 Temp Motor + ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 7, ADC_SampleTime_15Cycles); // 19 Temp Motor + + // ADC3 regular channels + ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); // 2 Curr 3 + ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 2, ADC_SampleTime_15Cycles); // 5 Volt 3 + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 3, ADC_SampleTime_15Cycles); // 8 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 4, ADC_SampleTime_15Cycles); // 11 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 5, ADC_SampleTime_15Cycles); // 14 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 6, ADC_SampleTime_15Cycles); // 17 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 7, ADC_SampleTime_15Cycles); // 20 Volt In + + // Injected channels + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 3, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 3, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_15Cycles); + + if (!switch_color_thd_running) { + chThdCreateStatic(switch_color_thread_wa, sizeof(switch_color_thread_wa), LOWPRIO, switch_color_thread, NULL); + switch_color_thd_running = true; + } +} + +void hw_start_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (!i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + i2cStart(&HW_I2C_DEV, &i2cfg); + i2c_running = true; + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +void hw_stop_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, PAL_MODE_INPUT); + + i2cStop(&HW_I2C_DEV); + i2c_running = false; + + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +/** + * Try to restore the i2c bus + */ +void hw_try_restore_i2c(void) { + if (i2c_running) { + i2cAcquireBus(&HW_I2C_DEV); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + chThdSleep(1); + + for(int i = 0;i < 16;i++) { + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + } + + // Generate start then stop condition + palClearPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + chThdSleep(1); + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + HW_I2C_DEV.state = I2C_STOP; + i2cStart(&HW_I2C_DEV, &i2cfg); + + i2cReleaseBus(&HW_I2C_DEV); + } +} + +void smart_switch_keep_on(void) { + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + //#ifdef HW_HAS_RGB_SWITCH + // LED_SWITCH_B_ON(); + // ledpwm_set_intensity(SWITCH_LED_B, 1.0); + //#else + // ledpwm_set_intensity(SWITCH_LED, 1.0); + // ledpwm_set_switch_intensity(0.6); + //#endif +} + +void smart_switch_shut_down(void) { + mc_interface_select_motor_thread(2); + mc_interface_set_current(0); + mc_interface_lock(); + mc_interface_select_motor_thread(1); + mc_interface_set_current(0); + mc_interface_lock(); + switch_state = SWITCH_SHUTTING_DOWN; + palClearPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + return; +} + +bool smart_switch_is_pressed(void) { + if (ADC_VOLTS(ADC_IND_SW_DET) > 0.9 && + (mc_interface_temp_fet_filtered() < 68.0) /* why?? */) { + return true; + } else { + return false; + } +} + +static THD_FUNCTION(switch_color_thread, arg) { + (void)arg; + chRegSetThreadName("switch_color"); + float switch_red = 0.0; + float switch_green = 0.0; + float switch_blue = 0.0; + + for(int i = 0; i < 400; i++) { + float angle = i*3.14/400.0; + float s,c; + utils_fast_sincos_better(angle, &s, &c); + switch_blue = 0.75* c*c; + ledpwm_set_intensity(LED_HW1,switch_bright*switch_blue); + utils_fast_sincos_better(angle + 3.14/3.0, &s, &c); + switch_green = 0.75* c*c; + ledpwm_set_intensity(LED_HW2,switch_bright*switch_green); + utils_fast_sincos_better(angle + 6.28/3.0, &s, &c); + switch_red = 0.75* c*c; + ledpwm_set_intensity(LED_HW3,switch_bright*switch_red); + chThdSleepMilliseconds(4); + } + float switch_red_old = switch_red_old; + float switch_green_old = switch_green; + float switch_blue_old = switch_blue; + float wh_left; + float left = mc_interface_get_battery_level(&wh_left); + + if (left < 0.5) { + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + } else { + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + } + + for (int i = 0; i < 100; i++) { + float red_now = utils_map((float) i,0.0, 100.0, switch_red_old, switch_red); + float blue_now = utils_map((float) i,0.0, 100.0, switch_blue_old, switch_blue); + float green_now = utils_map((float) i,0.0, 100.0, switch_green_old, switch_green); + ledpwm_set_intensity(LED_HW1, switch_bright*blue_now); + ledpwm_set_intensity(LED_HW2, switch_bright*green_now); + ledpwm_set_intensity(LED_HW3, switch_bright*red_now); + chThdSleepMilliseconds(2); + } + + for (;;) { + mc_fault_code fault = mc_interface_get_fault(); + mc_interface_select_motor_thread(2); + mc_fault_code fault2 = mc_interface_get_fault(); + mc_interface_select_motor_thread(1); + + if (fault != FAULT_CODE_NONE || fault2 != FAULT_CODE_NONE) { + ledpwm_set_intensity(LED_HW2, 0); + ledpwm_set_intensity(LED_HW1, 0); + for (int i = 0;i < (int)fault;i++) { + ledpwm_set_intensity(LED_HW3, 1.0); + chThdSleepMilliseconds(250); + ledpwm_set_intensity(LED_HW3, 0.0); + chThdSleepMilliseconds(250); + } + + chThdSleepMilliseconds(500); + + for (int i = 0;i < (int)fault2;i++) { + ledpwm_set_intensity(LED_HW3, 1.0); + chThdSleepMilliseconds(250); + ledpwm_set_intensity(LED_HW3, 0.0); + chThdSleepMilliseconds(250); + } + + chThdSleepMilliseconds(500); + } else { + left = mc_interface_get_battery_level(&wh_left); + if(left < 0.5){ + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + switch_green = 0; + }else{ + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + switch_red = 0; + } + ledpwm_set_intensity(LED_HW1, switch_bright*switch_blue); + ledpwm_set_intensity(LED_HW2, switch_bright*switch_green); + ledpwm_set_intensity(LED_HW3, switch_bright*switch_red); + } + + // Config check + mc_configuration *mcconf = (mc_configuration*)mc_interface_get_configuration(); + + if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_HALL) { + // In hall sensor mode we use the ADC pins on the comm-port as additional + // pull-ups as the voltage dividers take the voltage down otherwise. + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(HW_ADC_EXT5_GPIO, HW_ADC_EXT5_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN); + palSetPad(HW_ADC_EXT5_GPIO, HW_ADC_EXT5_PIN); + } else if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_ENCODER) { + // Ensure that the sin/cos pins are in ADC mode + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_INPUT_ANALOG); + palSetPadMode(HW_ADC_EXT5_GPIO, HW_ADC_EXT5_PIN, PAL_MODE_INPUT_ANALOG); + } + } + + chThdSleepMilliseconds(20); + } +} + +static THD_FUNCTION(smart_switch_thread, arg) { + (void)arg; + chRegSetThreadName("smart_switch"); + unsigned int millis_switch_pressed = 0; + + for (;;) { + const app_configuration *conf = app_get_configuration(); + + switch (switch_state) { + case SWITCH_BOOTED: + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + case SWITCH_TURN_ON_DELAY_ACTIVE: + switch_state = SWITCH_HELD_AFTER_TURN_ON; + mc_interface_select_motor_thread(2); + mc_interface_set_current(0); + mc_interface_lock(); + mc_interface_select_motor_thread(1); + mc_interface_set_current(0); + mc_interface_lock(); + + mc_interface_select_motor_thread(2); + mc_interface_unlock(); + mc_interface_select_motor_thread(1); + mc_interface_unlock(); + + // Wait for other systems to boot up before proceeding + while (!main_init_done()) { + chThdSleepMilliseconds(200); + } + break; + + case SWITCH_HELD_AFTER_TURN_ON: + if (smart_switch_is_pressed() && conf->shutdown_mode != SHUTDOWN_MODE_ALWAYS_OFF) { + switch_state = SWITCH_HELD_AFTER_TURN_ON; + } else { + switch_state = SWITCH_TURNED_ON; + } + break; + + case SWITCH_TURNED_ON: + if (conf->shutdown_mode == SHUTDOWN_MODE_ALWAYS_OFF) { + switch_bright = 1.0; + if (!smart_switch_is_pressed()) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } else { + if (smart_switch_is_pressed()) { + millis_switch_pressed++; + switch_bright = 0.5; + } else { + millis_switch_pressed = 0; + switch_bright = 1.0; + } + + if (millis_switch_pressed > SMART_SWITCH_MSECS_PRESSED_OFF) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } + break; + + case SWITCH_SHUTTING_DOWN: + switch_bright = 0; + systime_t tStart = chVTGetSystemTimeX(); + while (smart_switch_is_pressed()) { + chThdSleepMilliseconds(10); + if (UTILS_AGE_S(tStart) > 10.0) { + millis_switch_pressed = 0; + switch_state = SWITCH_TURNED_ON; + break; + } + } + + if (switch_state == SWITCH_TURNED_ON) { + break; + } + + shutdown_save_and_hold(); + comm_can_shutdown(255); + smart_switch_shut_down(); + chThdSleepMilliseconds(10000); + smart_switch_keep_on(); + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + default: + break; + } + + chThdSleepMilliseconds(1); + } +} + +void smart_switch_thread_start(void) { + chThdCreateStatic(smart_switch_thread_wa, sizeof(smart_switch_thread_wa), + NORMALPRIO, smart_switch_thread, NULL); +} + +void smart_switch_pin_init(void) { + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); + + palSetPadMode(SWITCH_OUT_GPIO,SWITCH_OUT_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_2_GPIO,SWITCH_LED_2_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + LED_SWITCH_B_ON(); + LED_SWITCH_R_OFF(); + LED_SWITCH_G_OFF(); + return; +} diff --git a/hwconf/vesc/classic/hw_classic_core.h b/hwconf/vesc/classic/hw_classic_core.h new file mode 100644 index 0000000000..f9d993a1d5 --- /dev/null +++ b/hwconf/vesc/classic/hw_classic_core.h @@ -0,0 +1,298 @@ +/* + Copyright 2025 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_CLASSIC_CORE_H_ +#define HW_CLASSIC_CORE_H_ + +#ifdef HWCLASSIC + #define HW_NAME "Classic" +#else + #error "Must define hardware type" +#endif + +// HW properties +#define HW_HAS_3_SHUNTS +#define HW_HAS_PHASE_FILTERS +#define HW_HAS_PHASE_SHUNTS + +// Macros +#define LED_GREEN_GPIO GPIOC +#define LED_GREEN_PIN 9 +#define LED_RED_GPIO GPIOC +#define LED_RED_PIN 12 + +#define LED_GREEN_ON() palSetPad(LED_GREEN_GPIO, LED_GREEN_PIN) +#define LED_GREEN_OFF() palClearPad(LED_GREEN_GPIO, LED_GREEN_PIN) +#define LED_RED_ON() palSetPad(LED_RED_GPIO, LED_RED_PIN) +#define LED_RED_OFF() palClearPad(LED_RED_GPIO, LED_RED_PIN) + +#define PHASE_FILTER_OFF() palSetPad(GPIOB, 12); palSetPad(GPIOC, 14); palSetPad(GPIOC, 15) +#define PHASE_FILTER_ON() palClearPad(GPIOB, 12); palClearPad(GPIOC, 14); palClearPad(GPIOC, 15) + +#define CURRENT_FILTER_GPIO GPIOC +#define CURRENT_FILTER_PIN 5 +#define CURRENT_FILTER_ON() palSetPad(CURRENT_FILTER_GPIO, CURRENT_FILTER_PIN) +#define CURRENT_FILTER_OFF() palClearPad(CURRENT_FILTER_GPIO, CURRENT_FILTER_PIN) + +#define AUX_GPIO GPIOA +#define AUX_PIN 3 +#define AUX_ON() palSetPad(AUX_GPIO, AUX_PIN) +#define AUX_OFF() palClearPad(AUX_GPIO, AUX_PIN) + +#define HW_SHUTDOWN_HOLD_ON(); +#define HW_SAMPLE_SHUTDOWN() 1 +#define HW_SHUTDOWN_HOLD_OFF() palClearPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); +#define HW_SHUTDOWN_NO + +#define DCCAL_ON() +#define DCCAL_OFF() + +#define HW_EARLY_INIT() smart_switch_pin_init(); \ + smart_switch_thread_start(); + +// Switch Pins +#define HW_HAS_RGB_SWITCH + +#define SMART_SWITCH_MSECS_PRESSED_OFF 2000 + +#define SWITCH_OUT_GPIO GPIOB +#define SWITCH_OUT_PIN 2 +#define SWITCH_LED_3_GPIO GPIOD +#define SWITCH_LED_3_PIN 2 +#define SWITCH_LED_2_GPIO GPIOC +#define SWITCH_LED_2_PIN 13 +#define SWITCH_LED_1_GPIO GPIOB +#define SWITCH_LED_1_PIN 7 + +#define LED_PWM1_ON() palClearPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM1_OFF() palSetPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM2_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM2_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM3_ON() palClearPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) +#define LED_PWM3_OFF() palSetPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) + +#define LED_SWITCH_R_ON() palClearPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_R_OFF() palSetPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_G_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_G_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_B_ON() palClearPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) +#define LED_SWITCH_B_OFF() palSetPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) + +/* + * ADC Vector + */ +#define HW_ADC_NBR_CONV 7 +#define HW_ADC_CHANNELS (HW_ADC_NBR_CONV * 3) +#define HW_ADC_INJ_CHANNELS 3 + +// ADC Indicies +#define ADC_IND_CURR1 0 +#define ADC_IND_CURR2 1 +#define ADC_IND_CURR3 2 +#define ADC_IND_SENS1 3 +#define ADC_IND_SENS2 4 +#define ADC_IND_SENS3 5 +#define ADC_IND_VIN_SENS 14 +#define ADC_IND_EXT 6 +#define ADC_IND_EXT2 7 +#define ADC_IND_EXT4 12 +#define ADC_IND_EXT5 13 +#define ADC_IND_TEMP_MOS 18 +#define ADC_IND_TEMP_MOTOR 16 +#define ADC_IND_SW_DET 15 + +// ADC macros and settings + +// Component parameters (can be overridden) +#ifndef V_REG +#define V_REG 3.3 +#endif +#ifndef VIN_R1 +#define VIN_R1 150000.0 +#endif +#ifndef VIN_R2 +#define VIN_R2 4700.0 +#endif +#ifndef CURRENT_AMP_GAIN +#define CURRENT_AMP_GAIN 20.0 +#endif +#ifndef CURRENT_SHUNT_RES +#define CURRENT_SHUNT_RES 0.00025 +#endif + +#define ENCODER_SIN_VOLTS ADC_VOLTS(ADC_IND_EXT4) +#define ENCODER_COS_VOLTS ADC_VOLTS(ADC_IND_EXT5) + +// Input voltage +#define GET_INPUT_VOLTAGE() ((V_REG / 4095.0) * (float)ADC_Value[ADC_IND_VIN_SENS] * ((VIN_R1 + VIN_R2) / VIN_R2)) + +// NTC Termistors +#define NTC_RES(adc_val) (10000.0 / ((4095.0 / (float)adc_val) - 1.0)) +#define NTC_TEMP(adc_ind) (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15) + +#define NTC_RES_MOTOR(adc_val) (10000.0 / ((4095.0 / (float)adc_val) - 1.0)) // Motor temp sensor on low side +#define NTC_TEMP_MOTOR(beta) (1.0 / ((logf(NTC_RES_MOTOR(ADC_Value[ADC_IND_TEMP_MOTOR]) / 10000.0) / beta) + (1.0 / 298.15)) - 273.15) + +// Voltage on ADC channel +#define ADC_VOLTS(ch) ((float)ADC_Value[ch] / 4096.0 * V_REG) + +// COMM-port ADC GPIOs +#define HW_ADC_EXT_GPIO GPIOA +#define HW_ADC_EXT_PIN 7 +#define HW_ADC_EXT2_GPIO GPIOA +#define HW_ADC_EXT2_PIN 6 +#define HW_ADC_EXT4_GPIO GPIOC +#define HW_ADC_EXT4_PIN 4 +#define HW_ADC_EXT5_GPIO GPIOB +#define HW_ADC_EXT5_PIN 1 + +// UART Peripheral +#define HW_UART_DEV SD3 +#define HW_UART_GPIO_AF GPIO_AF_USART3 +#define HW_UART_TX_PORT GPIOB +#define HW_UART_TX_PIN 10 +#define HW_UART_RX_PORT GPIOB +#define HW_UART_RX_PIN 11 + +// Permanent UART Peripheral (SWD/ESP) +// TODO: Encoder UART +//#define HW_UART_P_BAUD 115200 +//#define HW_UART_P_DEV SD4 +//#define HW_UART_P_GPIO_AF GPIO_AF_UART4 +//#define HW_UART_P_TX_PORT GPIOC +//#define HW_UART_P_TX_PIN 10 +//#define HW_UART_P_RX_PORT GPIOC +//#define HW_UART_P_RX_PIN 11 + +// ICU Peripheral for servo decoding +#define HW_USE_SERVO_TIM4 +#define HW_ICU_TIMER TIM4 +#define HW_ICU_TIM_CLK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE) +#define HW_ICU_DEV ICUD4 +#define HW_ICU_CHANNEL ICU_CHANNEL_1 +#define HW_ICU_GPIO_AF GPIO_AF_TIM4 +#define HW_ICU_GPIO GPIOB +#define HW_ICU_PIN 6 + +// I2C Peripheral +#define HW_I2C_DEV I2CD2 +#define HW_I2C_GPIO_AF GPIO_AF_I2C2 +#define HW_I2C_SCL_PORT GPIOB +#define HW_I2C_SCL_PIN 10 +#define HW_I2C_SDA_PORT GPIOB +#define HW_I2C_SDA_PIN 11 + +// Hall/encoder pins +#define HW_HALL_ENC_GPIO1 GPIOC +#define HW_HALL_ENC_PIN1 6 +#define HW_HALL_ENC_GPIO2 GPIOC +#define HW_HALL_ENC_PIN2 7 +#define HW_HALL_ENC_GPIO3 GPIOC +#define HW_HALL_ENC_PIN3 8 +#define HW_ENC_TIM TIM3 +#define HW_ENC_TIM_AF GPIO_AF_TIM3 +#define HW_ENC_TIM_CLK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE) +#define HW_ENC_EXTI_PORTSRC EXTI_PortSourceGPIOC +#define HW_ENC_EXTI_PINSRC EXTI_PinSource8 +#define HW_ENC_EXTI_CH EXTI9_5_IRQn +#define HW_ENC_EXTI_LINE EXTI_Line8 +#define HW_ENC_EXTI_ISR_VEC EXTI9_5_IRQHandler +#define HW_ENC_TIM_ISR_CH TIM3_IRQn +#define HW_ENC_TIM_ISR_VEC TIM3_IRQHandler + +// SPI pins +#define HW_SPI_DEV SPID1 +#define HW_SPI_GPIO_AF GPIO_AF_SPI1 +#define HW_SPI_PORT_NSS GPIOB +#define HW_SPI_PIN_NSS 11 +//#define HW_SPI_PORT_SCK GPIOA +//#define HW_SPI_PIN_SCK 5 +#define HW_SPI_PORT_MOSI GPIOB +#define HW_SPI_PIN_MOSI 10 +#define HW_SPI_PORT_MISO GPIOA +#define HW_SPI_PIN_MISO 6 + +// IMU +#define LSM6DS3_NSS_GPIO GPIOA +#define LSM6DS3_NSS_PIN 15 +#define LSM6DS3_SCK_GPIO GPIOB +#define LSM6DS3_SCK_PIN 3 +#define LSM6DS3_MOSI_GPIO GPIOB +#define LSM6DS3_MOSI_PIN 5 +#define LSM6DS3_MISO_GPIO GPIOB +#define LSM6DS3_MISO_PIN 4 +#define IMU_FLIP + +// Measurement macros +#define ADC_V_L1 ADC_Value[ADC_IND_SENS1] +#define ADC_V_L2 ADC_Value[ADC_IND_SENS2] +#define ADC_V_L3 ADC_Value[ADC_IND_SENS3] +#define ADC_V_ZERO (ADC_Value[ADC_IND_VIN_SENS] / 2) + +// Macros +#define READ_HALL1() palReadPad(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1) +#define READ_HALL2() palReadPad(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2) +#define READ_HALL3() palReadPad(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3) + +#define HW_DEAD_TIME_NSEC 300.0 + +// Default setting overrides +#ifndef MCCONF_L_MIN_VOLTAGE +#define MCCONF_L_MIN_VOLTAGE 14.0 // Minimum input voltage +#endif +#ifndef MCCONF_L_MAX_VOLTAGE +#define MCCONF_L_MAX_VOLTAGE 94.0 // Maximum input voltage +#endif +#ifndef MCCONF_FOC_F_ZV +#define MCCONF_FOC_F_ZV 30000.0 +#endif +#ifndef MCCONF_L_MAX_ABS_CURRENT +#define MCCONF_L_MAX_ABS_CURRENT 120.0 // The maximum absolute current above which a fault is generated +#endif +#ifndef MCCONF_FOC_SAMPLE_V0_V7 +#define MCCONF_FOC_SAMPLE_V0_V7 false // Run control loop in both v0 and v7 (requires phase shunts) +#endif +#ifndef MCCONF_L_IN_CURRENT_MAX +#define MCCONF_L_IN_CURRENT_MAX 150.0 // Input current limit in Amperes (Upper) +#endif +#ifndef MCCONF_L_IN_CURRENT_MIN +#define MCCONF_L_IN_CURRENT_MIN -150.0 // Input current limit in Amperes (Lower) +#endif +#ifndef APPCONF_APP_TO_USE +#define APPCONF_APP_TO_USE APP_NONE +#endif + +// Setting limits +#define HW_LIM_CURRENT -200.0, 200.0 +#define HW_LIM_CURRENT_IN -200.0, 200.0 +#define HW_LIM_CURRENT_ABS 0.0, 300.0 +#define HW_LIM_VIN 14.0, 97.0 +#define HW_LIM_ERPM -200e3, 200e3 +#define HW_LIM_DUTY_MIN 0.0, 0.1 +#define HW_LIM_DUTY_MAX 0.0, 0.99 +#define HW_LIM_TEMP_FET -40.0, 110.0 + +// Functions +void smart_switch_thread_start(void); +void smart_switch_pin_init(void); +bool smart_switch_is_pressed(void); +void smart_switch_shut_down(void); +void smart_switch_keep_on(void); + +#endif /* HW_CLASSIC_CORE_H_ */ diff --git a/hwconf/vesc/classic/hw_classic_no_limits.h b/hwconf/vesc/classic/hw_classic_no_limits.h new file mode 100644 index 0000000000..57e9315288 --- /dev/null +++ b/hwconf/vesc/classic/hw_classic_no_limits.h @@ -0,0 +1,29 @@ +/* + Copyright 2025 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_CLASSIC_NO_LIMITS_H_ +#define HW_CLASSIC_NO_LIMITS_H_ + +#define HWCLASSIC + +#define DISABLE_HW_LIMITS + +#include "hw_classic_core.h" + +#endif /* HW_CLASSIC_NO_LIMITS_H_ */ diff --git a/hwconf/vesc/classicp/hw_classicp.h b/hwconf/vesc/classicp/hw_classicp.h new file mode 100644 index 0000000000..ddf5d529ef --- /dev/null +++ b/hwconf/vesc/classicp/hw_classicp.h @@ -0,0 +1,27 @@ +/* + Copyright 2026 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_CLASSICP_H_ +#define HW_CLASSICP_H_ + +#define HWCLASSICP + +#include "hw_classicp_core.h" + +#endif /* HW_CLASSICP_H_ */ diff --git a/hwconf/vesc/classicp/hw_classicp_core.c b/hwconf/vesc/classicp/hw_classicp_core.c new file mode 100644 index 0000000000..954a086ff2 --- /dev/null +++ b/hwconf/vesc/classicp/hw_classicp_core.c @@ -0,0 +1,549 @@ +/* + Copyright 2026 Benjamin Vedder benjamin@vedder.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "hw.h" +#include "ch.h" +#include "hal.h" +#include "stm32f4xx_conf.h" +#include "utils_math.h" +#include +#include "mc_interface.h" +#include "ledpwm.h" +#include "utils_math.h" +#include "main.h" +#include "app.h" +#include "comm_can.h" +#include "utils.h" +#include "shutdown.h" + +typedef enum { + SWITCH_BOOTED = 0, + SWITCH_TURN_ON_DELAY_ACTIVE, + SWITCH_HELD_AFTER_TURN_ON, + SWITCH_TURNED_ON, + SWITCH_SHUTTING_DOWN, +} switch_states; + +// Variables +static THD_WORKING_AREA(smart_switch_thread_wa, 256); +static THD_WORKING_AREA(switch_color_thread_wa, 256); +static THD_FUNCTION(switch_color_thread, arg); +static volatile switch_states switch_state = SWITCH_BOOTED; + +static volatile float switch_bright = 0.75; +static bool switch_color_thd_running = false; +static volatile bool i2c_running = false; + +// I2C configuration +static const I2CConfig i2cfg = { + OPMODE_I2C, + 100000, + STD_DUTY_CYCLE +}; + +void hw_init_gpio(void) { + // GPIO clock enable + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + + // LEDs + palSetPadMode(LED_GREEN_GPIO, LED_GREEN_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(LED_RED_GPIO, LED_RED_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + + // GPIOA Configuration: Channel 1 to 3 as alternate function push-pull + palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOA, 10, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + // Hall sensors + palSetPadMode(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3, PAL_MODE_INPUT_PULLUP); + + // Phase filters + palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + PHASE_FILTER_OFF(); + + palSetPadMode(CURRENT_FILTER_GPIO, CURRENT_FILTER_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + CURRENT_FILTER_OFF(); + + // AUX pins + AUX_OFF(); + palSetPadMode(AUX_GPIO, AUX_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + + // ADC Pins + palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 7, PAL_MODE_INPUT_ANALOG); + + palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOB, 1, PAL_MODE_INPUT_ANALOG); + + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG); +} + +void hw_setup_adc_channels(void) { + // ADC1 regular channels + ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); // 0 Curr 1 + ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_15Cycles); // 3 Volt 1 + ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, ADC_SampleTime_15Cycles); // 6 EXT + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_15Cycles); // 9 EXT4 + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_15Cycles); // 12 EXT4 + ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_15Cycles); // 15 Smart Switch + ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 7, ADC_SampleTime_15Cycles); // 18 TEMP_MOS + + // ADC2 regular channels + ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); // 1 Curr 2 + ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 2, ADC_SampleTime_15Cycles); // 4 Volt 2 + ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 3, ADC_SampleTime_15Cycles); // 7 EXT2 + ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 4, ADC_SampleTime_15Cycles); // 10 EXT5 + ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 5, ADC_SampleTime_15Cycles); // 13 EXT5 + ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 6, ADC_SampleTime_15Cycles); // 16 Temp Motor + ADC_RegularChannelConfig(ADC2, ADC_Channel_3, 7, ADC_SampleTime_15Cycles); // 19 TEMP_MOS2 + + // ADC3 regular channels + ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); // 2 Curr 3 + ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 2, ADC_SampleTime_15Cycles); // 5 Volt 3 + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 3, ADC_SampleTime_15Cycles); // 8 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 4, ADC_SampleTime_15Cycles); // 11 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 5, ADC_SampleTime_15Cycles); // 14 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 6, ADC_SampleTime_15Cycles); // 17 Volt In + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 7, ADC_SampleTime_15Cycles); // 20 Volt In + + // Injected channels + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 3, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 3, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_15Cycles); + + if (!switch_color_thd_running) { + chThdCreateStatic(switch_color_thread_wa, sizeof(switch_color_thread_wa), LOWPRIO, switch_color_thread, NULL); + switch_color_thd_running = true; + } +} + +void hw_start_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (!i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + i2cStart(&HW_I2C_DEV, &i2cfg); + i2c_running = true; + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +void hw_stop_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, PAL_MODE_INPUT); + + i2cStop(&HW_I2C_DEV); + i2c_running = false; + + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +/** + * Try to restore the i2c bus + */ +void hw_try_restore_i2c(void) { + if (i2c_running) { + i2cAcquireBus(&HW_I2C_DEV); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + chThdSleep(1); + + for(int i = 0;i < 16;i++) { + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + } + + // Generate start then stop condition + palClearPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + chThdSleep(1); + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + HW_I2C_DEV.state = I2C_STOP; + i2cStart(&HW_I2C_DEV, &i2cfg); + + i2cReleaseBus(&HW_I2C_DEV); + } +} + +void smart_switch_keep_on(void) { + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + //#ifdef HW_HAS_RGB_SWITCH + // LED_SWITCH_B_ON(); + // ledpwm_set_intensity(SWITCH_LED_B, 1.0); + //#else + // ledpwm_set_intensity(SWITCH_LED, 1.0); + // ledpwm_set_switch_intensity(0.6); + //#endif +} + +void smart_switch_shut_down(void) { + mc_interface_select_motor_thread(2); + mc_interface_set_current(0); + mc_interface_lock(); + mc_interface_select_motor_thread(1); + mc_interface_set_current(0); + mc_interface_lock(); + switch_state = SWITCH_SHUTTING_DOWN; + palClearPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + return; +} + +bool smart_switch_is_pressed(void) { + if (ADC_VOLTS(ADC_IND_SW_DET) > 0.9 && + (mc_interface_temp_fet_filtered() < 68.0) /* why?? */) { + return true; + } else { + return false; + } +} + +static THD_FUNCTION(switch_color_thread, arg) { + (void)arg; + chRegSetThreadName("switch_color"); + float switch_red = 0.0; + float switch_green = 0.0; + float switch_blue = 0.0; + + for(int i = 0; i < 400; i++) { + float angle = i*3.14/400.0; + float s,c; + utils_fast_sincos_better(angle, &s, &c); + switch_blue = 0.75* c*c; + ledpwm_set_intensity(LED_HW1,switch_bright*switch_blue); + utils_fast_sincos_better(angle + 3.14/3.0, &s, &c); + switch_green = 0.75* c*c; + ledpwm_set_intensity(LED_HW2,switch_bright*switch_green); + utils_fast_sincos_better(angle + 6.28/3.0, &s, &c); + switch_red = 0.75* c*c; + ledpwm_set_intensity(LED_HW3,switch_bright*switch_red); + chThdSleepMilliseconds(4); + } + float switch_red_old = switch_red_old; + float switch_green_old = switch_green; + float switch_blue_old = switch_blue; + float wh_left; + float left = mc_interface_get_battery_level(&wh_left); + + if (left < 0.5) { + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + } else { + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + } + + for (int i = 0; i < 100; i++) { + float red_now = utils_map((float) i,0.0, 100.0, switch_red_old, switch_red); + float blue_now = utils_map((float) i,0.0, 100.0, switch_blue_old, switch_blue); + float green_now = utils_map((float) i,0.0, 100.0, switch_green_old, switch_green); + ledpwm_set_intensity(LED_HW1, switch_bright*blue_now); + ledpwm_set_intensity(LED_HW2, switch_bright*green_now); + ledpwm_set_intensity(LED_HW3, switch_bright*red_now); + chThdSleepMilliseconds(2); + } + + for (;;) { + mc_fault_code fault = mc_interface_get_fault(); + mc_interface_select_motor_thread(2); + mc_fault_code fault2 = mc_interface_get_fault(); + mc_interface_select_motor_thread(1); + + if (fault != FAULT_CODE_NONE || fault2 != FAULT_CODE_NONE) { + ledpwm_set_intensity(LED_HW2, 0); + ledpwm_set_intensity(LED_HW1, 0); + for (int i = 0;i < (int)fault;i++) { + ledpwm_set_intensity(LED_HW3, 1.0); + chThdSleepMilliseconds(250); + ledpwm_set_intensity(LED_HW3, 0.0); + chThdSleepMilliseconds(250); + } + + chThdSleepMilliseconds(500); + + for (int i = 0;i < (int)fault2;i++) { + ledpwm_set_intensity(LED_HW3, 1.0); + chThdSleepMilliseconds(250); + ledpwm_set_intensity(LED_HW3, 0.0); + chThdSleepMilliseconds(250); + } + + chThdSleepMilliseconds(500); + } else { + left = mc_interface_get_battery_level(&wh_left); + if(left < 0.5){ + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + switch_green = 0; + }else{ + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + switch_red = 0; + } + ledpwm_set_intensity(LED_HW1, switch_bright*switch_blue); + ledpwm_set_intensity(LED_HW2, switch_bright*switch_green); + ledpwm_set_intensity(LED_HW3, switch_bright*switch_red); + } + + // Config check + mc_configuration *mcconf = (mc_configuration*)mc_interface_get_configuration(); + + if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_HALL) { + // In hall sensor mode we use the ADC pins on the comm-port as additional + // pull-ups as the voltage dividers take the voltage down otherwise. + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(HW_ADC_EXT5_GPIO, HW_ADC_EXT5_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN); + palSetPad(HW_ADC_EXT5_GPIO, HW_ADC_EXT5_PIN); + } else if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_ENCODER) { + // Ensure that the sin/cos pins are in ADC mode + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_INPUT_ANALOG); + palSetPadMode(HW_ADC_EXT5_GPIO, HW_ADC_EXT5_PIN, PAL_MODE_INPUT_ANALOG); + } + } + + chThdSleepMilliseconds(20); + } +} + +static THD_FUNCTION(smart_switch_thread, arg) { + (void)arg; + chRegSetThreadName("smart_switch"); + unsigned int millis_switch_pressed = 0; + + for (;;) { + const app_configuration *conf = app_get_configuration(); + + switch (switch_state) { + case SWITCH_BOOTED: + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + case SWITCH_TURN_ON_DELAY_ACTIVE: + switch_state = SWITCH_HELD_AFTER_TURN_ON; + mc_interface_select_motor_thread(2); + mc_interface_set_current(0); + mc_interface_lock(); + mc_interface_select_motor_thread(1); + mc_interface_set_current(0); + mc_interface_lock(); + + mc_interface_select_motor_thread(2); + mc_interface_unlock(); + mc_interface_select_motor_thread(1); + mc_interface_unlock(); + + // Wait for other systems to boot up before proceeding + while (!main_init_done()) { + chThdSleepMilliseconds(200); + } + break; + + case SWITCH_HELD_AFTER_TURN_ON: + if (smart_switch_is_pressed() && conf->shutdown_mode != SHUTDOWN_MODE_ALWAYS_OFF) { + switch_state = SWITCH_HELD_AFTER_TURN_ON; + } else { + switch_state = SWITCH_TURNED_ON; + } + break; + + case SWITCH_TURNED_ON: + if (conf->shutdown_mode == SHUTDOWN_MODE_ALWAYS_OFF) { + switch_bright = 1.0; + if (!smart_switch_is_pressed()) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } else { + if (smart_switch_is_pressed()) { + millis_switch_pressed++; + switch_bright = 0.5; + } else { + millis_switch_pressed = 0; + switch_bright = 1.0; + } + + if (millis_switch_pressed > SMART_SWITCH_MSECS_PRESSED_OFF) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } + break; + + case SWITCH_SHUTTING_DOWN: + switch_bright = 0; + systime_t tStart = chVTGetSystemTimeX(); + while (smart_switch_is_pressed()) { + chThdSleepMilliseconds(10); + if (UTILS_AGE_S(tStart) > 10.0) { + millis_switch_pressed = 0; + switch_state = SWITCH_TURNED_ON; + break; + } + } + + if (switch_state == SWITCH_TURNED_ON) { + break; + } + + shutdown_save_and_hold(); + comm_can_shutdown(255); + smart_switch_shut_down(); + chThdSleepMilliseconds(10000); + smart_switch_keep_on(); + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + default: + break; + } + + chThdSleepMilliseconds(1); + } +} + +void smart_switch_thread_start(void) { + chThdCreateStatic(smart_switch_thread_wa, sizeof(smart_switch_thread_wa), + NORMALPRIO, smart_switch_thread, NULL); +} + +void smart_switch_pin_init(void) { + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); + + palSetPadMode(SWITCH_OUT_GPIO,SWITCH_OUT_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_2_GPIO,SWITCH_LED_2_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + LED_SWITCH_B_ON(); + LED_SWITCH_R_OFF(); + LED_SWITCH_G_OFF(); + return; +} + +float hw_classicp_get_temp(void) { + float t1 = (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15); + float t2 = (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS_2]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15); + float res = 0.0; + + if (t1 > t2) { + res = t1; + } else { + res = t2; + } + + return res; +} diff --git a/hwconf/vesc/classicp/hw_classicp_core.h b/hwconf/vesc/classicp/hw_classicp_core.h new file mode 100644 index 0000000000..0d903f4853 --- /dev/null +++ b/hwconf/vesc/classicp/hw_classicp_core.h @@ -0,0 +1,304 @@ +/* + Copyright 2026 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_CLASSICP_CORE_H_ +#define HW_CLASSICP_CORE_H_ + +#ifdef HWCLASSICP + #define HW_NAME "Classicp" +#else + #error "Must define hardware type" +#endif + +// HW properties +#define HW_HAS_3_SHUNTS +#define HW_HAS_PHASE_FILTERS +#define HW_HAS_PHASE_SHUNTS + +// Macros +#define LED_GREEN_GPIO GPIOC +#define LED_GREEN_PIN 9 +#define LED_RED_GPIO GPIOC +#define LED_RED_PIN 12 + +#define LED_GREEN_ON() palSetPad(LED_GREEN_GPIO, LED_GREEN_PIN) +#define LED_GREEN_OFF() palClearPad(LED_GREEN_GPIO, LED_GREEN_PIN) +#define LED_RED_ON() palSetPad(LED_RED_GPIO, LED_RED_PIN) +#define LED_RED_OFF() palClearPad(LED_RED_GPIO, LED_RED_PIN) + +#define PHASE_FILTER_OFF() palClearPad(GPIOB, 12) +#define PHASE_FILTER_ON() palSetPad(GPIOB, 12) + +#define CURRENT_FILTER_GPIO GPIOC +#define CURRENT_FILTER_PIN 15 +#define CURRENT_FILTER_ON() palSetPad(CURRENT_FILTER_GPIO, CURRENT_FILTER_PIN) +#define CURRENT_FILTER_OFF() palClearPad(CURRENT_FILTER_GPIO, CURRENT_FILTER_PIN) + +#define AUX_GPIO GPIOC +#define AUX_PIN 14 +#define AUX_ON() palSetPad(AUX_GPIO, AUX_PIN) +#define AUX_OFF() palClearPad(AUX_GPIO, AUX_PIN) + +#define HW_SHUTDOWN_HOLD_ON(); +#define HW_SAMPLE_SHUTDOWN() 1 +#define HW_SHUTDOWN_HOLD_OFF() palClearPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); +#define HW_SHUTDOWN_NO + +#define DCCAL_ON() +#define DCCAL_OFF() + +#define HW_EARLY_INIT() smart_switch_pin_init(); \ + smart_switch_thread_start(); + +// Switch Pins +#define HW_HAS_RGB_SWITCH + +#define SMART_SWITCH_MSECS_PRESSED_OFF 2000 + +#define SWITCH_OUT_GPIO GPIOB +#define SWITCH_OUT_PIN 2 +#define SWITCH_LED_3_GPIO GPIOD +#define SWITCH_LED_3_PIN 2 +#define SWITCH_LED_2_GPIO GPIOC +#define SWITCH_LED_2_PIN 13 +#define SWITCH_LED_1_GPIO GPIOB +#define SWITCH_LED_1_PIN 7 + +#define LED_PWM1_ON() palClearPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM1_OFF() palSetPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM2_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM2_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM3_ON() palClearPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) +#define LED_PWM3_OFF() palSetPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) + +#define LED_SWITCH_R_ON() palClearPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_R_OFF() palSetPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_G_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_G_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_B_ON() palClearPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) +#define LED_SWITCH_B_OFF() palSetPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) + +/* + * ADC Vector + */ +#define HW_ADC_NBR_CONV 7 +#define HW_ADC_CHANNELS (HW_ADC_NBR_CONV * 3) +#define HW_ADC_INJ_CHANNELS 3 + +// ADC Indicies +#define ADC_IND_CURR1 0 +#define ADC_IND_CURR2 1 +#define ADC_IND_CURR3 2 +#define ADC_IND_SENS1 3 +#define ADC_IND_SENS2 4 +#define ADC_IND_SENS3 5 +#define ADC_IND_VIN_SENS 14 +#define ADC_IND_EXT 6 +#define ADC_IND_EXT2 7 +#define ADC_IND_EXT4 12 +#define ADC_IND_EXT5 13 +#define ADC_IND_TEMP_MOS 18 +#define ADC_IND_TEMP_MOS_2 19 +#define ADC_IND_TEMP_MOTOR 16 +#define ADC_IND_SW_DET 15 + +// ADC macros and settings + +// Component parameters (can be overridden) +#ifndef V_REG +#define V_REG 3.3 +#endif +#ifndef VIN_R1 +#define VIN_R1 150000.0 +#endif +#ifndef VIN_R2 +#define VIN_R2 4700.0 +#endif +#ifndef CURRENT_AMP_GAIN +#define CURRENT_AMP_GAIN 20.0 +#endif +#ifndef CURRENT_SHUNT_RES +#define CURRENT_SHUNT_RES (0.00025 / 2.0) +#endif + +#define ENCODER_SIN_VOLTS ADC_VOLTS(ADC_IND_EXT4) +#define ENCODER_COS_VOLTS ADC_VOLTS(ADC_IND_EXT5) + +// Input voltage +#define GET_INPUT_VOLTAGE() ((V_REG / 4095.0) * (float)ADC_Value[ADC_IND_VIN_SENS] * ((VIN_R1 + VIN_R2) / VIN_R2)) + +// NTC Termistors +#define NTC_RES(adc_val) (10000.0 / ((4095.0 / (float)adc_val) - 1.0)) +#define NTC_TEMP(adc_ind) hw_classicp_get_temp() + +#define NTC_RES_MOTOR(adc_val) (10000.0 / ((4095.0 / (float)adc_val) - 1.0)) // Motor temp sensor on low side +#define NTC_TEMP_MOTOR(beta) (1.0 / ((logf(NTC_RES_MOTOR(ADC_Value[ADC_IND_TEMP_MOTOR]) / 10000.0) / beta) + (1.0 / 298.15)) - 273.15) + +#define NTC_TEMP_MOS1() (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15) +#define NTC_TEMP_MOS2() (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS_2]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15) +#define NTC_TEMP_MOS3() NTC_TEMP_MOS2() + +// Voltage on ADC channel +#define ADC_VOLTS(ch) ((float)ADC_Value[ch] / 4096.0 * V_REG) + +// COMM-port ADC GPIOs +#define HW_ADC_EXT_GPIO GPIOA +#define HW_ADC_EXT_PIN 7 +#define HW_ADC_EXT2_GPIO GPIOA +#define HW_ADC_EXT2_PIN 6 +#define HW_ADC_EXT4_GPIO GPIOC +#define HW_ADC_EXT4_PIN 4 +#define HW_ADC_EXT5_GPIO GPIOB +#define HW_ADC_EXT5_PIN 1 + +// UART Peripheral +#define HW_UART_DEV SD3 +#define HW_UART_GPIO_AF GPIO_AF_USART3 +#define HW_UART_TX_PORT GPIOB +#define HW_UART_TX_PIN 10 +#define HW_UART_RX_PORT GPIOB +#define HW_UART_RX_PIN 11 + +// Permanent UART Peripheral (SWD/ESP) +// TODO: Encoder UART +//#define HW_UART_P_BAUD 115200 +//#define HW_UART_P_DEV SD4 +//#define HW_UART_P_GPIO_AF GPIO_AF_UART4 +//#define HW_UART_P_TX_PORT GPIOC +//#define HW_UART_P_TX_PIN 10 +//#define HW_UART_P_RX_PORT GPIOC +//#define HW_UART_P_RX_PIN 11 + +// ICU Peripheral for servo decoding +#define HW_USE_SERVO_TIM4 +#define HW_ICU_TIMER TIM4 +#define HW_ICU_TIM_CLK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE) +#define HW_ICU_DEV ICUD4 +#define HW_ICU_CHANNEL ICU_CHANNEL_1 +#define HW_ICU_GPIO_AF GPIO_AF_TIM4 +#define HW_ICU_GPIO GPIOB +#define HW_ICU_PIN 6 + +// I2C Peripheral +#define HW_I2C_DEV I2CD2 +#define HW_I2C_GPIO_AF GPIO_AF_I2C2 +#define HW_I2C_SCL_PORT GPIOB +#define HW_I2C_SCL_PIN 10 +#define HW_I2C_SDA_PORT GPIOB +#define HW_I2C_SDA_PIN 11 + +// Hall/encoder pins +#define HW_HALL_ENC_GPIO1 GPIOC +#define HW_HALL_ENC_PIN1 6 +#define HW_HALL_ENC_GPIO2 GPIOC +#define HW_HALL_ENC_PIN2 7 +#define HW_HALL_ENC_GPIO3 GPIOC +#define HW_HALL_ENC_PIN3 8 +#define HW_ENC_TIM TIM3 +#define HW_ENC_TIM_AF GPIO_AF_TIM3 +#define HW_ENC_TIM_CLK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE) +#define HW_ENC_EXTI_PORTSRC EXTI_PortSourceGPIOC +#define HW_ENC_EXTI_PINSRC EXTI_PinSource8 +#define HW_ENC_EXTI_CH EXTI9_5_IRQn +#define HW_ENC_EXTI_LINE EXTI_Line8 +#define HW_ENC_EXTI_ISR_VEC EXTI9_5_IRQHandler +#define HW_ENC_TIM_ISR_CH TIM3_IRQn +#define HW_ENC_TIM_ISR_VEC TIM3_IRQHandler + +// SPI pins +#define HW_SPI_DEV SPID1 +#define HW_SPI_GPIO_AF GPIO_AF_SPI1 +#define HW_SPI_PORT_NSS GPIOB +#define HW_SPI_PIN_NSS 11 +//#define HW_SPI_PORT_SCK GPIOA +//#define HW_SPI_PIN_SCK 5 +#define HW_SPI_PORT_MOSI GPIOB +#define HW_SPI_PIN_MOSI 10 +#define HW_SPI_PORT_MISO GPIOA +#define HW_SPI_PIN_MISO 6 + +// IMU +#define LSM6DS3_NSS_GPIO GPIOA +#define LSM6DS3_NSS_PIN 15 +#define LSM6DS3_SCK_GPIO GPIOB +#define LSM6DS3_SCK_PIN 3 +#define LSM6DS3_MOSI_GPIO GPIOB +#define LSM6DS3_MOSI_PIN 5 +#define LSM6DS3_MISO_GPIO GPIOB +#define LSM6DS3_MISO_PIN 4 +#define IMU_FLIP + +// Measurement macros +#define ADC_V_L1 ADC_Value[ADC_IND_SENS1] +#define ADC_V_L2 ADC_Value[ADC_IND_SENS2] +#define ADC_V_L3 ADC_Value[ADC_IND_SENS3] +#define ADC_V_ZERO (ADC_Value[ADC_IND_VIN_SENS] / 2) + +// Macros +#define READ_HALL1() palReadPad(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1) +#define READ_HALL2() palReadPad(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2) +#define READ_HALL3() palReadPad(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3) + +#define HW_DEAD_TIME_NSEC 300.0 + +// Default setting overrides +#ifndef MCCONF_L_MIN_VOLTAGE +#define MCCONF_L_MIN_VOLTAGE 14.0 // Minimum input voltage +#endif +#ifndef MCCONF_L_MAX_VOLTAGE +#define MCCONF_L_MAX_VOLTAGE 94.0 // Maximum input voltage +#endif +#ifndef MCCONF_FOC_F_ZV +#define MCCONF_FOC_F_ZV 30000.0 +#endif +#ifndef MCCONF_L_MAX_ABS_CURRENT +#define MCCONF_L_MAX_ABS_CURRENT 120.0 // The maximum absolute current above which a fault is generated +#endif +#ifndef MCCONF_FOC_SAMPLE_V0_V7 +#define MCCONF_FOC_SAMPLE_V0_V7 false // Run control loop in both v0 and v7 (requires phase shunts) +#endif +#ifndef MCCONF_L_IN_CURRENT_MAX +#define MCCONF_L_IN_CURRENT_MAX 150.0 // Input current limit in Amperes (Upper) +#endif +#ifndef MCCONF_L_IN_CURRENT_MIN +#define MCCONF_L_IN_CURRENT_MIN -150.0 // Input current limit in Amperes (Lower) +#endif +#ifndef APPCONF_APP_TO_USE +#define APPCONF_APP_TO_USE APP_NONE +#endif + +// Setting limits +#define HW_LIM_CURRENT -410.0, 410.0 +#define HW_LIM_CURRENT_IN -410.0, 410.0 +#define HW_LIM_CURRENT_ABS 0.0, 600.0 +#define HW_LIM_VIN 14.0, 97.0 +#define HW_LIM_ERPM -200e3, 200e3 +#define HW_LIM_DUTY_MIN 0.0, 0.1 +#define HW_LIM_DUTY_MAX 0.0, 0.99 +#define HW_LIM_TEMP_FET -40.0, 110.0 + +// Functions +void smart_switch_thread_start(void); +void smart_switch_pin_init(void); +bool smart_switch_is_pressed(void); +void smart_switch_shut_down(void); +void smart_switch_keep_on(void); +float hw_classicp_get_temp(void); + +#endif /* HW_CLASSICP_CORE_H_ */ diff --git a/hwconf/vesc/classicp/hw_classicp_no_limits.h b/hwconf/vesc/classicp/hw_classicp_no_limits.h new file mode 100644 index 0000000000..15d09c07ea --- /dev/null +++ b/hwconf/vesc/classicp/hw_classicp_no_limits.h @@ -0,0 +1,29 @@ +/* + Copyright 2026 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_CLASSICP_NO_LIMITS_H_ +#define HW_CLASSICP_NO_LIMITS_H_ + +#define HWCLASSICP + +#define DISABLE_HW_LIMITS + +#include "hw_classicp_core.h" + +#endif /* HW_CLASSICP_NO_LIMITS_H_ */ diff --git a/hwconf/vesc/duet/hw_duet_core.c b/hwconf/vesc/duet/hw_duet_core.c index 010b3ae44d..a50369e140 100644 --- a/hwconf/vesc/duet/hw_duet_core.c +++ b/hwconf/vesc/duet/hw_duet_core.c @@ -23,6 +23,9 @@ #include "ledpwm.h" #include "utils_math.h" #include "main.h" +#include "app.h" +#include "utils.h" +#include "shutdown.h" typedef enum { SWITCH_BOOTED = 0, @@ -34,9 +37,9 @@ typedef enum { // Variables static volatile bool i2c_running = false; -static THD_WORKING_AREA(smart_switch_thread_wa, 128); +static THD_WORKING_AREA(smart_switch_thread_wa, 256); static THD_WORKING_AREA(mux_thread_wa, 256); -static THD_WORKING_AREA(switch_color_thread_wa, 128); +static THD_WORKING_AREA(switch_color_thread_wa, 256); static THD_FUNCTION(mux_thread, arg); static THD_FUNCTION(switch_color_thread, arg); static volatile switch_states switch_state = SWITCH_BOOTED; @@ -382,10 +385,12 @@ void smart_switch_shut_down(void) { } bool smart_switch_is_pressed(void) { - if(palReadPad(SWITCH_IN_GPIO, SWITCH_IN_PIN) == 1 && (mc_interface_temp_fet_filtered() < 68.0)) + if (palReadPad(SWITCH_IN_GPIO, SWITCH_IN_PIN) == 1 && + (mc_interface_temp_fet_filtered() < 68.0) /* why?? */) { return true; - else + } else { return false; + } } static THD_FUNCTION(switch_color_thread, arg) { @@ -414,18 +419,20 @@ static THD_FUNCTION(switch_color_thread, arg) { float switch_blue_old = switch_blue; float wh_left; float left = mc_interface_get_battery_level(&wh_left); - if(left < 0.5){ + + if (left < 0.5) { float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); utils_truncate_number(&intense,0,1); switch_blue = intense; switch_red = 1.0-intense; - }else{ + } else { float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); utils_truncate_number(&intense,0,1); switch_green = intense; switch_blue = 1.0-intense; } - for(int i = 0; i < 100; i++) { + + for (int i = 0; i < 100; i++) { float red_now = utils_map((float) i,0.0, 100.0, switch_red_old, switch_red); float blue_now = utils_map((float) i,0.0, 100.0, switch_blue_old, switch_blue); float green_now = utils_map((float) i,0.0, 100.0, switch_green_old, switch_green); @@ -440,6 +447,7 @@ static THD_FUNCTION(switch_color_thread, arg) { mc_interface_select_motor_thread(2); mc_fault_code fault2 = mc_interface_get_fault(); mc_interface_select_motor_thread(1); + if (fault != FAULT_CODE_NONE || fault2 != FAULT_CODE_NONE) { ledpwm_set_intensity(LED_HW2, 0); ledpwm_set_intensity(LED_HW1, 0); @@ -490,10 +498,13 @@ static THD_FUNCTION(smart_switch_thread, arg) { unsigned int millis_switch_pressed = 0; for (;;) { + const app_configuration *conf = app_get_configuration(); + switch (switch_state) { case SWITCH_BOOTED: switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; break; + case SWITCH_TURN_ON_DELAY_ACTIVE: switch_state = SWITCH_HELD_AFTER_TURN_ON; mc_interface_select_motor_thread(2); @@ -507,45 +518,70 @@ static THD_FUNCTION(smart_switch_thread, arg) { mc_interface_unlock(); mc_interface_select_motor_thread(1); mc_interface_unlock(); - //Wait for other systems to boot up before proceeding + + // Wait for other systems to boot up before proceeding while (!main_init_done()) { chThdSleepMilliseconds(200); } break; + case SWITCH_HELD_AFTER_TURN_ON: - if(smart_switch_is_pressed()){ + if (smart_switch_is_pressed() && conf->shutdown_mode != SHUTDOWN_MODE_ALWAYS_OFF) { switch_state = SWITCH_HELD_AFTER_TURN_ON; } else { switch_state = SWITCH_TURNED_ON; } break; + case SWITCH_TURNED_ON: - if (smart_switch_is_pressed()) { - millis_switch_pressed++; - switch_bright = 0.5; - } else { - millis_switch_pressed = 0; + if (conf->shutdown_mode == SHUTDOWN_MODE_ALWAYS_OFF) { switch_bright = 1.0; - } - - if (millis_switch_pressed > SMART_SWITCH_MSECS_PRESSED_OFF) { - switch_state = SWITCH_SHUTTING_DOWN; + if (!smart_switch_is_pressed()) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } else { + if (smart_switch_is_pressed()) { + millis_switch_pressed++; + switch_bright = 0.5; + } else { + millis_switch_pressed = 0; + switch_bright = 1.0; + } + + if (millis_switch_pressed > SMART_SWITCH_MSECS_PRESSED_OFF) { + switch_state = SWITCH_SHUTTING_DOWN; + } } break; + case SWITCH_SHUTTING_DOWN: switch_bright = 0; + systime_t tStart = chVTGetSystemTimeX(); while (smart_switch_is_pressed()) { chThdSleepMilliseconds(10); + if (UTILS_AGE_S(tStart) > 10.0) { + millis_switch_pressed = 0; + switch_state = SWITCH_TURNED_ON; + break; + } } + + if (switch_state == SWITCH_TURNED_ON) { + break; + } + + shutdown_save_and_hold(); comm_can_shutdown(255); smart_switch_shut_down(); chThdSleepMilliseconds(10000); smart_switch_keep_on(); switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; break; + default: break; } + chThdSleepMilliseconds(1); } } diff --git a/hwconf/vesc/duet/hw_duet_core.h b/hwconf/vesc/duet/hw_duet_core.h index 79b120a770..0c2fd3f8b5 100644 --- a/hwconf/vesc/duet/hw_duet_core.h +++ b/hwconf/vesc/duet/hw_duet_core.h @@ -27,6 +27,7 @@ #define INVERTED_SHUNT_POLARITY #define HW_HAS_3_SHUNTS +#define HW_BOOT_VESC_CAN #define HW_DEAD_TIME_NSEC 300.0 @@ -71,6 +72,7 @@ #define HW_SHUTDOWN_HOLD_ON(); #define HW_SAMPLE_SHUTDOWN() 1 #define HW_SHUTDOWN_HOLD_OFF() palClearPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); +#define HW_SHUTDOWN_NO #define DCCAL_ON() #define DCCAL_OFF() @@ -336,6 +338,9 @@ #ifndef MCCONF_L_MAX_VOLTAGE #define MCCONF_L_MAX_VOLTAGE 92.0 // Maximum input voltage #endif +#ifndef MCCONF_FOC_F_ZV +#define MCCONF_FOC_F_ZV 23000.0 +#endif #define HW_LIM_CURRENT -200.0, 200.0 #define HW_LIM_CURRENT_ABS 0.0, 300.0 diff --git a/hwconf/vesc/duet_xs/hw_duet_xs100.h b/hwconf/vesc/duet_xs/hw_duet_xs100.h new file mode 100644 index 0000000000..80a615cd58 --- /dev/null +++ b/hwconf/vesc/duet_xs/hw_duet_xs100.h @@ -0,0 +1,25 @@ +/* + Copyright 2018 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_DUET_XS100_H_ +#define HW_DUET_XS100_H_ + +#include "hw_duet_xs_core.h" + +#endif /* HW_DUET_XS100_H_ */ diff --git a/hwconf/vesc/duet_xs/hw_duet_xs100_no_limits.h b/hwconf/vesc/duet_xs/hw_duet_xs100_no_limits.h new file mode 100644 index 0000000000..ee75e78bdd --- /dev/null +++ b/hwconf/vesc/duet_xs/hw_duet_xs100_no_limits.h @@ -0,0 +1,27 @@ +/* + Copyright 2018 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_DUET_XS100_NO_LIMITS_H_ +#define HW_DUET_XS100_NO_LIMITS_H_ + +#define DISABLE_HW_LIMITS + +#include "hw_duet_xs_core.h" + +#endif /* HW_DUET_XS100_NO_LIMITS_H_ */ diff --git a/hwconf/vesc/duet_xs/hw_duet_xs60.h b/hwconf/vesc/duet_xs/hw_duet_xs60.h new file mode 100644 index 0000000000..7df3250e84 --- /dev/null +++ b/hwconf/vesc/duet_xs/hw_duet_xs60.h @@ -0,0 +1,27 @@ +/* + Copyright 2018 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_DUET_XS60_H_ +#define HW_DUET_XS60_H_ + +#define HW_XS60 + +#include "hw_duet_xs_core.h" + +#endif /* HW_DUET_XS100_H_ */ diff --git a/hwconf/vesc/duet_xs/hw_duet_xs60_no_limits.h b/hwconf/vesc/duet_xs/hw_duet_xs60_no_limits.h new file mode 100644 index 0000000000..8e6e0b911a --- /dev/null +++ b/hwconf/vesc/duet_xs/hw_duet_xs60_no_limits.h @@ -0,0 +1,28 @@ +/* + Copyright 2018 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_DUET_XS60_NO_LIMITS_H_ +#define HW_DUET_XS60_NO_LIMITS_H_ + +#define HW_XS60 +#define DISABLE_HW_LIMITS + +#include "hw_duet_xs_core.h" + +#endif /* HW_DUET_XS60_NO_LIMITS_H_ */ diff --git a/hwconf/vesc/duet_xs/hw_duet_xs_core.c b/hwconf/vesc/duet_xs/hw_duet_xs_core.c new file mode 100644 index 0000000000..a50369e140 --- /dev/null +++ b/hwconf/vesc/duet_xs/hw_duet_xs_core.c @@ -0,0 +1,610 @@ +/* + Copyright 2016 Benjamin Vedder benjamin@vedder.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include "hw.h" +#include "ch.h" +#include "hal.h" +#include "stm32f4xx_conf.h" +#include "comm_can.h" +#include "mc_interface.h" +#include "ledpwm.h" +#include "utils_math.h" +#include "main.h" +#include "app.h" +#include "utils.h" +#include "shutdown.h" + +typedef enum { + SWITCH_BOOTED = 0, + SWITCH_TURN_ON_DELAY_ACTIVE, + SWITCH_HELD_AFTER_TURN_ON, + SWITCH_TURNED_ON, + SWITCH_SHUTTING_DOWN, +} switch_states; + +// Variables +static volatile bool i2c_running = false; +static THD_WORKING_AREA(smart_switch_thread_wa, 256); +static THD_WORKING_AREA(mux_thread_wa, 256); +static THD_WORKING_AREA(switch_color_thread_wa, 256); +static THD_FUNCTION(mux_thread, arg); +static THD_FUNCTION(switch_color_thread, arg); +static volatile switch_states switch_state = SWITCH_BOOTED; + +static volatile float switch_bright = 0.75; + + + +// I2C configuration +static const I2CConfig i2cfg = { + OPMODE_I2C, + 100000, + STD_DUTY_CYCLE +}; + +void hw_init_gpio(void) { + // GPIO clock enable + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); + + + palSetPadMode(GPIOE, 3, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(GPIOE, 4, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(GPIOE, 6, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + PHASE_FILTER_OFF(); + palSetPadMode(GPIOE, 0, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(GPIOE, 1, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(GPIOE, 2, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + PHASE_FILTER_OFF_M2(); + + palSetPadMode(AUX_GPIO, AUX_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(AUX2_GPIO, AUX2_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + + AUX_OFF(); + AUX2_OFF(); + + // LEDs + palSetPadMode(GPIOA, 8, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(GPIOC, 9, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + + // Temp switches + palSetPadMode(ADC_SW_1_PORT, ADC_SW_1_PIN , + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(ADC_SW_2_PORT, ADC_SW_2_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(ADC_SW_3_PORT, ADC_SW_3_PIN , + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + + + ENABLE_MOS_TEMP1(); + + // GPIOB (DCCAL) + + // GPIOA Configuration: Channel 1 to 3 as alternate function push-pull + palSetPadMode(GPIOE, 8, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOE, 9, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOE, 10, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + palSetPadMode(GPIOE, 11, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOE, 12, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOE, 13, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + palSetPadMode(GPIOC, 6, PAL_MODE_ALTERNATE(GPIO_AF_TIM8) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOC, 7, PAL_MODE_ALTERNATE(GPIO_AF_TIM8) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOC, 8, PAL_MODE_ALTERNATE(GPIO_AF_TIM8) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(GPIO_AF_TIM8) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(GPIO_AF_TIM8) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOA, 7, PAL_MODE_ALTERNATE(GPIO_AF_TIM8) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + // Hall sensors + palSetPadMode(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO4, HW_HALL_ENC_PIN4, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO5, HW_HALL_ENC_PIN5, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO6, HW_HALL_ENC_PIN6, PAL_MODE_INPUT_PULLUP); + + // ADC Pins + palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOB, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 5, PAL_MODE_INPUT_ANALOG); + + // DAC as voltage reference for shunt amps + palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); + DAC->CR |= DAC_CR_EN1; + DAC->DHR12R1 = 2047; +} + +void hw_setup_adc_channels(void) { + + // ADC1 regular channels + ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_15Cycles); //0 + ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 2, ADC_SampleTime_15Cycles); //3 + ADC_RegularChannelConfig(ADC1, ADC_Channel_5 , 3, ADC_SampleTime_15Cycles); //6 + ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 4, ADC_SampleTime_15Cycles); //9 + ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 5, ADC_SampleTime_15Cycles); //12 + + // ADC2 regular channels + ADC_RegularChannelConfig(ADC2, ADC_Channel_8, 1, ADC_SampleTime_15Cycles); //1 + ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 2, ADC_SampleTime_15Cycles); //4 + ADC_RegularChannelConfig(ADC2, ADC_Channel_14, 3, ADC_SampleTime_15Cycles); //7 + ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 4, ADC_SampleTime_15Cycles); //10 + ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 5, ADC_SampleTime_15Cycles); //13 + + // ADC3 regular channels + ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_15Cycles); //2 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 2, ADC_SampleTime_15Cycles); //5 + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 3, ADC_SampleTime_15Cycles); //8 + ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 4, ADC_SampleTime_15Cycles); //11 + ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 5, ADC_SampleTime_15Cycles); //14 + + // Injected channels + ADC_InjectedChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_15Cycles); + + + ADC_InjectedChannelConfig(ADC2, ADC_Channel_5, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_4, 2, ADC_SampleTime_15Cycles); + + // ADC_InjectedChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_15Cycles); + // ADC_InjectedChannelConfig(ADC3, ADC_Channel_0, 2, ADC_SampleTime_15Cycles); + //ADC_InjectedChannelConfig(ADC3, ADC_Channel_1, 3, ADC_SampleTime_15Cycles); + + chThdCreateStatic(mux_thread_wa, sizeof(mux_thread_wa), NORMALPRIO, mux_thread, NULL); + chThdCreateStatic(switch_color_thread_wa, sizeof(switch_color_thread_wa), LOWPRIO, switch_color_thread, NULL); + +} + +void hw_start_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (!i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + i2cStart(&HW_I2C_DEV, &i2cfg); + i2c_running = true; + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +void hw_stop_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, PAL_MODE_INPUT); + + i2cStop(&HW_I2C_DEV); + i2c_running = false; + + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +/** + * Try to restore the i2c bus + */ +void hw_try_restore_i2c(void) { + if (i2c_running) { + i2cAcquireBus(&HW_I2C_DEV); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + chThdSleep(1); + + for(int i = 0;i < 16;i++) { + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + } + + // Generate start then stop condition + palClearPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + chThdSleep(1); + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + HW_I2C_DEV.state = I2C_STOP; + i2cStart(&HW_I2C_DEV, &i2cfg); + + i2cReleaseBus(&HW_I2C_DEV); + } +} + +int samp_cmp_func (const void * a, const void * b) { + return (*(uint16_t*)a - *(uint16_t*)b); +} + +static THD_FUNCTION(mux_thread, arg) { + chRegSetThreadName("adc_mux"); + (void)arg; + +#define TEMP_FILTER_LEN 9 + uint16_t mot1_temp_samples[TEMP_FILTER_LEN] = {0}; + uint16_t mot2_temp_samples[TEMP_FILTER_LEN] = {0}; + unsigned int mot1_temp_samp_ptr = 0; + unsigned int mot2_temp_samp_ptr = 0; + + for (;;) { + ENABLE_MOS_TEMP1(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_TEMP_MOS] = ADC_Value[ADC_IND_ADC_MUX]; + + ENABLE_MOS_TEMP2(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_TEMP_MOS_M2] = ADC_Value[ADC_IND_ADC_MUX]; + + ENABLE_MOT_TEMP1(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_TEMP_MOTOR] = utils_median_filter_uint16_run( + mot1_temp_samples, &mot1_temp_samp_ptr, TEMP_FILTER_LEN, ADC_Value[ADC_IND_ADC_MUX]); + + ENABLE_MOT_TEMP2(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_TEMP_MOTOR_2] = utils_median_filter_uint16_run( + mot2_temp_samples, &mot2_temp_samp_ptr, TEMP_FILTER_LEN, ADC_Value[ADC_IND_ADC_MUX]); + + ENABLE_ADC_EXT_1(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_EXT] = ADC_Value[ADC_IND_ADC_MUX]; + + ENABLE_ADC_EXT_2(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_EXT2] = ADC_Value[ADC_IND_ADC_MUX]; + + ENABLE_ADC_EXT_3(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_EXT3] = ADC_Value[ADC_IND_ADC_MUX]; + + + ENABLE_V_BATT_DIV(); + chThdSleepMicroseconds(400); + ADC_Value[ADC_IND_V_BATT] = ADC_Value[ADC_IND_ADC_MUX]; + } +} + +void smart_switch_keep_on(void) { + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + //#ifdef HW_HAS_RGB_SWITCH + // LED_SWITCH_B_ON(); + // ledpwm_set_intensity(SWITCH_LED_B, 1.0); + //#else + // ledpwm_set_intensity(SWITCH_LED, 1.0); + // ledpwm_set_switch_intensity(0.6); + //#endif +} + +void smart_switch_shut_down(void) { + mc_interface_select_motor_thread(2); + mc_interface_set_current(0); + mc_interface_lock(); + mc_interface_select_motor_thread(1); + mc_interface_set_current(0); + mc_interface_lock(); + switch_state = SWITCH_SHUTTING_DOWN; + palClearPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + return; +} + +bool smart_switch_is_pressed(void) { + if (palReadPad(SWITCH_IN_GPIO, SWITCH_IN_PIN) == 1 && + (mc_interface_temp_fet_filtered() < 68.0) /* why?? */) { + return true; + } else { + return false; + } +} + +static THD_FUNCTION(switch_color_thread, arg) { + (void)arg; + chRegSetThreadName("switch_color"); + float switch_red = 0.0; + float switch_green = 0.0; + float switch_blue = 0.0; + + for(int i = 0; i < 400; i++) { + float angle = i*3.14/400.0; + float s,c; + utils_fast_sincos_better(angle, &s, &c); + switch_blue = 0.75* c*c; + ledpwm_set_intensity(LED_HW1,switch_bright*switch_blue); + utils_fast_sincos_better(angle + 3.14/3.0, &s, &c); + switch_green = 0.75* c*c; + ledpwm_set_intensity(LED_HW2,switch_bright*switch_green); + utils_fast_sincos_better(angle + 6.28/3.0, &s, &c); + switch_red = 0.75* c*c; + ledpwm_set_intensity(LED_HW3,switch_bright*switch_red); + chThdSleepMilliseconds(4); + } + float switch_red_old = switch_red_old; + float switch_green_old = switch_green; + float switch_blue_old = switch_blue; + float wh_left; + float left = mc_interface_get_battery_level(&wh_left); + + if (left < 0.5) { + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + } else { + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + } + + for (int i = 0; i < 100; i++) { + float red_now = utils_map((float) i,0.0, 100.0, switch_red_old, switch_red); + float blue_now = utils_map((float) i,0.0, 100.0, switch_blue_old, switch_blue); + float green_now = utils_map((float) i,0.0, 100.0, switch_green_old, switch_green); + ledpwm_set_intensity(LED_HW1, switch_bright*blue_now); + ledpwm_set_intensity(LED_HW2, switch_bright*green_now); + ledpwm_set_intensity(LED_HW3, switch_bright*red_now); + chThdSleepMilliseconds(2); + } + + for (;;) { + mc_fault_code fault = mc_interface_get_fault(); + mc_interface_select_motor_thread(2); + mc_fault_code fault2 = mc_interface_get_fault(); + mc_interface_select_motor_thread(1); + + if (fault != FAULT_CODE_NONE || fault2 != FAULT_CODE_NONE) { + ledpwm_set_intensity(LED_HW2, 0); + ledpwm_set_intensity(LED_HW1, 0); + for (int i = 0;i < (int)fault;i++) { + ledpwm_set_intensity(LED_HW3, 1.0); + chThdSleepMilliseconds(250); + ledpwm_set_intensity(LED_HW3, 0.0); + chThdSleepMilliseconds(250); + } + + chThdSleepMilliseconds(500); + + for (int i = 0;i < (int)fault2;i++) { + ledpwm_set_intensity(LED_HW3, 1.0); + chThdSleepMilliseconds(250); + ledpwm_set_intensity(LED_HW3, 0.0); + chThdSleepMilliseconds(250); + } + + chThdSleepMilliseconds(500); + } else { + left = mc_interface_get_battery_level(&wh_left); + if(left < 0.5){ + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + switch_green = 0; + }else{ + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + switch_red = 0; + } + ledpwm_set_intensity(LED_HW1, switch_bright*switch_blue); + ledpwm_set_intensity(LED_HW2, switch_bright*switch_green); + ledpwm_set_intensity(LED_HW3, switch_bright*switch_red); + } + + chThdSleepMilliseconds(20); + } +} + +static THD_FUNCTION(smart_switch_thread, arg) { + (void)arg; + chRegSetThreadName("smart_switch"); + unsigned int millis_switch_pressed = 0; + + for (;;) { + const app_configuration *conf = app_get_configuration(); + + switch (switch_state) { + case SWITCH_BOOTED: + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + case SWITCH_TURN_ON_DELAY_ACTIVE: + switch_state = SWITCH_HELD_AFTER_TURN_ON; + mc_interface_select_motor_thread(2); + mc_interface_set_current(0); + mc_interface_lock(); + mc_interface_select_motor_thread(1); + mc_interface_set_current(0); + mc_interface_lock(); + + mc_interface_select_motor_thread(2); + mc_interface_unlock(); + mc_interface_select_motor_thread(1); + mc_interface_unlock(); + + // Wait for other systems to boot up before proceeding + while (!main_init_done()) { + chThdSleepMilliseconds(200); + } + break; + + case SWITCH_HELD_AFTER_TURN_ON: + if (smart_switch_is_pressed() && conf->shutdown_mode != SHUTDOWN_MODE_ALWAYS_OFF) { + switch_state = SWITCH_HELD_AFTER_TURN_ON; + } else { + switch_state = SWITCH_TURNED_ON; + } + break; + + case SWITCH_TURNED_ON: + if (conf->shutdown_mode == SHUTDOWN_MODE_ALWAYS_OFF) { + switch_bright = 1.0; + if (!smart_switch_is_pressed()) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } else { + if (smart_switch_is_pressed()) { + millis_switch_pressed++; + switch_bright = 0.5; + } else { + millis_switch_pressed = 0; + switch_bright = 1.0; + } + + if (millis_switch_pressed > SMART_SWITCH_MSECS_PRESSED_OFF) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } + break; + + case SWITCH_SHUTTING_DOWN: + switch_bright = 0; + systime_t tStart = chVTGetSystemTimeX(); + while (smart_switch_is_pressed()) { + chThdSleepMilliseconds(10); + if (UTILS_AGE_S(tStart) > 10.0) { + millis_switch_pressed = 0; + switch_state = SWITCH_TURNED_ON; + break; + } + } + + if (switch_state == SWITCH_TURNED_ON) { + break; + } + + shutdown_save_and_hold(); + comm_can_shutdown(255); + smart_switch_shut_down(); + chThdSleepMilliseconds(10000); + smart_switch_keep_on(); + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + default: + break; + } + + chThdSleepMilliseconds(1); + } +} + +void smart_switch_thread_start(void) { + chThdCreateStatic(smart_switch_thread_wa, sizeof(smart_switch_thread_wa), + NORMALPRIO, smart_switch_thread, NULL); +} + +void smart_switch_pin_init(void) { + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); + + palSetPadMode(SWITCH_IN_GPIO, SWITCH_IN_PIN, PAL_MODE_INPUT_PULLDOWN); + palSetPadMode(SWITCH_OUT_GPIO,SWITCH_OUT_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_2_GPIO,SWITCH_LED_2_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + LED_SWITCH_B_ON(); + LED_SWITCH_R_OFF(); + LED_SWITCH_G_OFF(); + return; +} + diff --git a/hwconf/vesc/duet_xs/hw_duet_xs_core.h b/hwconf/vesc/duet_xs/hw_duet_xs_core.h new file mode 100644 index 0000000000..55e8c6e421 --- /dev/null +++ b/hwconf/vesc/duet_xs/hw_duet_xs_core.h @@ -0,0 +1,369 @@ +/* + Copyright 2016 Benjamin Vedder benjamin@vedder.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#ifndef HW_VESC_DUET_XS_CORE_H_ +#define HW_VESC_DUET_XS_CORE_H_ + +#define HW_HAS_DUAL_MOTORS + +#ifdef HW_XS60 +#define HW_NAME "DUET XS60" +#else +#define HW_NAME "DUET XS100" +#endif +#ifndef HW_NAME +#error "Must define hardware type" +#endif + +#define INVERTED_SHUNT_POLARITY +#define HW_HAS_3_SHUNTS +#define HW_BOOT_VESC_CAN + +#define HW_DEAD_TIME_NSEC 200.0 + +// Switch Pins +#define HW_HAS_RGB_SWITCH + +#define SWITCH_IN_GPIO GPIOA +#define SWITCH_IN_PIN 15 +#define SWITCH_OUT_GPIO GPIOB +#define SWITCH_OUT_PIN 13 +#define SWITCH_LED_3_GPIO GPIOD +#define SWITCH_LED_3_PIN 11 +#define SWITCH_LED_2_GPIO GPIOD +#define SWITCH_LED_2_PIN 10 +#define SWITCH_LED_1_GPIO GPIOD +#define SWITCH_LED_1_PIN 15 + +#define LED_PWM1_ON() palClearPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM1_OFF() palSetPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM2_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM2_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM3_ON() palClearPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) +#define LED_PWM3_OFF() palSetPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) + +#define SMART_SWITCH_MSECS_PRESSED_OFF 2000 + +#define HW_HAS_PHASE_FILTERS +#define PHASE_FILTER_OFF() palSetPad(GPIOE, 3); palSetPad(GPIOE, 4); palSetPad(GPIOE, 6); +#define PHASE_FILTER_ON() palClearPad(GPIOE, 3); palClearPad(GPIOE, 4); palClearPad(GPIOE, 6); +#define PHASE_FILTER_OFF_M2() palSetPad(GPIOE, 0); palSetPad(GPIOE, 1); palSetPad(GPIOE, 2); +#define PHASE_FILTER_ON_M2() palClearPad(GPIOE, 0); palClearPad(GPIOE, 1); palClearPad(GPIOE, 2); + +#define AUX_GPIO GPIOE +#define AUX_PIN 14 +#define AUX_ON() palSetPad(AUX_GPIO, AUX_PIN) +#define AUX_OFF() palClearPad(AUX_GPIO, AUX_PIN) +#define AUX2_GPIO GPIOE +#define AUX2_PIN 15 +#define AUX2_ON() palSetPad(AUX2_GPIO, AUX2_PIN) +#define AUX2_OFF() palClearPad(AUX2_GPIO, AUX2_PIN) + +#define HW_SHUTDOWN_HOLD_ON(); +#define HW_SAMPLE_SHUTDOWN() 1 +#define HW_SHUTDOWN_HOLD_OFF() palClearPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); +#define HW_SHUTDOWN_NO + +#define DCCAL_ON() +#define DCCAL_OFF() + +#define HW_EARLY_INIT() smart_switch_pin_init(); \ + smart_switch_thread_start(); + +//Pins for BLE UART +//#define USE_ALT_UART_PORT + +#define HW_UART_P_BAUD 115200 +#define HW_UART_P_DEV SD1 +#define HW_UART_P_GPIO_AF GPIO_AF_USART1 +#define HW_UART_P_TX_PORT GPIOA +#define HW_UART_P_TX_PIN 9 +#define HW_UART_P_RX_PORT GPIOA +#define HW_UART_P_RX_PIN 10 + +#define ADC_SW_1_PORT GPIOD +#define ADC_SW_1_PIN 7 +#define ADC_SW_2_PORT GPIOB +#define ADC_SW_2_PIN 3 +#define ADC_SW_3_PORT GPIOE +#define ADC_SW_3_PIN 7 + +#define AD1_L() palClearPad(ADC_SW_1_PORT, ADC_SW_1_PIN ) +#define AD1_H() palSetPad(ADC_SW_1_PORT, ADC_SW_1_PIN ) +#define AD2_L() palClearPad(ADC_SW_2_PORT, ADC_SW_2_PIN ) +#define AD2_H() palSetPad(ADC_SW_2_PORT, ADC_SW_2_PIN ) +#define AD3_L() palClearPad(ADC_SW_3_PORT, ADC_SW_3_PIN ) +#define AD3_H() palSetPad(ADC_SW_3_PORT, ADC_SW_3_PIN ) + +#define ENABLE_MOS_TEMP1() AD3_L(); AD2_L(); AD1_L(); +#define ENABLE_MOS_TEMP2() AD3_L(); AD2_L(); AD1_H(); +#define ENABLE_MOT_TEMP1() AD3_L(); AD2_H(); AD1_L(); +#define ENABLE_MOT_TEMP2() AD3_L(); AD2_H(); AD1_H(); +#define ENABLE_ADC_EXT_2() AD3_H(); AD2_L(); AD1_L(); +#define ENABLE_ADC_EXT_1() AD3_H(); AD2_L(); AD1_H(); +#define ENABLE_ADC_EXT_3() AD3_H(); AD2_H(); AD1_L(); +#define ENABLE_V_BATT_DIV() AD3_H(); AD2_H(); AD1_H(); + +#define LED_GREEN_ON() palSetPad(GPIOC, 9);// palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN); +#define LED_GREEN_OFF() palClearPad(GPIOC, 9);// palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN); +#define LED_RED_ON() palSetPad(GPIOA, 8); //palClearPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN); +#define LED_RED_OFF() palClearPad(GPIOA, 8); //palSetPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN); +#define LED_SWITCH_R_ON() palClearPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_R_OFF() palSetPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_G_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_G_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_B_ON() palClearPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) +#define LED_SWITCH_B_OFF() palSetPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) + +/* + * ADC Vector + * + * 0: IN9 CURR1 + * 1: IN8 CURR2 + * 2: IN2 CURR3 + * 3: IN15 CURR4 + * 4: IN6 CURR5 + * 5: IN3 CURR6 + * 6: IN5 ADC_MUX + * 7: IN14 SENS1 + * 8: IN13 SENS4 + * 9: IN9 CURR1 + * 10: IN12 SENS5 + * 11: IN11 SENS6 + * 12: IN0 SENS2 + * 13: IN1 SENS3 + * 14: IN10 VBUSDIV + */ + +#define HW_ADC_CHANNELS 15 +#define HW_ADC_CHANNELS_EXTRA 15 +#define HW_ADC_INJ_CHANNELS 2 +#define HW_ADC_NBR_CONV 5 + +// ADC Indexes + +#define ADC_IND_CURR1 0 +#define ADC_IND_CURR2 1 +#define ADC_IND_CURR3 2 + +#define ADC_IND_CURR4 3 +#define ADC_IND_CURR5 4 +#define ADC_IND_CURR6 5 + +#define ADC_IND_ADC_MUX 6 +#define ADC_IND_VIN_SENS 14 + +#define ADC_IND_SENS1 7 +#define ADC_IND_SENS2 12 +#define ADC_IND_SENS3 13 + +#define ADC_IND_SENS4 8 +#define ADC_IND_SENS5 10 +#define ADC_IND_SENS6 11 + +#define ADC_IND_TEMP_MOS 15 +#define ADC_IND_TEMP_MOS_M2 16 +#define ADC_IND_TEMP_MOTOR 17 +#define ADC_IND_TEMP_MOTOR_2 18 +#define ADC_IND_EXT 19 +#define ADC_IND_EXT2 20 +#define ADC_IND_EXT3 21 +#define ADC_IND_V_BATT 22 + +// ADC macros and settings + +// Component parameters (can be overridden) +#ifndef V_REG +#define V_REG 3.3 +#endif +#ifndef VIN_R1 +#define VIN_R1 68000.0 +#endif +#ifndef VIN_R2 +#define VIN_R2 2200.0 +#endif + + +#ifndef CURRENT_AMP_GAIN +#define CURRENT_AMP_GAIN 20.0 +#endif +#ifndef CURRENT_SHUNT_RES +#define CURRENT_SHUNT_RES 0.0005 +#endif + +#define GET_INPUT_VOLTAGE() ((V_REG / 4095.0) * (float)ADC_Value[ADC_IND_VIN_SENS] * ((VIN_R1 + VIN_R2) / VIN_R2)) + +// Voltage on ADC channel +#define ADC_VOLTS(ch) ((float)ADC_Value[ch] / 4095.0 * V_REG) + +// NTC Termistors +#define NTC_RES(adc_val) (10000.0 / ((4095.0 / (float)adc_val) - 1.0)) // Motor temp sensor on low side // High side ->((4095.0 * 10000.0) / adc_val - 10000.0) +#define NTC_TEMP(adc_ind) (1.0 / ((logf(NTC_RES(ADC_Value[adc_ind]) / 10000.0) / 3434.0) + (1.0 / 298.15)) - 273.15) + +#define NTC_RES_MOTOR(adc_val) (10000.0 / ((4095.0 / (float)adc_val) - 1.0)) // Motor temp sensor on low side +#define NTC_TEMP_MOTOR(beta) (1.0 / ((logf(NTC_RES_MOTOR(ADC_Value[ADC_IND_TEMP_MOTOR]) / 10000.0) / beta) + (1.0 / 298.15)) - 273.15) +#define NTC_TEMP_MOTOR_2(beta) (1.0 / ((logf(NTC_RES_MOTOR(ADC_Value[ADC_IND_TEMP_MOTOR_2]) / 10000.0) / beta) + (1.0 / 298.15)) - 273.15) + +// UART Peripheral +#define HW_UART_DEV SD3 +#define HW_UART_GPIO_AF GPIO_AF_USART3 +#define HW_UART_TX_PORT GPIOB +#define HW_UART_TX_PIN 10 +#define HW_UART_RX_PORT GPIOB +#define HW_UART_RX_PIN 11 + +// ICU Peripheral for servo decoding +#define HW_ICU_TIMER TIM9 +#define HW_ICU_TIM_CLK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE) +#define HW_ICU_DEV ICUD9 +#define HW_ICU_CHANNEL ICU_CHANNEL_1 +#define HW_ICU_GPIO_AF GPIO_AF_TIM9 +#define HW_ICU_GPIO GPIOE +#define HW_ICU_PIN 5 + +// I2C Peripheral +#define HW_I2C_DEV I2CD2 +#define HW_I2C_GPIO_AF GPIO_AF_I2C2 +#define HW_I2C_SCL_PORT GPIOB +#define HW_I2C_SCL_PIN 10 +#define HW_I2C_SDA_PORT GPIOB +#define HW_I2C_SDA_PIN 11 + +// Hall/encoder pins +#define HW_HALL_ENC_GPIO1 GPIOD +#define HW_HALL_ENC_PIN1 13 +#define HW_HALL_ENC_GPIO2 GPIOD +#define HW_HALL_ENC_PIN2 12 +#define HW_HALL_ENC_GPIO3 GPIOD +#define HW_HALL_ENC_PIN3 14 +#define HW_ENC_TIM TIM4 +#define HW_ENC_TIM_AF GPIO_AF_TIM4 +#define HW_ENC_TIM_CLK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE) +#define HW_ENC_EXTI_PORTSRC EXTI_PortSourceGPIOD +#define HW_ENC_EXTI_PINSRC EXTI_PinSource14 +#define HW_ENC_EXTI_CH EXTI15_10_IRQn +#define HW_ENC_EXTI_LINE EXTI_Line14 +#define HW_ENC_EXTI_ISR_VEC EXTI15_10_IRQHandler +#define HW_ENC_TIM_ISR_CH TIM4_IRQn +#define HW_ENC_TIM_ISR_VEC TIM4_IRQHandler + +#define HW_HALL_ENC_GPIO4 GPIOB +#define HW_HALL_ENC_PIN4 4 +#define HW_HALL_ENC_GPIO5 GPIOB +#define HW_HALL_ENC_PIN5 6 +#define HW_HALL_ENC_GPIO6 GPIOB +#define HW_HALL_ENC_PIN6 7 +#define HW_ENC_TIM2 TIM3 +#define HW_ENC_TIM_AF2 GPIO_AF_TIM3 +#define HW_ENC_TIM_CLK_EN2() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE) +#define HW_ENC_EXTI_PORTSRC2 EXTI_PortSourceGPIOB +#define HW_ENC_EXTI_PINSRC2 EXTI_PinSource7 +#define HW_ENC_EXTI_CH2 EXTI9_5_IRQn +#define HW_ENC_EXTI_LINE2 EXTI_Line6 +#define HW_ENC_EXTI_ISR_VEC2 EXTI9_5_IRQHandler +#define HW_ENC_TIM_ISR_CH2 TIM3_IRQn +#define HW_ENC_TIM_ISR_VEC2 TIM3_IRQHandler + +// NRF pins +// NRF pins +#define NRF_PORT_CSN GPIOD +#define NRF_PIN_CSN 3 +#define NRF_PORT_SCK GPIOD +#define NRF_PIN_SCK 2 +#define NRF_PORT_MOSI GPIOD +#define NRF_PIN_MOSI 11 +#define NRF_PORT_MISO GPIOD +#define NRF_PIN_MISO 10 + +#ifndef MCCONF_DEFAULT_MOTOR_TYPE +#define MCCONF_DEFAULT_MOTOR_TYPE MOTOR_TYPE_FOC +#endif + +// LSM6DS3 +#define LSM6DS3_SDA_GPIO GPIOB +#define LSM6DS3_SDA_PIN 9 +#define LSM6DS3_SCL_GPIO GPIOB +#define LSM6DS3_SCL_PIN 8 + +// Measurement macros +#define ADC_V_L1 ADC_Value[ADC_IND_SENS1] +#define ADC_V_L2 ADC_Value[ADC_IND_SENS2] +#define ADC_V_L3 ADC_Value[ADC_IND_SENS3] +#define ADC_V_L4 ADC_Value[ADC_IND_SENS4] +#define ADC_V_L5 ADC_Value[ADC_IND_SENS5] +#define ADC_V_L6 ADC_Value[ADC_IND_SENS6] +#define ADC_V_ZERO (ADC_Value[ADC_IND_VIN_SENS] / 2) + +// Macros +#define READ_HALL1() palReadPad(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1) +#define READ_HALL2() palReadPad(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2) +#define READ_HALL3() palReadPad(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3) + +#define READ_HALL1_2() palReadPad(HW_HALL_ENC_GPIO4, HW_HALL_ENC_PIN4) +#define READ_HALL2_2() palReadPad(HW_HALL_ENC_GPIO5, HW_HALL_ENC_PIN5) +#define READ_HALL3_2() palReadPad(HW_HALL_ENC_GPIO6, HW_HALL_ENC_PIN6) + +//CAN +#define HW_CANRX_PORT GPIOD +#define HW_CANRX_PIN 0 +#define HW_CANTX_PORT GPIOD +#define HW_CANTX_PIN 1 + +// Setting limits +#ifndef MCCONF_L_MAX_ABS_CURRENT +#define MCCONF_L_MAX_ABS_CURRENT 80.0 // The maximum absolute current above which a fault is generated +#endif +#ifndef MCCONF_FOC_F_ZV +#define MCCONF_FOC_F_ZV 23000.0 +#endif +#ifndef MCCONF_L_IN_CURRENT_MAX +#define MCCONF_L_IN_CURRENT_MAX 45.0 // Input current limit in Amperes (Upper) +#endif +#ifndef MCCONF_L_IN_CURRENT_MIN +#define MCCONF_L_IN_CURRENT_MIN -45.0 // Input current limit in Amperes (Lower) +#endif + +#ifdef HW_XS60 +#ifndef MCCONF_L_MAX_VOLTAGE +#define MCCONF_L_MAX_VOLTAGE 55.0 +#endif +#define HW_LIM_VIN 6.0, 57.0 +#define HW_LIM_CURRENT -100.0, 100.0 +#define HW_LIM_CURRENT_ABS 0.0, 150.0 +#define HW_LIM_CURRENT_IN -100.0, 100.0 +#else +#ifndef MCCONF_L_MAX_VOLTAGE +#define MCCONF_L_MAX_VOLTAGE 90.0 +#endif +#define HW_LIM_VIN 6.0, 94.0 +#define HW_LIM_CURRENT -65.0, 65.0 +#define HW_LIM_CURRENT_ABS 0.0, 110.0 +#define HW_LIM_CURRENT_IN -65.0, 65.0 +#endif + +#define HW_LIM_ERPM -200e3, 200e3 +#define HW_LIM_DUTY_MIN 0.0, 0.1 +#define HW_LIM_DUTY_MAX 0.0, 0.95 +#define HW_LIM_TEMP_FET -40.0, 110.0 + +// Functions +void smart_switch_thread_start(void); +void smart_switch_pin_init(void); +bool smart_switch_is_pressed(void); +void smart_switch_shut_down(void); +void smart_switch_keep_on(void); + +#endif /* HW_VESC_DUET_XS_CORE_H_ */ diff --git a/hwconf/vesc/maxim/hw_maxim_core.c b/hwconf/vesc/maxim/hw_maxim_core.c index 5eea738899..c6fb268906 100644 --- a/hwconf/vesc/maxim/hw_maxim_core.c +++ b/hwconf/vesc/maxim/hw_maxim_core.c @@ -157,40 +157,42 @@ void hw_init_gpio(void) { } void hw_setup_adc_channels(void) { + uint8_t sample_time = ADC_SampleTime_15Cycles; + // ADC1 regular channels - ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); // 0 - ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_15Cycles); // 3 - ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, ADC_SampleTime_15Cycles); // 6 - ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_15Cycles); // 9 - ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 5, ADC_SampleTime_15Cycles); // 12 - ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 6, ADC_SampleTime_15Cycles); // 15 + ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, sample_time); // 0 + ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, sample_time); // 3 + ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, sample_time); // 6 + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, sample_time); // 9 + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, sample_time); // 12 + ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 6, sample_time); // 15 // ADC2 regular channels - ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); // 1 - ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 2, ADC_SampleTime_15Cycles); // 4 - ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 3, ADC_SampleTime_15Cycles); // 7 - ADC_RegularChannelConfig(ADC2, ADC_Channel_15, 4, ADC_SampleTime_15Cycles); // 10 - ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 5, ADC_SampleTime_15Cycles); // 13 - ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 6, ADC_SampleTime_15Cycles); // 16 + ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, sample_time); // 1 + ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 2, sample_time); // 4 + ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 3, sample_time); // 7 + ADC_RegularChannelConfig(ADC2, ADC_Channel_15, 4, sample_time); // 10 + ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 5, sample_time); // 13 + ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 6, sample_time); // 16 // ADC3 regular channels - ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); // 2 - ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 2, ADC_SampleTime_15Cycles); // 5 - ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 3, ADC_SampleTime_15Cycles); // 8 - ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 4, ADC_SampleTime_15Cycles); // 11 - ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 5, ADC_SampleTime_15Cycles); // 14 - ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 6, ADC_SampleTime_15Cycles); // 17 + ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, sample_time); // 2 + ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 2, sample_time); // 5 + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 3, sample_time); // 8 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 4, sample_time); // 11 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 5, sample_time); // 14 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 6, sample_time); // 17 // Injected channels - ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 2, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 2, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 3, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 3, ADC_SampleTime_15Cycles); - ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 1, sample_time); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 1, sample_time); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 1, sample_time); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 2, sample_time); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 2, sample_time); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 2, sample_time); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 3, sample_time); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 3, sample_time); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 3, sample_time); if (!mux_thd_running) { chThdCreateStatic(mux_thread_wa, sizeof(mux_thread_wa), NORMALPRIO, mux_thread, NULL); @@ -307,11 +309,13 @@ static THD_FUNCTION(mux_thread, arg) { PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); -#define T_SAMP_US 400 +#define T_SAMP_US 500 for (;;) { ADCMUX_MOT_TEMP(); - chThdSleepMicroseconds(T_SAMP_US); + // Wait longer on this one as some temperature sensors, e.g. the PT1000 change very little + // and the voltage divider gives us bad resolution for it. + chThdSleepMilliseconds(5); ADC_Value[ADC_IND_TEMP_MOTOR] = ADC_Value[ADC_IND_ADC_MUX]; ADCMUX_12V_SENSE_V(); @@ -341,6 +345,41 @@ static THD_FUNCTION(mux_thread, arg) { ADCMUX_TEMP_DCDC(); chThdSleepMicroseconds(T_SAMP_US); ADC_Value[ADC_IND_TEMP_DCDC] = ADC_Value[ADC_IND_ADC_MUX]; + + // Config check + mc_configuration *mcconf = (mc_configuration*)mc_interface_get_configuration(); + + if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_HALL) { + + // In hall sensor mode we use the ADC pins on the comm-port as additional + // pull-ups as the voltage dividers take the voltage down otherwise. + palSetPadMode(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN); + palSetPad(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN); + + // Prevent the uart-pins from interfering + palSetPadMode(HW_UART_TX_PORT, HW_UART_TX_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_UART_RX_PORT, HW_UART_RX_PIN, PAL_MODE_INPUT); + } else if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_ENCODER) { + + // Prevent the uart-pins from interfering + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_ABI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_AS5047_SPI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_PWM_ABI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_UART_TX_PORT, HW_UART_TX_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_UART_RX_PORT, HW_UART_RX_PIN, PAL_MODE_INPUT); + } + + // Ensure that the sin/cos pins are in ADC mode + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN, PAL_MODE_INPUT_ANALOG); + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_INPUT_ANALOG); + } + } } } diff --git a/hwconf/vesc/maxim/hw_maxim_core.h b/hwconf/vesc/maxim/hw_maxim_core.h index 282d6b3010..215660284b 100644 --- a/hwconf/vesc/maxim/hw_maxim_core.h +++ b/hwconf/vesc/maxim/hw_maxim_core.h @@ -32,6 +32,7 @@ #define HW_HAS_3_SHUNTS #define INVERTED_SHUNT_POLARITY #define HW_HAS_PHASE_FILTERS +#define HW_BOOT_VESC_CAN // Macros #define LED_GREEN_GPIO GPIOC @@ -91,11 +92,16 @@ #define HW_SAMPLE_SHUTDOWN() hw_sample_shutdown_button() #define HW_SHUTDOWN_NO // Normally open button -// Hold shutdown pin early to wake up on short pulses -#define HW_EARLY_INIT() palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); \ - HW_SHUTDOWN_HOLD_ON(); +#define HW_VERY_EARLY_INIT() RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); \ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); \ + palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); \ + palSetPadMode(AUX_GPIO, AUX_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); \ + palSetPadMode(AUX2_GPIO, AUX2_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); \ + HW_SHUTDOWN_HOLD_ON(); \ + AUX_OFF(); \ + AUX2_OFF(); -#define MCPWM_FOC_CURRENT_SAMP_OFFSET (2) // Offset from timer top for ADC samples +#define HW_EARLY_INIT() HW_VERY_EARLY_INIT() /* * ADC Vector @@ -112,14 +118,13 @@ #define ADC_IND_SENS1 3 #define ADC_IND_SENS2 4 #define ADC_IND_SENS3 5 -#define ADC_IND_VIN_SENS 11 +#define ADC_IND_VIN_SENS 8 #define ADC_IND_EXT5 16 #define ADC_IND_EXT 6 #define ADC_IND_EXT2 7 -#define ADC_IND_EXT3 8 -#define ADC_IND_VREFINT 12 +#define ADC_IND_EXT3 14 #define ADC_IND_ADC_MUX 15 -#define ADC_IND_EXT4 9 +#define ADC_IND_EXT4 12 #define ADC_IND_SHUTDOWN 13 #define ADC_IND_EXT6 13 @@ -304,7 +309,7 @@ #define MCCONF_L_IN_CURRENT_MIN -200.0 // Input current limit in Amperes (Lower) #endif #ifndef APPCONF_SHUTDOWN_MODE -#define APPCONF_SHUTDOWN_MODE SHUTDOWN_MODE_ALWAYS_ON +#define APPCONF_SHUTDOWN_MODE SHUTDOWN_MODE_ALWAYS_OFF #endif #ifndef APPCONF_APP_TO_USE #define APPCONF_APP_TO_USE APP_NONE diff --git a/hwconf/vesc/maximp/hw_maximp_core.c b/hwconf/vesc/maximp/hw_maximp_core.c index 6d3d080e34..d6cfd0e86f 100644 --- a/hwconf/vesc/maximp/hw_maximp_core.c +++ b/hwconf/vesc/maximp/hw_maximp_core.c @@ -175,7 +175,7 @@ void hw_setup_adc_channels(void) { ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_15Cycles); // 3 ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, ADC_SampleTime_15Cycles); // 6 ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_15Cycles); // 9 - ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 5, ADC_SampleTime_15Cycles); // 12 + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_15Cycles); // 12 ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 6, ADC_SampleTime_15Cycles); // 15 // ADC2 regular channels @@ -189,10 +189,10 @@ void hw_setup_adc_channels(void) { // ADC3 regular channels ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); // 2 ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 2, ADC_SampleTime_15Cycles); // 5 - ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 3, ADC_SampleTime_15Cycles); // 8 - ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 4, ADC_SampleTime_15Cycles); // 11 - ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 5, ADC_SampleTime_15Cycles); // 14 - ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 6, ADC_SampleTime_15Cycles); // 17 + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 3, ADC_SampleTime_15Cycles); // 8 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 4, ADC_SampleTime_15Cycles); // 11 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 5, ADC_SampleTime_15Cycles); // 14 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 6, ADC_SampleTime_15Cycles); // 17 // Injected channels ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); @@ -320,11 +320,13 @@ static THD_FUNCTION(mux_thread, arg) { PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); -#define T_SAMP_US 400 +#define T_SAMP_US 500 for (;;) { ADCMUX_MOT_TEMP(); - chThdSleepMicroseconds(T_SAMP_US); + // Wait longer on this one as some temperature sensors, e.g. the PT1000 change very little + // and the voltage divider gives us bad resolution for it. + chThdSleepMilliseconds(5); ADC_Value[ADC_IND_TEMP_MOTOR] = ADC_Value[ADC_IND_ADC_MUX]; ADCMUX_12V_SENSE_V(); @@ -354,6 +356,41 @@ static THD_FUNCTION(mux_thread, arg) { ADCMUX_TEMP_DCDC(); chThdSleepMicroseconds(T_SAMP_US); ADC_Value[ADC_IND_TEMP_DCDC] = ADC_Value[ADC_IND_ADC_MUX]; + + // Config check + mc_configuration *mcconf = (mc_configuration*)mc_interface_get_configuration(); + + if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_HALL) { + + // In hall sensor mode we use the ADC pins on the comm-port as additional + // pull-ups as the voltage dividers take the voltage down otherwise. + palSetPadMode(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN); + palSetPad(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN); + + // Prevent the uart-pins from interfering + palSetPadMode(HW_UART_TX_PORT, HW_UART_TX_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_UART_RX_PORT, HW_UART_RX_PIN, PAL_MODE_INPUT); + } else if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_ENCODER) { + + // Prevent the uart-pins from interfering + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_ABI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_AS5047_SPI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_PWM_ABI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_UART_TX_PORT, HW_UART_TX_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_UART_RX_PORT, HW_UART_RX_PIN, PAL_MODE_INPUT); + } + + // Ensure that the sin/cos pins are in ADC mode + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN, PAL_MODE_INPUT_ANALOG); + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_INPUT_ANALOG); + } + } } } diff --git a/hwconf/vesc/maximp/hw_maximp_core.h b/hwconf/vesc/maximp/hw_maximp_core.h index 19f991d3d6..fa9ecb7850 100644 --- a/hwconf/vesc/maximp/hw_maximp_core.h +++ b/hwconf/vesc/maximp/hw_maximp_core.h @@ -32,6 +32,7 @@ #define HW_HAS_3_SHUNTS #define INVERTED_SHUNT_POLARITY #define HW_HAS_PHASE_FILTERS +#define HW_BOOT_VESC_CAN // Macros #define LED_GREEN_GPIO GPIOC @@ -105,15 +106,14 @@ #define ADC_IND_SENS1 3 #define ADC_IND_SENS2 4 #define ADC_IND_SENS3 5 -#define ADC_IND_VIN_SENS 11 +#define ADC_IND_VIN_SENS 8 #define ADC_IND_EXT5 16 #define ADC_IND_EXT 6 #define ADC_IND_EXT2 7 #define ADC_IND_SHUTDOWN 10 -#define ADC_IND_EXT3 8 -#define ADC_IND_VREFINT 12 +#define ADC_IND_EXT3 14 #define ADC_IND_ADC_MUX 15 -#define ADC_IND_EXT4 9 +#define ADC_IND_EXT4 12 #define ADC_IND_TEMP_MOTOR 18 #define ADC_IND_12V_SENSE_V 19 diff --git a/hwconf/vesc/minim/hw_minim_core.c b/hwconf/vesc/minim/hw_minim_core.c index 129de7152f..b50a9c6482 100644 --- a/hwconf/vesc/minim/hw_minim_core.c +++ b/hwconf/vesc/minim/hw_minim_core.c @@ -27,16 +27,43 @@ #include "lispbm.h" #include "terminal.h" #include "commands.h" - -static void terminal_shutdown_now(int argc, const char **argv); -static void terminal_button_test(int argc, const char **argv); - -// Variables -static volatile bool i2c_running = false; -static mutex_t shutdown_mutex; -static volatile bool shutdown_mutex_init_done = false; +#include "utils.h" +#include "ledpwm.h" +#include "main.h" +#include "app.h" +#include "comm_can.h" +#include "shutdown.h" + +typedef enum { + SWITCH_BOOTED = 0, + SWITCH_TURN_ON_DELAY_ACTIVE, + SWITCH_HELD_AFTER_TURN_ON, + SWITCH_TURNED_ON, + SWITCH_SHUTTING_DOWN, +} switch_states; + +// Switch +static THD_WORKING_AREA(smart_switch_thread_wa, 256); +static THD_WORKING_AREA(switch_color_thread_wa, 256); +static THD_FUNCTION(switch_color_thread, arg); +static volatile switch_states switch_state = SWITCH_BOOTED; + +static volatile float switch_bright = 0.75; +static bool switch_color_thd_running = false; static volatile float bt_diff = 0.0; static volatile bool shutdown_hold_en = true; +static volatile bool shutdown_sample_dis = false; +static mutex_t shutdown_mutex; +static volatile bool shutdown_mutex_init_done = false; + +static volatile bool i2c_running = false; + +// Sense thread +static THD_WORKING_AREA(sense_thread_wa, 256); +static THD_FUNCTION(sense_thread, arg); +static volatile bool sense_thd_running = false; +static volatile float speed_time = 0.0; +static volatile systime_t speed_update = 0; // I2C configuration static const I2CConfig i2cfg = { @@ -45,6 +72,8 @@ static const I2CConfig i2cfg = { STD_DUTY_CYCLE }; +static void terminal_button_test(int argc, const char **argv); + static lbm_value ext_basic_set_out(lbm_value *args, lbm_uint argn) { LBM_CHECK_ARGN_NUMBER(2); @@ -86,9 +115,21 @@ static lbm_value ext_basic_set_out(lbm_value *args, lbm_uint argn) { return res; } +static lbm_value ext_speed_last_time(lbm_value *args, lbm_uint argn) { + (void)args; (void)argn; + return lbm_enc_float(speed_time); +} + +static lbm_value ext_speed_age(lbm_value *args, lbm_uint argn) { + (void)args; (void)argn; + return lbm_enc_float(UTILS_AGE_S(speed_update)); +} + static void load_extensions(bool main_found) { if (!main_found) { lbm_add_extension("hw-set-out", ext_basic_set_out); + lbm_add_extension("speed-last-time", ext_speed_last_time); + lbm_add_extension("speed-age", ext_speed_age); } } @@ -178,12 +219,6 @@ void hw_init_gpio(void) { lispif_add_ext_load_callback(load_extensions); - terminal_register_command_callback( - "shutdown", - "Shutdown VESC now.", - 0, - terminal_shutdown_now); - terminal_register_command_callback( "test_button", "Try sampling the shutdown button", @@ -226,8 +261,75 @@ void hw_setup_adc_channels(void) { ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 3, ADC_SampleTime_15Cycles); ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 3, ADC_SampleTime_15Cycles); ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_15Cycles); + + if (!sense_thd_running) { + chThdCreateStatic(sense_thread_wa, sizeof(sense_thread_wa), NORMALPRIO, sense_thread, NULL); + sense_thd_running = true; + } + + if (!switch_color_thd_running) { + chThdCreateStatic(switch_color_thread_wa, sizeof(switch_color_thread_wa), LOWPRIO, switch_color_thread, NULL); + switch_color_thd_running = true; + } } +// ADC-version with filtering and hysteresis +static THD_FUNCTION(sense_thread, arg) { + (void)arg; + + chRegSetThreadName("hw-wheel"); + + float volts = ADC_VOLTS(ADC_IND_EXT3); + bool speed_last = volts < 1.5; + + for (;;) { + bool speed = false; + + UTILS_LP_FAST(volts, ADC_VOLTS(ADC_IND_EXT3), 0.5); + + if (speed_last) { + speed = volts < 1.3; + } else { + speed = volts < 0.6; + } + + if (speed && speed != speed_last) { + float time = UTILS_AGE_S(speed_update); + if (time > 0.05) { // Max 900 RPM + speed_time = time; + speed_update = chVTGetSystemTimeX(); + } + } + + speed_last = speed; + chThdSleep(1); + } +} + +// Digital version +//static THD_FUNCTION(sense_thread, arg) { +// (void)arg; +// +// chRegSetThreadName("hw-wheel"); +// +// int speed_last = palReadPad(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN); +// +// for (;;) { +// bool speed = palReadPad(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN); +// +// if (speed && speed != speed_last) { +// float time = UTILS_AGE_S(speed_update); +// if (time > 0.05) { // Max 900 RPM +// speed_time = time; +// speed_update = chVTGetSystemTimeX(); +// } +// } +// +// speed_last = speed; +// chThdSleep(1); +// } +//} + void hw_start_i2c(void) { i2cAcquireBus(&HW_I2C_DEV); @@ -322,21 +424,26 @@ void hw_try_restore_i2c(void) { } } -bool hw_sample_shutdown_button(void) { +bool smart_switch_is_pressed(void) { chMtxLock(&shutdown_mutex); + if (shutdown_sample_dis) { + chMtxUnlock(&shutdown_mutex); + return false; + } + bt_diff = 0.0; int samples = 10; for (int i = 0;i < samples;i++) { - palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_INPUT_ANALOG); + palSetPadMode(SWITCH_OUT_GPIO, SWITCH_OUT_PIN, PAL_MODE_INPUT_ANALOG); chThdSleep(5); float val1 = ADC_VOLTS(ADC_IND_SHUTDOWN); chThdSleepMilliseconds(5); float val2 = ADC_VOLTS(ADC_IND_SHUTDOWN); if (shutdown_hold_en) { - palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(SWITCH_OUT_GPIO, SWITCH_OUT_PIN, PAL_MODE_OUTPUT_PUSHPULL); } chThdSleepMilliseconds(1); @@ -348,25 +455,227 @@ bool hw_sample_shutdown_button(void) { chMtxUnlock(&shutdown_mutex); - return (bt_diff < 0.355); + return (bt_diff < 0.31); } void hw_shutdown_set_hold(bool hold) { shutdown_hold_en = hold; if (hold) { - palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); - palSetPad(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN); + palSetPadMode(SWITCH_OUT_GPIO, SWITCH_OUT_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); } else { - palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_INPUT_ANALOG); + palSetPadMode(SWITCH_OUT_GPIO, SWITCH_OUT_PIN, PAL_MODE_INPUT_ANALOG); } } -static void terminal_shutdown_now(int argc, const char **argv) { - (void)argc; - (void)argv; - DISABLE_GATE(); - HW_SHUTDOWN_HOLD_OFF(); +void smart_switch_shut_down(void) { + switch_state = SWITCH_SHUTTING_DOWN; +} + +static THD_FUNCTION(switch_color_thread, arg) { + (void)arg; + chRegSetThreadName("switch_color"); + float switch_red = 0.0; + float switch_green = 0.0; + float switch_blue = 0.0; + + for(int i = 0; i < 400; i++) { + float angle = i*3.14/400.0; + float s,c; + utils_fast_sincos_better(angle, &s, &c); + switch_blue = 0.75* c*c; + ledpwm_set_intensity(LED_HW1,switch_bright*switch_blue); + utils_fast_sincos_better(angle + 3.14/3.0, &s, &c); + switch_green = 0.75* c*c; + ledpwm_set_intensity(LED_HW2,switch_bright*switch_green); + utils_fast_sincos_better(angle + 6.28/3.0, &s, &c); + switch_red = 0.75* c*c; + ledpwm_set_intensity(LED_HW3,switch_bright*switch_red); + chThdSleepMilliseconds(4); + } + float switch_red_old = switch_red_old; + float switch_green_old = switch_green; + float switch_blue_old = switch_blue; + float wh_left; + float left = mc_interface_get_battery_level(&wh_left); + + if (left < 0.5) { + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + } else { + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + } + + for (int i = 0; i < 100; i++) { + float red_now = utils_map((float) i,0.0, 100.0, switch_red_old, switch_red); + float blue_now = utils_map((float) i,0.0, 100.0, switch_blue_old, switch_blue); + float green_now = utils_map((float) i,0.0, 100.0, switch_green_old, switch_green); + ledpwm_set_intensity(LED_HW1, switch_bright*blue_now); + ledpwm_set_intensity(LED_HW2, switch_bright*green_now); + ledpwm_set_intensity(LED_HW3, switch_bright*red_now); + chThdSleepMilliseconds(2); + } + + for (;;) { + mc_fault_code fault = mc_interface_get_fault(); + + if (fault != FAULT_CODE_NONE) { + ledpwm_set_intensity(LED_HW2, 0); + ledpwm_set_intensity(LED_HW1, 0); + for (int i = 0;i < (int)fault;i++) { + ledpwm_set_intensity(LED_HW3, 1.0); + chThdSleepMilliseconds(250); + ledpwm_set_intensity(LED_HW3, 0.0); + chThdSleepMilliseconds(250); + } + + chThdSleepMilliseconds(500); + } else { + left = mc_interface_get_battery_level(&wh_left); + if (left < 0.5){ + float intense = utils_map(left,0.0, 0.5, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_blue = intense; + switch_red = 1.0-intense; + switch_green = 0; + } else { + float intense = utils_map(left , 0.5, 1.0, 0.0, 1.0); + utils_truncate_number(&intense,0,1); + switch_green = intense; + switch_blue = 1.0-intense; + switch_red = 0; + } + ledpwm_set_intensity(LED_HW1, switch_bright*switch_blue); + ledpwm_set_intensity(LED_HW2, switch_bright*switch_green); + ledpwm_set_intensity(LED_HW3, switch_bright*switch_red); + } + + chThdSleepMilliseconds(20); + } +} + +static THD_FUNCTION(smart_switch_thread, arg) { + (void)arg; + chRegSetThreadName("smart_switch"); + systime_t switch_pressed_ts = chVTGetSystemTimeX(); + + for (;;) { + const app_configuration *conf = app_get_configuration(); + + switch (switch_state) { + case SWITCH_BOOTED: + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + case SWITCH_TURN_ON_DELAY_ACTIVE: + switch_state = SWITCH_HELD_AFTER_TURN_ON; + + // Wait for other systems to boot up before proceeding + while (!main_init_done()) { + chThdSleepMilliseconds(200); + } + break; + + case SWITCH_HELD_AFTER_TURN_ON: + if (smart_switch_is_pressed() && conf->shutdown_mode != SHUTDOWN_MODE_ALWAYS_OFF) { + switch_state = SWITCH_HELD_AFTER_TURN_ON; + } else { + switch_state = SWITCH_TURNED_ON; + } + break; + + case SWITCH_TURNED_ON: + if (conf->shutdown_mode == SHUTDOWN_MODE_ALWAYS_OFF) { + switch_bright = 1.0; + if (!smart_switch_is_pressed()) { + switch_state = SWITCH_SHUTTING_DOWN; + } + } else { + if (smart_switch_is_pressed() && + conf->shutdown_mode != SHUTDOWN_MODE_ALWAYS_ON) { + switch_bright = 0.5; + } else { + switch_bright = 1.0; + switch_pressed_ts = chVTGetSystemTimeX(); + } + + if (UTILS_AGE_S(switch_pressed_ts) > ((float)(SMART_SWITCH_MSECS_PRESSED_OFF) / 1000.0)) { + switch_state = SWITCH_SHUTTING_DOWN; +#ifdef USE_LISPBM + lispif_process_shutdown(); +#endif + } + } + break; + + case SWITCH_SHUTTING_DOWN: + switch_bright = 0; + systime_t tStart = chVTGetSystemTimeX(); + while (smart_switch_is_pressed()) { + chThdSleepMilliseconds(10); + if (UTILS_AGE_S(tStart) > 10.0) { + switch_pressed_ts = chVTGetSystemTimeX(); + switch_state = SWITCH_TURNED_ON; + break; + } + } + + if (switch_state == SWITCH_TURNED_ON) { + break; + } + + shutdown_save_and_hold(); + comm_can_shutdown(255); + mc_interface_set_current(0); + mc_interface_lock(); + hw_shutdown_set_hold(false); + chThdSleepMilliseconds(10000); + + // Shutdown never happened + mc_interface_unlock(); + hw_shutdown_set_hold(true); + switch_state = SWITCH_TURN_ON_DELAY_ACTIVE; + break; + + default: + break; + } + + chThdSleepMilliseconds(1); + } +} + +void smart_switch_thread_start(void) { + chThdCreateStatic(smart_switch_thread_wa, sizeof(smart_switch_thread_wa), + NORMALPRIO, smart_switch_thread, NULL); +} + +void smart_switch_pin_init(void) { + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); + + palSetPadMode(SWITCH_OUT_GPIO,SWITCH_OUT_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_2_GPIO,SWITCH_LED_2_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN, PAL_MODE_OUTPUT_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST); + palSetPad(SWITCH_OUT_GPIO, SWITCH_OUT_PIN); + LED_SWITCH_B_ON(); + LED_SWITCH_R_OFF(); + LED_SWITCH_G_OFF(); + return; +} + +void smart_switch_set_sampling_disabled(bool dis) { + chMtxLock(&shutdown_mutex); + shutdown_sample_dis = dis; + chMtxUnlock(&shutdown_mutex); } static void terminal_button_test(int argc, const char **argv) { @@ -374,7 +683,7 @@ static void terminal_button_test(int argc, const char **argv) { (void)argv; for (int i = 0;i < 40;i++) { - commands_printf("BT: %d %.2f", HW_SAMPLE_SHUTDOWN(), (double)bt_diff); + commands_printf("BT: %d %.2f", smart_switch_is_pressed(), (double)bt_diff); chThdSleepMilliseconds(100); } } diff --git a/hwconf/vesc/minim/hw_minim_core.h b/hwconf/vesc/minim/hw_minim_core.h index 60aff040d9..1b562cfa7a 100644 --- a/hwconf/vesc/minim/hw_minim_core.h +++ b/hwconf/vesc/minim/hw_minim_core.h @@ -1,5 +1,5 @@ /* - Copyright 2023 Benjamin Vedder benjamin@vedder.se + Copyright 2023 - 2026 Benjamin Vedder benjamin@vedder.se This file is part of the VESC firmware. @@ -22,6 +22,8 @@ #ifdef HW_MINIM #define HW_NAME "Minim" +#elif defined (HW_MINIM_W60) + #define HW_NAME "Minim W60" #else #error "Must define hardware type" #endif @@ -31,6 +33,10 @@ #define HW_HAS_PHASE_FILTERS #define INVERTED_SHUNT_POLARITY +#ifdef HW_MINIM_W60 +#define HW_BOOT_VESC_CAN +#endif + // Macros #define LED_GREEN_GPIO GPIOB #define LED_GREEN_PIN 7 @@ -65,15 +71,40 @@ #define OUT_3_OFF() palClearPad(OUT_3_GPIO, OUT_3_PIN) // Shutdown pin -#define HW_SHUTDOWN_GPIO GPIOA -#define HW_SHUTDOWN_PIN 5 -#define HW_SHUTDOWN_HOLD_ON() hw_shutdown_set_hold(true) -#define HW_SHUTDOWN_HOLD_OFF() hw_shutdown_set_hold(false) -#define HW_SAMPLE_SHUTDOWN() hw_sample_shutdown_button() -#define HW_SHUTDOWN_NO - -// Hold shutdown pin early to wake up on short pulses -#define HW_EARLY_INIT() HW_SHUTDOWN_HOLD_ON() +#define HW_SHUTDOWN_NO // Normally open switch +#define HW_SHUTDOWN_HOLD_ON() +#define HW_SAMPLE_SHUTDOWN() 1 +#define HW_SHUTDOWN_HOLD_OFF() smart_switch_shut_down() +#define SHUTDOWN_SET_SAMPLING_DISABLED(d) smart_switch_set_sampling_disabled(d); \ + shutdown_set_sampling_disabled(d) + +#define HW_EARLY_INIT() smart_switch_pin_init(); \ + smart_switch_thread_start(); + +#define SMART_SWITCH_MSECS_PRESSED_OFF 1500 + +#define SWITCH_OUT_GPIO GPIOA +#define SWITCH_OUT_PIN 5 +#define SWITCH_LED_3_GPIO GPIOB +#define SWITCH_LED_3_PIN 12 +#define SWITCH_LED_2_GPIO GPIOC +#define SWITCH_LED_2_PIN 12 +#define SWITCH_LED_1_GPIO GPIOC +#define SWITCH_LED_1_PIN 9 + +#define LED_PWM1_ON() palClearPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM1_OFF() palSetPad(SWITCH_LED_1_GPIO,SWITCH_LED_1_PIN) +#define LED_PWM2_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM2_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_PWM3_ON() palClearPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) +#define LED_PWM3_OFF() palSetPad(SWITCH_LED_3_GPIO, SWITCH_LED_3_PIN) + +#define LED_SWITCH_R_ON() palClearPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_R_OFF() palSetPad(SWITCH_LED_3_GPIO,SWITCH_LED_3_PIN) +#define LED_SWITCH_G_ON() palClearPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_G_OFF() palSetPad(SWITCH_LED_2_GPIO, SWITCH_LED_2_PIN) +#define LED_SWITCH_B_ON() palClearPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) +#define LED_SWITCH_B_OFF() palSetPad(SWITCH_LED_1_GPIO, SWITCH_LED_1_PIN) /* * ADC Vector @@ -153,8 +184,10 @@ // COMM-port ADC GPIOs #define HW_ADC_EXT_GPIO GPIOA #define HW_ADC_EXT_PIN 3 -#define HW_ADC_EXT2_GPIO GPIOA -#define HW_ADC_EXT2_PIN 6 +#define HW_ADC_EXT2_GPIO GPIOB +#define HW_ADC_EXT2_PIN 0 +#define HW_ADC_EXT3_GPIO GPIOA +#define HW_ADC_EXT3_PIN 7 // UART Peripheral #define HW_UART_DEV SD3 @@ -236,39 +269,57 @@ #define HW_DEAD_TIME_NSEC 200.0 // Default setting overrides -#ifndef MCCONF_L_MIN_VOLTAGE -#define MCCONF_L_MIN_VOLTAGE 15.0 // Minimum voltage input -#endif -#ifndef MCCONF_L_MAX_VOLTAGE -#define MCCONF_L_MAX_VOLTAGE 90.0 // Maximum input voltage -#endif #ifndef MCCONF_DEFAULT_MOTOR_TYPE #define MCCONF_DEFAULT_MOTOR_TYPE MOTOR_TYPE_FOC #endif #ifndef MCCONF_FOC_F_ZV #define MCCONF_FOC_F_ZV 30000.0 #endif +#ifndef APPCONF_SHUTDOWN_MODE +#define APPCONF_SHUTDOWN_MODE SHUTDOWN_MODE_TOGGLE_BUTTON_ONLY +#endif #ifndef MCCONF_L_MAX_ABS_CURRENT -#define MCCONF_L_MAX_ABS_CURRENT 80.0 // The maximum absolute current above which a fault is generated +#define MCCONF_L_MAX_ABS_CURRENT 80.0 #endif #ifndef MCCONF_L_IN_CURRENT_MAX -#define MCCONF_L_IN_CURRENT_MAX 45.0 // Input current limit in Amperes (Upper) +#define MCCONF_L_IN_CURRENT_MAX 45.0 #endif #ifndef MCCONF_L_IN_CURRENT_MIN -#define MCCONF_L_IN_CURRENT_MIN -45.0 // Input current limit in Amperes (Lower) +#define MCCONF_L_IN_CURRENT_MIN -45.0 +#endif +#ifndef MCCONF_L_MIN_VOLTAGE +#define MCCONF_L_MIN_VOLTAGE 15.0 #endif -// Setting limits +#ifdef HW_MINIM_W60 +#ifndef MCCONF_L_MAX_VOLTAGE +#define MCCONF_L_MAX_VOLTAGE 55.0 +#endif +#define HW_LIM_CURRENT -100.0, 100.0 +#define HW_LIM_CURRENT_IN -100.0, 100.0 +#define HW_LIM_CURRENT_ABS 0.0, 150.0 +#define HW_LIM_VIN 11.0, 57.0 +#else +#ifndef MCCONF_L_MAX_VOLTAGE +#define MCCONF_L_MAX_VOLTAGE 90.0 +#endif #define HW_LIM_CURRENT -65.0, 65.0 -#define HW_LIM_CURRENT_IN -60.0, 60.0 +#define HW_LIM_CURRENT_IN -65.0, 65.0 #define HW_LIM_CURRENT_ABS 0.0, 110.0 #define HW_LIM_VIN 11.0, 94.0 +#endif + #define HW_LIM_ERPM -200e3, 200e3 #define HW_LIM_DUTY_MIN 0.0, 0.1 #define HW_LIM_DUTY_MAX 0.0, 0.99 #define HW_LIM_TEMP_FET -40.0, 110.0 -bool hw_sample_shutdown_button(void); +// Functions +void smart_switch_thread_start(void); +void smart_switch_pin_init(void); +bool smart_switch_is_pressed(void); void hw_shutdown_set_hold(bool hold); +void smart_switch_shut_down(void); +void smart_switch_set_sampling_disabled(bool dis); #endif /* HW_MINIM_CORE_H_ */ diff --git a/hwconf/vesc/minim/hw_minim_w60.h b/hwconf/vesc/minim/hw_minim_w60.h new file mode 100644 index 0000000000..9a88537eb7 --- /dev/null +++ b/hwconf/vesc/minim/hw_minim_w60.h @@ -0,0 +1,27 @@ +/* + Copyright 2026 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef HW_MINIM_W60_H_ +#define HW_MINIM_W60_H_ + +#define HW_MINIM_W60 + +#include "hw_minim_core.h" + +#endif /* HW_MINIM_W60_H_ */ diff --git a/hwconf/vesc/pronto/hw_pronto_core.c b/hwconf/vesc/pronto/hw_pronto_core.c index b8e6f224a1..080b72fc47 100644 --- a/hwconf/vesc/pronto/hw_pronto_core.c +++ b/hwconf/vesc/pronto/hw_pronto_core.c @@ -48,8 +48,8 @@ static lbm_value ext_reg_v(lbm_value *args, lbm_uint argn) { static lbm_value ext_reg_i(lbm_value *args, lbm_uint argn) { (void)args; (void)argn; float adc = (float)ADC_Value[ADC_IND_12V_SENSE_I]; - // 0.01 ohm, shunt amp same as rest of hw - return lbm_enc_float((adc * (V_REG / 4095.0) - (V_REG / 2.0)) / (CURRENT_AMP_GAIN * 0.01)); + // 0.01 ohm, 20x shunt amp + return lbm_enc_float((adc * (V_REG / 4095.0)) / (20.0 * 0.01)); } static lbm_value ext_reg_t(lbm_value *args, lbm_uint argn) { @@ -157,7 +157,7 @@ void hw_setup_adc_channels(void) { ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_15Cycles); // 3 ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, ADC_SampleTime_15Cycles); // 6 ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_15Cycles); // 9 - ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 5, ADC_SampleTime_15Cycles); // 12 + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_15Cycles); // 12 ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 6, ADC_SampleTime_15Cycles); // 15 // ADC2 regular channels @@ -171,10 +171,10 @@ void hw_setup_adc_channels(void) { // ADC3 regular channels ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); // 2 ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 2, ADC_SampleTime_15Cycles); // 5 - ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 3, ADC_SampleTime_15Cycles); // 8 - ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 4, ADC_SampleTime_15Cycles); // 11 - ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 5, ADC_SampleTime_15Cycles); // 14 - ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 6, ADC_SampleTime_15Cycles); // 17 + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 3, ADC_SampleTime_15Cycles); // 8 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 4, ADC_SampleTime_15Cycles); // 11 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 5, ADC_SampleTime_15Cycles); // 14 + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 6, ADC_SampleTime_15Cycles); // 17 // Injected channels ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); @@ -302,11 +302,13 @@ static THD_FUNCTION(mux_thread, arg) { PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); -#define T_SAMP_US 400 +#define T_SAMP_US 500 for (;;) { ADCMUX_MOT_TEMP(); - chThdSleepMicroseconds(T_SAMP_US); + // Wait longer on this one as some temperature sensors, e.g. the PT1000 change very little + // and the voltage divider gives us bad resolution for it. + chThdSleepMilliseconds(5); ADC_Value[ADC_IND_TEMP_MOTOR] = ADC_Value[ADC_IND_ADC_MUX]; ADCMUX_12V_SENSE_V(); @@ -324,6 +326,41 @@ static THD_FUNCTION(mux_thread, arg) { ADCMUX_TEMP_DCDC(); chThdSleepMicroseconds(T_SAMP_US); ADC_Value[ADC_IND_TEMP_DCDC] = ADC_Value[ADC_IND_ADC_MUX]; + + // Config check + mc_configuration *mcconf = (mc_configuration*)mc_interface_get_configuration(); + + if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_HALL) { + + // In hall sensor mode we use the ADC pins on the comm-port as additional + // pull-ups as the voltage dividers take the voltage down otherwise. + palSetPadMode(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN); + palSetPad(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN); + + // Prevent the uart-pins from interfering + palSetPadMode(HW_UART_TX_PORT, HW_UART_TX_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_UART_RX_PORT, HW_UART_RX_PIN, PAL_MODE_INPUT); + } else if (mcconf->motor_type == MOTOR_TYPE_FOC && + mcconf->foc_sensor_mode == FOC_SENSOR_MODE_ENCODER) { + + // Prevent the uart-pins from interfering + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_ABI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_AS5047_SPI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_PWM_ABI || + mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_UART_TX_PORT, HW_UART_TX_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_UART_RX_PORT, HW_UART_RX_PIN, PAL_MODE_INPUT); + } + + // Ensure that the sin/cos pins are in ADC mode + if (mcconf->m_sensor_port_mode == SENSOR_PORT_MODE_SINCOS) { + palSetPadMode(HW_ADC_EXT3_GPIO, HW_ADC_EXT3_PIN, PAL_MODE_INPUT_ANALOG); + palSetPadMode(HW_ADC_EXT4_GPIO, HW_ADC_EXT4_PIN, PAL_MODE_INPUT_ANALOG); + } + } } } diff --git a/hwconf/vesc/pronto/hw_pronto_core.h b/hwconf/vesc/pronto/hw_pronto_core.h index 5310e518f0..2b2dff8237 100644 --- a/hwconf/vesc/pronto/hw_pronto_core.h +++ b/hwconf/vesc/pronto/hw_pronto_core.h @@ -30,6 +30,7 @@ #define HW_HAS_3_SHUNTS #define HW_HAS_PHASE_FILTERS #define HW_HAS_PHASE_SHUNTS +#define HW_BOOT_VESC_CAN #define COMM_USE_USB 0 @@ -91,11 +92,11 @@ #define HW_SAMPLE_SHUTDOWN() hw_sample_shutdown_button() #define HW_SHUTDOWN_NO // Normally open button -// Hold shutdown pin early to wake up on short pulses -#define HW_EARLY_INIT() palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); \ +#define HW_VERY_EARLY_INIT() RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); \ + palSetPadMode(HW_SHUTDOWN_GPIO, HW_SHUTDOWN_PIN, PAL_MODE_OUTPUT_PUSHPULL); \ HW_SHUTDOWN_HOLD_ON(); -#define MCPWM_FOC_CURRENT_SAMP_OFFSET (2) // Offset from timer top for ADC samples +#define HW_EARLY_INIT() HW_VERY_EARLY_INIT() /* * ADC Vector @@ -112,14 +113,13 @@ #define ADC_IND_SENS1 3 #define ADC_IND_SENS2 4 #define ADC_IND_SENS3 5 -#define ADC_IND_VIN_SENS 11 +#define ADC_IND_VIN_SENS 8 #define ADC_IND_EXT5 16 #define ADC_IND_EXT 6 #define ADC_IND_EXT2 7 -#define ADC_IND_EXT3 8 -#define ADC_IND_VREFINT 12 +#define ADC_IND_EXT3 14 #define ADC_IND_ADC_MUX 15 -#define ADC_IND_EXT4 9 +#define ADC_IND_EXT4 12 #define ADC_IND_SHUTDOWN 13 #define ADC_IND_EXT6 13 @@ -269,7 +269,7 @@ #define MCCONF_L_MIN_VOLTAGE 20.0 // Minimum input voltage #endif #ifndef MCCONF_L_MAX_VOLTAGE -#define MCCONF_L_MAX_VOLTAGE 100.0 // Maximum input voltage +#define MCCONF_L_MAX_VOLTAGE 94.0 // Maximum input voltage #endif #ifndef MCCONF_FOC_F_ZV #define MCCONF_FOC_F_ZV 30000.0 @@ -287,7 +287,7 @@ #define MCCONF_L_IN_CURRENT_MIN -150.0 // Input current limit in Amperes (Lower) #endif #ifndef APPCONF_SHUTDOWN_MODE -#define APPCONF_SHUTDOWN_MODE SHUTDOWN_MODE_ALWAYS_ON +#define APPCONF_SHUTDOWN_MODE SHUTDOWN_MODE_ALWAYS_OFF #endif #ifndef APPCONF_APP_TO_USE #define APPCONF_APP_TO_USE APP_NONE @@ -297,7 +297,7 @@ #define HW_LIM_CURRENT -200.0, 200.0 #define HW_LIM_CURRENT_IN -200.0, 200.0 #define HW_LIM_CURRENT_ABS 0.0, 300.0 -#define HW_LIM_VIN 20.0, 110.0 +#define HW_LIM_VIN 20.0, 97.0 #define HW_LIM_ERPM -200e3, 200e3 #define HW_LIM_DUTY_MIN 0.0, 0.1 #define HW_LIM_DUTY_MAX 0.0, 0.99 diff --git a/hwconf/vesc/str365/hw_str365_core.c b/hwconf/vesc/str365/hw_str365_core.c index 42dbff046d..4e73cfdd76 100644 --- a/hwconf/vesc/str365/hw_str365_core.c +++ b/hwconf/vesc/str365/hw_str365_core.c @@ -346,11 +346,13 @@ static THD_FUNCTION(mux_thread, arg) { PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); -#define T_SAMP_US 400 +#define T_SAMP_US 500 for (;;) { ADCMUX_MOT_TEMP(); - chThdSleepMicroseconds(T_SAMP_US); + // Wait longer on this one as some temperature sensors, e.g. the PT1000 change very little + // and the voltage divider gives us bad resolution for it. + chThdSleepMilliseconds(5); ADC_Value[ADC_IND_TEMP_MOTOR] = ADC_Value[ADC_IND_ADC_MUX]; ADCMUX_12V_SENSE_V(); diff --git a/lispBM/README.md b/lispBM/README.md index 2e2236d446..e03df96dc8 100644 --- a/lispBM/README.md +++ b/lispBM/README.md @@ -1910,6 +1910,85 @@ Returns the difference between the observer position and the encoder position ma --- +#### phase-all + +| Platforms | Firmware | +|---|---| +| ESC | 6.06.1+ | + +```clj +(phase-all) +``` + +Returns a list of phases and various phase errors, all sampled at the same time. This can be used for doing encoder error mapping and creating encoder error correction tables. Returns the folliwing list of values, all in degrees: + +```clj +( + phase_observer ; Observer phase + phase_encoder ; Encoder phase, derived from current encoder settings + phase_bemf ; Phase derived from the back-emf (only valid when undriven) + pos_encoder ; Encoder angle reading in encoder reference frame + err_observer_encoder ; Phase error between observer and encoder + err_bemf_encoder ; Phase error between back-emf and encoder + err_observer_bemf ; Phase error between observer and back-emf +) +``` + +--- + +#### enc-corr + +| Platforms | Firmware | +|---|---| +| ESC | 6.06.1+ | + +```clj +(enc-corr angle optCorr) +``` + +Get (or set) encoder correction for angle. The angle is in the encoder reference frame and the correction is in the FOC reference frame. Returns the correction value for angle. The optional value optCorr can be used to update the correction value at angle, if it is left out only the old value will be returned. The correction is applied in the FOC reference frame, so it should be the error on the FOC motor phase that the encoder causes. + +Example: + +```clj +; Prints encoder correction value for 10 degrees. Read only, nothing is chaged. +(print (enc-corr 10)) + +; Set encoder correction value for 10 degrees to -5 degrees. +(enc-corr 10 -5) +``` + +--- + +--- + +#### enc-corr-en + +| Platforms | Firmware | +|---|---| +| ESC | 6.06.1+ | + +```clj +(enc-corr-en optEn) +``` + +Returns 1 if encoder correction is enabled and 0 if it is disabled. The optional argument optEn can be used to enable or disable encoder correction. + +Example: + +```clj +; Prints 1 if correction is enabled, 0 otherwise. Read only, nothing is chaged. +(print (enc-corr-en)) + +; Enable correction +(enc-corr-en 1) + +; Disable correction +(enc-corr-en 0) +``` + +--- + ### Setup Values These commands return the accumulated values from all VESC-based motor controllers on the CAN-bus. Note that the corresponding CAN status messages must be activated for these commands to work. @@ -2482,12 +2561,18 @@ Example: ```clj ; Configuration update on ID54: -(can-cmd 54 "(conf-set max-speed 10.0)") +(can-cmd 54 "(conf-set 'max-speed 10.0)") ; The string-functions can be used for setting something from a variable (def max-speed-kmh 25.0) (can-cmd 54 (str-from-n (/ max-speed-kmh 3.6) "(conf-set 'max-speed %.3f)")) ``` + +**Note** +can-cmd is limited to two commands per second per device. If commands are sent more often that that they are ignored. + +**Note2** +A better way to achieve something similar to can-cmd but with much less overhead and unlimited rate is using the [Code Server](https://github.com/vedderb/vesc_pkg/tree/main/lib_code_server) library. --- @@ -3694,6 +3779,7 @@ The following selection of app and motor parameters can be read and set from Lis ; 12: SENSOR_PORT_MODE_CUSTOM_ENCODER ; 13: SENSOR_PORT_MODE_PWM ; 14: SENSOR_PORT_MODE_PWM_ABI +'m-fault-stop-time-ms ; Milliseconds to stop the motor for after fauls (FW6.06.5) 'si-motor-poles ; Number of motor poles, must be multiple of 2 'si-gear-ratio ; Gear ratio (Added in FW 6.05) 'si-wheel-diameter ; Wheel diameter in meters (Added in FW 6.05) @@ -3772,15 +3858,21 @@ The following selection of app and motor parameters can be read and set from Lis 'controller-id ; VESC CAN ID 'timeout-msec ; Motor timeout in milliseconds (Added in FW 6.06) 'can-baud-rate ; CAN-bus baud rate (Added in FW 6.05) - ; 0: 125K - ; 1: 250K - ; 2: 500K - ; 3: 1M - ; 4: 10K - ; 5: 20K - ; 6: 50K - ; 7: 75K - ; 8: 100K + ; 0: 125K + ; 1: 250K + ; 2: 500K + ; 3: 1M + ; 4: 10K + ; 5: 20K + ; 6: 50K + ; 7: 75K + ; 8: 100K +'can-mode ; CAN-bus mode (FW 6.05.3+) + ; 0: 125K + ; 1: VESC + ; 2: UAVCAN + ; 3: COMM Bridge + ; 4: Unused 'can-status-rate-1 ; CAN status rate 1 in Hz (Added in FW 6.05) 'can-status-msgs-r1 ; Bitfield with the status messages (Added in FW 6.05) ; Bit0: Status 1 (RPM, Current, Duty) @@ -3809,6 +3901,7 @@ The following selection of app and motor parameters can be read and set from Lis 'ppm-pulse-center ; Pulse corresponding to center throttle in ms 'ppm-ramp-time-pos ; Positive ramping time in seconds 'ppm-ramp-time-neg ; Negative ramping time in seconds +'ppm-hyst ; Input deadband, range 0 to 1 (Added in FW 6.06.5) 'adc-ctrl-type ; ADC Control Type (Added in FW 6.02) ; 0: ADC_CTRL_TYPE_NONE ; 1: ADC_CTRL_TYPE_CURRENT @@ -3827,7 +3920,7 @@ The following selection of app and motor parameters can be read and set from Lis ; 14: ADC_CTRL_TYPE_PID_REV_BUTTON 'adc-ramp-time-pos ; Positive ramping time in seconds (Added in FW 6.05) 'adc-ramp-time-neg ; Negative ramping time in seconds (Added in FW 6.05) -'adc-thr-hyst ; Throttle hysteresis, range 0 to 1 (Added in FW 6.05) +'adc-thr-hyst ; Throttle deadband, range 0 to 1 (Added in FW 6.05) 'adc-v1-start ; Throttle 1 start voltage (Added in FW 6.05) 'adc-v1-end ; Throttle 1 end voltage (Added in FW 6.05) 'adc-v1-min ; Throttle 1 low fault voltage (Added in FW 6.05) @@ -3837,20 +3930,20 @@ The following selection of app and motor parameters can be read and set from Lis ; Express settings (Added in 6.05) 'controller-id ; VESC CAN ID 'can-baud-rate ; CAN-bus baud rate - ; 0: 125K - ; 1: 250K - ; 2: 500K - ; 3: 1M - ; 4: 10K - ; 5: 20K - ; 6: 50K - ; 7: 75K - ; 8: 100K + ; 0: 125K + ; 1: 250K + ; 2: 500K + ; 3: 1M + ; 4: 10K + ; 5: 20K + ; 6: 50K + ; 7: 75K + ; 8: 100K 'can-status-rate-hz ; CAN status message rate 'wifi-mode ; Wifi mode - ; 0: Disabled - ; 1: Station - ; 2: Access Point + ; 0: Disabled + ; 1: Station + ; 2: Access Point 'wifi-sta-ssid ; Wifi station SSID 'wifi-sta-key ; Wifi station Key 'wifi-ap-ssid ; Wifi access point SSID @@ -3862,10 +3955,10 @@ The following selection of app and motor parameters can be read and set from Lis 'tcp-hub-id ; TCP hub connection ID 'tcp-hub-pass ; TCP hub password 'ble-mode ; BLE mode - ; 0: Disabled - ; 1: Enabled - ; 2: Enabled and encrypted with pin - ; 3: Enabled with scripting + ; 0: Disabled + ; 1: Enabled + ; 2: Enabled and encrypted with pin + ; 3: Enabled with scripting 'ble-name ; Device name (also the name that shows up in VESC Tool) 'ble-pin ; BLE pin code 'ble-service-capacity ; BLE Service Capacity @@ -3926,6 +4019,20 @@ Store the current configuration to flash. This will stop the motor. Note: On the --- +#### store-backup + +| Platforms | Firmware | +|---|---| +| ESC | 6.06.6+ | + +```clj +(store-backup) +``` + +Store backup data, such as odometer and runtime counter, to flash. This will stop the motor. conf-store will also store this data, but this function alone is much faster as the configurations are not stored. + +--- + #### conf-detect-foc | Platforms | Firmware | @@ -4179,6 +4286,20 @@ Example: --- +#### conf-detect-hall + +| Platforms | Firmware | +|---|---| +| ESC | 6.06.1+ | + +```clj +(conf-detect-hall current) +``` + +Runs hall sensor detection using current in openloop. Returns the hall sensor table as a byte array on success or nil on failure. + +--- + ### EEPROM (Nonvolatile Storage) Up to 128 (256 in FW 6.06) variables (int32 or float) can be stored in a nonvolatile memory reserved for LispBM. These variables persist between power cycles and configuration changes, but not between firmware updates. Keep in mind that the motor will be stopped briefly when writing them and that they only can be written a limited number of times (about 100 000 writes) before wear on the flash memory starts to become an issue. @@ -6707,7 +6828,10 @@ When a SD-card is present in the VESC Express files can be listed, read, written (f-connect pin-mosi pin-miso pin-sck pin-cs optSpiSpeed) ``` -Connect SD-card on pin-mosi, pin-miso, pin-sck and pin-cs. The optional argument optSpiSpeed can be used to specify the SPI speed (default 20000 Hz). Returns true on success, nil otherwise. +Connect SD-card on pin-mosi, pin-miso, pin-sck and pin-cs. The optional argument optSpiSpeed can be used to specify the SPI speed (default 20000 Hz). Returns true on success, nil otherwise. + +**NOTE** +This is only needed if you connect a memory card manually to hardware that does not come with one. Hardware such as the [VESC Nanolog](https://www.vesclabs.com/product/vl-nanolog/) already has the memory card connected and initialized, so you can use the file operations right away. --- diff --git a/lispBM/chtime.h b/lispBM/chtime.h new file mode 100644 index 0000000000..64b2718d15 --- /dev/null +++ b/lispBM/chtime.h @@ -0,0 +1,8 @@ +// Dummy file for platform_timestamp to build + +#ifndef LISPBM_CHTIME_H_ +#define LISPBM_CHTIME_H_ + + + +#endif /* LISPBM_CHTIME_H_ */ diff --git a/lispBM/lispBM/README.md b/lispBM/lispBM/README.md index ed4cd5999d..76fdd5b71a 100644 --- a/lispBM/lispBM/README.md +++ b/lispBM/lispBM/README.md @@ -1,3 +1,9 @@ +[![Website](https://img.shields.io/badge/Website-lispbm.com-blue)](https://www.lispbm.com) +[![Documentation](https://img.shields.io/badge/docs-latest-brightgreen)](https://www.lispbm.com/#documentation) +[![Discord](https://img.shields.io/badge/Discord-Join%20Server-7289da?logo=discord&logoColor=white)](https://discord.gg/urtJUUMnwQ) +[![Gallery](https://img.shields.io/badge/Gallery-Community%20Projects-green?logo=image)](https://www.lispbm.com/gallery.html) +[![Contributors](https://img.shields.io/badge/Contributors-Meet%20Our%20Team-blue?logo=github)](https://www.lispbm.com/contributors.html) + # lispBM (LBM) LispBM is a lisp or scheme like programming language for diff --git a/lispBM/lispBM/benchmarks/bench_chibi/Makefile b/lispBM/lispBM/benchmarks/bench_chibi/Makefile index 2c95ede58f..5238470dc3 100644 --- a/lispBM/lispBM/benchmarks/bench_chibi/Makefile +++ b/lispBM/lispBM/benchmarks/bench_chibi/Makefile @@ -139,7 +139,8 @@ LBMSRC = ../../src/env.c \ ../../src/lbm_flat_value.c \ ../../src/lbm_defrag_mem.c \ ../../src/lbm_image.c \ - ../../platform/chibios/src/platform_mutex.c + ../../platform/chibios/src/platform_mutex.c \ + ../../platform/chibios/src/platform_timestamp.c CSRC = $(ALLCSRC) \ $(TESTSRC) \ diff --git a/lispBM/lispBM/benchmarks/bench_chibi/main.c b/lispBM/lispBM/benchmarks/bench_chibi/main.c index 7e1df51417..a558ea6adc 100644 --- a/lispBM/lispBM/benchmarks/bench_chibi/main.c +++ b/lispBM/lispBM/benchmarks/bench_chibi/main.c @@ -143,10 +143,8 @@ static bool lbm_wait_ctx(lbm_cid cid, lbm_uint timeout_ms) { } if (exists) { - if (sleep_callback) { - sleep_callback(10); - } - if (timeout_ms > 0) i ++; + sleep_callback(10); + if (timeout_ms > 0) i ++; } } while (exists && i < timeout_ms); @@ -171,13 +169,6 @@ void done_callback(eval_context_t *ctx) { } } -uint32_t timestamp_callback(void) { - systime_t t = chVTGetSystemTime(); - uint32_t ts = (uint32_t) ((1000000 / CH_CFG_ST_FREQUENCY) * t); - //chprintf(chp,"timestamp %d\r\n ", ts); - return ts; -} - static THD_FUNCTION(eval, arg) { (void) arg; lbm_run_eval(); @@ -268,7 +259,6 @@ int main(void) { } lbm_set_ctx_done_callback(done_callback); - lbm_set_timestamp_us_callback(timestamp_callback); lbm_set_usleep_callback(sleep_callback); lbm_set_verbose(true); diff --git a/lispBM/lispBM/doc/c_doc/building.dox b/lispBM/lispBM/doc/c_doc/building.dox index 4f4409091e..4ec0ca591b 100644 --- a/lispBM/lispBM/doc/c_doc/building.dox +++ b/lispBM/lispBM/doc/c_doc/building.dox @@ -28,6 +28,7 @@ These should be added as a -D... flag to the C compiler for the LispBM compilati
  • LBM_USE_TIME_QUOTA - Use scheduler with time-based quotas instead of evaluator steps.
  • LBM_USE_EXT_MAILBOX_GET - loads the mailbox-get extension that allows introspection into mailboxes.
  • LBM_USE_ERROR_LINENO - Reports the line in eval_cps.c where the error was triggered. For debug use.
  • +
  • LBM_USE_MACRO_REST_ARGS - allow macros to access a rest-args list just like lambda defined functions.
  • The following preprocessor flags control code size optimizions on a per subsystem basis. diff --git a/lispBM/lispBM/doc/c_doc/integration.dox b/lispBM/lispBM/doc/c_doc/integration.dox new file mode 100644 index 0000000000..63ec61fa35 --- /dev/null +++ b/lispBM/lispBM/doc/c_doc/integration.dox @@ -0,0 +1,128 @@ +/** \page Integration LispBM Integration Safety Manual + +

    LispBM Integration Safety Manual

    + +

    Document Information

    + + + + + +
    Document Version:DRAFT
    LispBM Version:0.33.0
    Last Updated:September 2025
    + +

    Revision History

    + + + +

    Future versions of this document will include change logs +highlighting modifications to integration requirements, safety considerations, +and API changes that may affect existing integrations.

    + +

    Overview

    + +

    LispBM is designed to be integrated into larger systems as a sandboxed +scripting runtime that interacts with the host system through well-defined, +controlled mechanisms. This manual describes how to integrate LispBM correctly +to maintain system safety and reliability.

    + +

    An incorrectly integrated LispBM can compromise sandboxing, cause system +instability, memory corruption, or unpredictable behavior. This document +provides safety-focused integration guidelines.

    + +

    Sandboxed runtime system

    + +

    The LispBM runtime system is designed such that it cannot access or manipulate any memory +not explicitly assigned to the runtime system for use as Heap, Arrays memory or image storage. +

    + +

    The programs running on the LispBM runtime system can communicate with the host application +through usage of extensions or message-passing (via an events system). Note that extensions +are implemented in C and can access, read/write, any memory. The extensions form the interface +between the host application and the LispBM applications. The lispBM runtime system can do nothing +to ensure that extensions are well behaved in relation to memory. +

    + +

    Integration requirements

    + +

    LispBM requires the following functionality to be supplied by a HAL or RTOS:

    + +
      +
    • A Thread abstraction.
    • +
    • A Mutex implementation.
    • +
    + +

    If Chibios, FreeRTOS, Zephyr is used, LispBM can use the threading support supplied by these RTOSes. + The threading abstraction is used at the border-line between the C application and the LispBM runtime system. + The C application will start a thread for running the LispBM runtime system and scheduler. +

    + +

    Mutexes are used on the inside of lispbm (as well as in the C application) to ensure that + communication between C and LispBM is safe. As mutexes are used internally, a LispBM mutex abstraction + is defined in the platform directory. +

    + +

    The LispBM mutex abstraction consists of:

    +
      +
    • A type: mutex_t.
    • +
    • Initialization function: bool mutex_init(mutex_t *m).
    • +
    • Lock function: void mutex_lock(mutex_t *m).
    • +
    • Unlock function: void mutex_unlock(mutex_t *m).
    • +
    + +

    Here a FreeRTOS implementation of the LispBM mutex abstraction is shown as an example:

    + +@code + +// In header file platform/freertos/include/platform_mutex.h +#include +#include +#include + +typedef SemaphoreHandle_t mutex_t; + +extern bool mutex_init(mutex_t *m); +extern void mutex_lock(mutex_t *m); +extern void mutex_unlock(mutex_t *m); + +// In source file platform/freertos/src/platform_mutex.c +#include "platform_mutex.h" + +bool mutex_init(mutex_t *m) { + *m = xSemaphoreCreateMutex(); + if (*m != NULL) + return true; + return false; +} + +void mutex_lock(mutex_t *m) { + xSemaphoreTake(*m, portMAX_DELAY); +} + +void mutex_unlock(mutex_t *m) { + xSemaphoreGive(*m); +} +@endcode + +

    Porting LispBM to a different HAL or RTOS, X, requires an +implementation of platform/X/include/platform_mutex.h +and platform/X/src/platform_mutex.c. + +

    Building the LispBM runtime system

    + +

    LispBM is compiled into an application by the integrator. While the LispBM +runtime system is thoroughly tested, differences in compiler version or libraries +could reveal bugs. A final set of integration tests on the system as a whole is +strongly recommended.

    + +

    Practical building instructions can be found here \ref Building.

    + +

    Configuring the LispBM runtime system

    + + + +*/ \ No newline at end of file diff --git a/lispBM/lispBM/doc/c_doc/mainpage.dox b/lispBM/lispBM/doc/c_doc/mainpage.dox index ad9aee4b8e..5bbc709af5 100644 --- a/lispBM/lispBM/doc/c_doc/mainpage.dox +++ b/lispBM/lispBM/doc/c_doc/mainpage.dox @@ -1,13 +1,19 @@ /** @mainpage LispBM -@author Bo Joel Svensson. +@author LispBM project http://www.lispbm.com https://github.com/svenssonjoel/lispBM +

    Build LispBM

    + Building instructions: \ref Building +

    Integration safety manual

    + +Integration safety manual: \ref Integration +

    Implementation documentation

    C Interoperation: \ref lbm_c_interop.h \ref lbm_c_interop.c
    diff --git a/lispBM/lispBM/examples/esp32c3/CMakeLists.txt b/lispBM/lispBM/examples/esp32c3/CMakeLists.txt new file mode 100644 index 0000000000..2ad5b44e43 --- /dev/null +++ b/lispBM/lispBM/examples/esp32c3/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) + +idf_build_set_property(COMPILE_OPTIONS "-DLBM_USE_ERROR_LINENO" APPEND) +project(repl) diff --git a/lispBM/lispBM/examples/esp32c3/README.md b/lispBM/lispBM/examples/esp32c3/README.md new file mode 100644 index 0000000000..a52db2bfb2 --- /dev/null +++ b/lispBM/lispBM/examples/esp32c3/README.md @@ -0,0 +1,46 @@ + +# LispBM REPL in FreeRTOS for esp32c3 + +The purpose of this example is to get people who want to try/use LispBM +started. This example sets up a thread for running LispBM programs +concurrently to the main application written in C. + +This example was developed using ESP-IDF v6.0-dev-1489-g4e036983a7. +Are you using a newer ESP-IDF and this example is no longer compiling, let me know. + +This code runs on the esp32c3-devkit-mini1 but likely runs fine on similar +development kits. + +# Building + +The example uses a flash partition for image storage. + +run: + +``` +idf.py partition-table +``` + +to process the partitions.csv file + +Then run: + +``` +idf.py build +``` + +followed by: + +``` +idf.py flash +``` + +Now connect to the development kit using a serial terminal (such as minicom) or run: + +``` +idf.py monitor +``` + +You can now interact with a simple REPL on your esp32c3. + + diff --git a/lispBM/lispBM/examples/esp32c3/main/CMakeLists.txt b/lispBM/lispBM/examples/esp32c3/main/CMakeLists.txt new file mode 100644 index 0000000000..4685cf3902 --- /dev/null +++ b/lispBM/lispBM/examples/esp32c3/main/CMakeLists.txt @@ -0,0 +1,24 @@ +idf_component_register(SRCS "main.c" + "../../../src/env.c" + "../../../src/eval_cps.c" + "../../../src/extensions.c" + "../../../src/fundamental.c" + "../../../src/heap.c" + "../../../src/lbm_memory.c" + "../../../src/print.c" + "../../../src/stack.c" + "../../../src/symrepr.c" + "../../../src/tokpar.c" + "../../../src/lispbm.c" + "../../../src/lbm_c_interop.c" + "../../../src/lbm_custom_type.c" + "../../../src/lbm_channel.c" + "../../../src/lbm_flat_value.c" + "../../../src/lbm_defrag_mem.c" + "../../../src/lbm_image.c" + "../../../platform/freertos/src/platform_mutex.c" + "../../../platform/freertos/src/platform_timestamp.c" + PRIV_REQUIRES spi_flash esp_partition esp_driver_uart + INCLUDE_DIRS "../../../include" + "../../../platform/freertos/include" + ) diff --git a/lispBM/lispBM/examples/esp32c3/main/main.c b/lispBM/lispBM/examples/esp32c3/main/main.c new file mode 100644 index 0000000000..24751c7b95 --- /dev/null +++ b/lispBM/lispBM/examples/esp32c3/main/main.c @@ -0,0 +1,216 @@ + +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_partition.h" +#include "driver/uart.h" + +#include +#include + + +// //////////////////////////////////////////////////////////// +// Flash storage handling for lbm image + +static const esp_partition_t *get_lbm_image_storage_partition(void) { + return esp_partition_find_first(ESP_PARTITION_TYPE_ANY, + ESP_PARTITION_SUBTYPE_ANY, + "lisp"); +} + + +// //////////////////////////////////////////////////////////// +// Lispbm configuration and initializaion + +#define GC_STACK_SIZE 256 +#define PRINT_STACK_SIZE 256 +#define HEAP_SIZE 4096 +#define EXTENSION_STORAGE_SIZE 256 + +static lbm_cons_t heap[HEAP_SIZE] __attribute__ ((aligned (8))); +static uint32_t memory_array[LBM_MEMORY_SIZE_8K]; +static uint32_t bitmap_array[LBM_MEMORY_BITMAP_SIZE_8K]; +static lbm_extension_t extensions[EXTENSION_STORAGE_SIZE]; + +static lbm_string_channel_state_t string_tok_state; +static lbm_char_channel_t string_tok; + +static void done_callback(eval_context_t *ctx) { + char buf[256]; + lbm_print_value(buf, 256, ctx->r); + printf("\n# %s\n", buf); +} + +static void usleep_callback(uint32_t us) { + TickType_t t = us / (portTICK_PERIOD_MS * 1000); + if (t == 0) t = 1; + vTaskDelay(t); +} + +static uint32_t image_size = 0; +static uint32_t *image_addr = NULL; +static esp_partition_mmap_handle_t image_mmap_handle; +static const esp_partition_t *lbm_image_partition; + +static bool image_write(uint32_t w, int32_t ix, bool const_heap) { + uint32_t offset = ix * 4; // byte location into partition + if (ESP_OK == esp_partition_write(lbm_image_partition, offset, &w, 4)) { + return true; + } + return false; +} + +static void eval_thread(void *arg) { + (void)arg; + lbm_run_eval(); + vTaskDelete(NULL); +} + +static bool startup_lbm(void) { + + if (!lbm_init(heap, HEAP_SIZE, + memory_array, LBM_MEMORY_SIZE_8K, + bitmap_array, LBM_MEMORY_BITMAP_SIZE_8K, + GC_STACK_SIZE, + PRINT_STACK_SIZE, + extensions, + EXTENSION_STORAGE_SIZE)) { + printf("failed initialize lbm\n"); + fflush(stdout); + esp_restart(); + } + + lbm_set_usleep_callback(usleep_callback); + lbm_set_ctx_done_callback(done_callback); + lbm_set_printf_callback(printf); + lbm_set_verbose(true); + + lbm_image_init(image_addr, + image_size, + image_write); + + if (!lbm_image_exists()) { + printf("Image does not exist - creating!\n"); + lbm_image_create("v01"); + } + if (!lbm_image_boot()) { + printf("Unable to boot image.\n"); + fflush(stdout); + esp_restart(); + } + printf("Image booted\n"); + + lbm_add_eval_symbols(); + + xTaskCreatePinnedToCore(eval_thread, "lbm_eval", 3072, NULL, 6, NULL, tskNO_AFFINITY); + return true; +} + +// //////////////////////////////////////////////////////////// +// UART + +static void init_uart(void) { + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + + uart_driver_install(UART_NUM_0, 512, 0, 0, NULL, 0); + uart_param_config(UART_NUM_0, &uart_config); + } + +// //////////////////////////////////////////////////////////// +// Put it all together +void app_main(void) +{ + init_uart(); + + lbm_image_partition = get_lbm_image_storage_partition(); + if (lbm_image_partition) { + printf("lbm_image_partition found\n"); + image_size = lbm_image_partition->size / sizeof(uint32_t); + } else { + printf("ERROR: cannot find lbm_image_partition\n"); + fflush(stdout); + esp_restart(); + } + + if (esp_partition_mmap(lbm_image_partition, + 0, + lbm_image_partition->size, + ESP_PARTITION_MMAP_DATA, + (const void**)&image_addr, + &image_mmap_handle) == ESP_OK) { + printf("Image paritition successfully mapped at %x\n", (unsigned int)image_addr); + } else { + printf("ERROR: cannot mmap image partition\n"); + fflush(stdout); + esp_restart(); + } + + startup_lbm(); + + + while (true) { + // HERE read user input + + static char input_buffer[512]; + static int pos = 0; + uint8_t data; + int len = uart_read_bytes(UART_NUM_0, &data, 1, 0); // Non-blocking read + + if (len > 0) { + if (data == '\n' || data == '\r') { + if (pos > 0) { + input_buffer[pos] = '\0'; + + if (strncmp(input_buffer, ":clear", 6) == 0 ) { + if (ESP_OK == esp_partition_erase_range(lbm_image_partition,0 ,lbm_image_partition->size)) { + // restart after clearing + esp_restart(); + } else { + printf("Failed to erase partition\n"); + } + } + + // Process the complete line + lbm_pause_eval(); + while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { + vTaskDelay(1); + } + + lbm_create_string_char_channel(&string_tok_state, + &string_tok, + input_buffer); + lbm_load_and_eval_expression(&string_tok); + lbm_continue_eval(); + + // The input_buffer will now be read by the reader in another thread. + // Give it some time to do what it does! + // More robust handling of this inter-thread communication is deisrable. + vTaskDelay(100 / portTICK_PERIOD_MS); + + pos = 0; // Reset for next input + printf(">"); fflush(stdout); + } + } else if (pos < sizeof(input_buffer) - 1) { + input_buffer[pos++] = data; + putchar(data); // Echo character + fflush(stdout); + } + } + + vTaskDelay(10 / portTICK_PERIOD_MS); + } + + printf("Restarting now.\n"); + + esp_restart(); +} + diff --git a/lispBM/lispBM/examples/esp32c3/partitions.csv b/lispBM/lispBM/examples/esp32c3/partitions.csv new file mode 100644 index 0000000000..3daaa2a2e5 --- /dev/null +++ b/lispBM/lispBM/examples/esp32c3/partitions.csv @@ -0,0 +1,6 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 512k, +lisp, data, nvs, , 512k, diff --git a/lispBM/lispBM/examples/esp32c3/sdkconfig b/lispBM/lispBM/examples/esp32c3/sdkconfig new file mode 100644 index 0000000000..2c867ce34f --- /dev/null +++ b/lispBM/lispBM/examples/esp32c3/sdkconfig @@ -0,0 +1,1407 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) 6.0.0 Project Configuration +# +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_DEDICATED_GPIO_SUPPORTED=y +CONFIG_SOC_UART_SUPPORTED=y +CONFIG_SOC_GDMA_SUPPORTED=y +CONFIG_SOC_UHCI_SUPPORTED=y +CONFIG_SOC_AHB_GDMA_SUPPORTED=y +CONFIG_SOC_GPTIMER_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED=y +CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y +CONFIG_SOC_TEMP_SENSOR_SUPPORTED=y +CONFIG_SOC_XT_WDT_SUPPORTED=y +CONFIG_SOC_PHY_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_SUPPORTS_SECURE_DL_MODE=y +CONFIG_SOC_EFUSE_KEY_PURPOSE_FIELD=y +CONFIG_SOC_EFUSE_HAS_EFUSE_RST_BUG=y +CONFIG_SOC_EFUSE_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_GPSPI_SUPPORTED=y +CONFIG_SOC_LEDC_SUPPORTED=y +CONFIG_SOC_I2C_SUPPORTED=y +CONFIG_SOC_SYSTIMER_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_HMAC_SUPPORTED=y +CONFIG_SOC_DIG_SIGN_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_MEMPROT_SUPPORTED=y +CONFIG_SOC_BOD_SUPPORTED=y +CONFIG_SOC_CLK_TREE_SUPPORTED=y +CONFIG_SOC_ASSIST_DEBUG_SUPPORTED=y +CONFIG_SOC_WDT_SUPPORTED=y +CONFIG_SOC_SPI_FLASH_SUPPORTED=y +CONFIG_SOC_RNG_SUPPORTED=y +CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y +CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y +CONFIG_SOC_LP_PERIPH_SHARE_INTERRUPT=y +CONFIG_SOC_PM_SUPPORTED=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_AES_SUPPORT_DMA=y +CONFIG_SOC_AES_GDMA=y +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_ARBITER_SUPPORTED=y +CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED=y +CONFIG_SOC_ADC_MONITOR_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=2 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=5 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=1 +CONFIG_SOC_ADC_PATT_LEN_MAX=8 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=4 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_DIGI_IIR_FILTER_NUM=2 +CONFIG_SOC_ADC_DIGI_MONITOR_NUM=2 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=83333 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=611 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_CALIBRATION_V1_SUPPORTED=y +CONFIG_SOC_ADC_SELF_HW_CALI_SUPPORTED=y +CONFIG_SOC_ADC_SHARED_POWER=y +CONFIG_SOC_APB_BACKUP_DMA=y +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED=y +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +CONFIG_SOC_CACHE_FREEZE_SUPPORTED=y +CONFIG_SOC_CACHE_MEMORY_IBANK_SIZE=0x4000 +CONFIG_SOC_CPU_CORES_NUM=1 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FLEXIBLE_INTC=y +CONFIG_SOC_CPU_HAS_CSR_PC=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=8 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=8 +CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=0x80000000 +CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=3072 +CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16 +CONFIG_SOC_DS_KEY_CHECK_MAX_WAIT_US=1100 +CONFIG_SOC_AHB_GDMA_VERSION=1 +CONFIG_SOC_GDMA_NUM_GROUPS_MAX=1 +CONFIG_SOC_GDMA_PAIRS_PER_GROUP_MAX=3 +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=22 +CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER=y +CONFIG_SOC_GPIO_FILTER_CLK_SUPPORT_APB=y +CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y +CONFIG_SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP=y +CONFIG_SOC_GPIO_IN_RANGE_MAX=21 +CONFIG_SOC_GPIO_OUT_RANGE_MAX=21 +CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK=0 +CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT=6 +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x00000000003FFFC0 +CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y +CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 +CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y +CONFIG_SOC_DEDIC_GPIO_OUT_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_GPIO_IN_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_PERIPH_ALWAYS_ENABLE=y +CONFIG_SOC_I2C_NUM=1 +CONFIG_SOC_HP_I2C_NUM=1 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_CMD_REG_NUM=8 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_HW_CLR_BUS=y +CONFIG_SOC_I2C_SUPPORT_XTAL=y +CONFIG_SOC_I2C_SUPPORT_RTC=y +CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST=y +CONFIG_SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS=y +CONFIG_SOC_I2S_NUM=1 +CONFIG_SOC_I2S_HW_VERSION_2=y +CONFIG_SOC_I2S_SUPPORTS_XTAL=y +CONFIG_SOC_I2S_SUPPORTS_PLL_F160M=y +CONFIG_SOC_I2S_SUPPORTS_PCM=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_SUPPORTS_PCM2PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y +CONFIG_SOC_I2S_PDM_MAX_TX_LINES=2 +CONFIG_SOC_I2S_PDM_MAX_RX_LINES=1 +CONFIG_SOC_I2S_SUPPORTS_TDM=y +CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_XTAL_CLOCK=y +CONFIG_SOC_LEDC_TIMER_NUM=4 +CONFIG_SOC_LEDC_CHANNEL_NUM=6 +CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=14 +CONFIG_SOC_LEDC_SUPPORT_FADE_STOP=y +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=1 +CONFIG_SOC_MMU_PERIPH_NUM=1 +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=2 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=2 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=4 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=48 +CONFIG_SOC_RMT_SUPPORT_RX_PINGPONG=y +CONFIG_SOC_RMT_SUPPORT_RX_DEMODULATION=y +CONFIG_SOC_RMT_SUPPORT_TX_ASYNC_STOP=y +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_COUNT=y +CONFIG_SOC_RMT_SUPPORT_TX_SYNCHRO=y +CONFIG_SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY=y +CONFIG_SOC_RMT_SUPPORT_XTAL=y +CONFIG_SOC_RMT_SUPPORT_APB=y +CONFIG_SOC_RMT_SUPPORT_RC_FAST=y +CONFIG_SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH=128 +CONFIG_SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM=108 +CONFIG_SOC_SLEEP_SYSTIMER_STALL_WORKAROUND=y +CONFIG_SOC_SLEEP_TGWDT_STOP_WORKAROUND=y +CONFIG_SOC_RTCIO_PIN_COUNT=0 +CONFIG_SOC_MPI_MEM_BLOCKS_NUM=4 +CONFIG_SOC_MPI_OPERATIONS_NUM=3 +CONFIG_SOC_RSA_MAX_BIT_LEN=3072 +CONFIG_SOC_SHA_DMA_MAX_BUFFER_SIZE=3968 +CONFIG_SOC_SHA_SUPPORT_DMA=y +CONFIG_SOC_SHA_SUPPORT_RESUME=y +CONFIG_SOC_SHA_GDMA=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA224=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SDM_GROUPS=1 +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=4 +CONFIG_SOC_SDM_CLK_SUPPORT_APB=y +CONFIG_SOC_SPI_PERIPH_NUM=2 +CONFIG_SOC_SPI_MAX_CS_NUM=6 +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_SUPPORT_DDRCLK=y +CONFIG_SOC_SPI_SLAVE_SUPPORT_SEG_TRANS=y +CONFIG_SOC_SPI_SUPPORT_CD_SIG=y +CONFIG_SOC_SPI_SUPPORT_CONTINUOUS_TRANS=y +CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2=y +CONFIG_SOC_SPI_SUPPORT_CLK_APB=y +CONFIG_SOC_SPI_SUPPORT_CLK_XTAL=y +CONFIG_SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT=y +CONFIG_SOC_SPI_SCT_SUPPORTED=y +CONFIG_SOC_SPI_SCT_REG_NUM=14 +CONFIG_SOC_SPI_SCT_BUFFER_NUM_MAX=y +CONFIG_SOC_SPI_SCT_CONF_BITLEN_MAX=0x3FFFA +CONFIG_SOC_MEMSPI_IS_INDEPENDENT=y +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=16 +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_RESUME=y +CONFIG_SOC_SPI_MEM_SUPPORT_IDLE_INTR=y +CONFIG_SOC_SPI_MEM_SUPPORT_SW_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_CHECK_SUS=y +CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y +CONFIG_SOC_SPI_MEM_SUPPORT_WRAP=y +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_SYSTIMER_COUNTER_NUM=2 +CONFIG_SOC_SYSTIMER_ALARM_NUM=3 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_LO=32 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_HI=20 +CONFIG_SOC_SYSTIMER_FIXED_DIVIDER=y +CONFIG_SOC_SYSTIMER_INT_LEVEL=y +CONFIG_SOC_SYSTIMER_ALARM_MISS_COMPENSATE=y +CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32 +CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16 +CONFIG_SOC_MWDT_SUPPORT_XTAL=y +CONFIG_SOC_TWAI_CONTROLLER_NUM=1 +CONFIG_SOC_TWAI_MASK_FILTER_NUM=1 +CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_BRP_MAX=16384 +CONFIG_SOC_TWAI_SUPPORTS_RX_STATUS=y +CONFIG_SOC_EFUSE_DIS_DOWNLOAD_ICACHE=y +CONFIG_SOC_EFUSE_DIS_PAD_JTAG=y +CONFIG_SOC_EFUSE_DIS_USB_JTAG=y +CONFIG_SOC_EFUSE_DIS_DIRECT_BOOT=y +CONFIG_SOC_EFUSE_SOFT_DIS_JTAG=y +CONFIG_SOC_EFUSE_DIS_ICACHE=y +CONFIG_SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK=y +CONFIG_SOC_SECURE_BOOT_V2_RSA=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=3 +CONFIG_SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32 +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES=y +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128=y +CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE=16 +CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE=512 +CONFIG_SOC_UART_NUM=2 +CONFIG_SOC_UART_HP_NUM=2 +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_UART_SUPPORT_APB_CLK=y +CONFIG_SOC_UART_SUPPORT_RTC_CLK=y +CONFIG_SOC_UART_SUPPORT_XTAL_CLK=y +CONFIG_SOC_UART_SUPPORT_WAKEUP_INT=y +CONFIG_SOC_UART_SUPPORT_FSM_TX_WAIT_SEND=y +CONFIG_SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE=y +CONFIG_SOC_UHCI_NUM=1 +CONFIG_SOC_COEX_HW_PTI=y +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_MAC_BB_PD_MEM_SIZE=192 +CONFIG_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12 +CONFIG_SOC_PM_SUPPORT_WIFI_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_BT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_CPU_PD=y +CONFIG_SOC_PM_SUPPORT_WIFI_PD=y +CONFIG_SOC_PM_SUPPORT_BT_PD=y +CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y +CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y +CONFIG_SOC_PM_SUPPORT_MAC_BB_PD=y +CONFIG_SOC_PM_CPU_RETENTION_BY_RTCCNTL=y +CONFIG_SOC_PM_MODEM_RETENTION_BY_BACKUPDMA=y +CONFIG_SOC_PM_MODEM_PD_BY_SW=y +CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y +CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y +CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y +CONFIG_SOC_CLK_LP_FAST_SUPPORT_XTAL_D2=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC=y +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL=y +CONFIG_SOC_WIFI_HW_TSF=y +CONFIG_SOC_WIFI_FTM_SUPPORT=y +CONFIG_SOC_WIFI_GCMP_SUPPORT=y +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_WIFI_SUPPORT_VARIABLE_BEACON_WINDOW=y +CONFIG_SOC_WIFI_PHY_NEEDS_USB_WORKAROUND=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_BLE_50_SUPPORTED=y +CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y +CONFIG_SOC_BLUFI_SUPPORTED=y +CONFIG_SOC_PHY_COMBO_MODULE=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TOOLCHAIN="gcc" +CONFIG_IDF_TOOLCHAIN_GCC=y +CONFIG_IDF_TARGET_ARCH_RISCV=y +CONFIG_IDF_TARGET_ARCH="riscv" +CONFIG_IDF_TARGET="esp32c3" +CONFIG_IDF_INIT_VERSION="6.0.0" +CONFIG_IDF_TARGET_ESP32C3=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0005 + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# end of Build type + +# +# Bootloader config +# + +# +# Bootloader manager +# +CONFIG_BOOTLOADER_COMPILE_TIME_DATE=y +CONFIG_BOOTLOADER_PROJECT_VER=1 +# end of Bootloader manager + +# +# Application Rollback +# +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# end of Application Rollback + +# +# Recovery Bootloader and Rollback +# +# end of Recovery Bootloader and Rollback + +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set + +# +# Log +# +CONFIG_BOOTLOADER_LOG_VERSION_1=y +CONFIG_BOOTLOADER_LOG_VERSION=1 +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 + +# +# Format +# +# CONFIG_BOOTLOADER_LOG_COLORS is not set +CONFIG_BOOTLOADER_LOG_TIMESTAMP_SOURCE_CPU_TICKS=y +# end of Format + +# +# Settings +# +CONFIG_BOOTLOADER_LOG_MODE_TEXT_EN=y +CONFIG_BOOTLOADER_LOG_MODE_TEXT=y +# end of Settings +# end of Log + +CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ=80 + +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V2_RSA_SUPPORTED=y +CONFIG_SECURE_BOOT_V2_PREFERRED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +CONFIG_SECURE_ROM_DL_MODE_ENABLED=y +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=9 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_MZ_CRC32=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_UART_CLK_IS_XTAL=y +CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=3 +CONFIG_ESP_ROM_HAS_RETARGETABLE_LOCKING=y +CONFIG_ESP_ROM_HAS_ERASE_0_REGION_BUG=y +CONFIG_ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV=y +CONFIG_ESP_ROM_GET_CLK_FREQ=y +CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y +CONFIG_ESP_ROM_HAS_LAYOUT_TABLE=y +CONFIG_ESP_ROM_HAS_SPI_FLASH=y +CONFIG_ESP_ROM_HAS_SPI_FLASH_MMAP=y +CONFIG_ESP_ROM_HAS_ETS_PRINTF_BUG=y +CONFIG_ESP_ROM_HAS_NEWLIB=y +CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y +CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME=y +CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE=y +CONFIG_ESP_ROM_RAM_APP_NEEDS_MMU_INIT=y +CONFIG_ESP_ROM_HAS_SW_FLOAT=y +CONFIG_ESP_ROM_USB_OTG_NUM=-1 +CONFIG_ESP_ROM_HAS_VERSION=y +CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y +CONFIG_ESP_ROM_CONSOLE_OUTPUT_SECONDARY=y +CONFIG_ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY=y + +# +# Boot ROM Behavior +# +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="2MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEBUG=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_ASSERT_NDEBUG_EVALUATE=y +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_NO_MERGE_CONSTANTS is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set +CONFIG_COMPILER_DISABLE_DEFAULT_ERRORS=y +# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set +# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set +# CONFIG_COMPILER_DISABLE_GCC14_WARNINGS is not set +# CONFIG_COMPILER_DISABLE_GCC15_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +CONFIG_COMPILER_RT_LIB_GCCLIB=y +CONFIG_COMPILER_RT_LIB_NAME="gcc" +CONFIG_COMPILER_ORPHAN_SECTIONS_ERROR=y +# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set +# CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE is not set +# CONFIG_COMPILER_STATIC_ANALYZER is not set +# end of Compiler options + +# +# Component config +# + +# +# !!! MINIMAL_BUILD is enabled !!! +# + +# +# Only common components and those transitively required by the main component are listed +# + +# +# If a component configuration is missing, please add it to the main component's requirements +# + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# ESP-Driver:GPIO Configurations +# +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:GPIO Configurations + +# +# ESP-Driver:UART Configurations +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of ESP-Driver:UART Configurations + +# +# ESP-Driver:UHCI Configurations +# +# CONFIG_UHCI_ISR_HANDLER_IN_IRAM is not set +# CONFIG_UHCI_ISR_CACHE_SAFE is not set +# CONFIG_UHCI_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:UHCI Configurations + +# +# Hardware Settings +# + +# +# Chip revision +# +# CONFIG_ESP32C3_REV_MIN_0 is not set +# CONFIG_ESP32C3_REV_MIN_1 is not set +# CONFIG_ESP32C3_REV_MIN_2 is not set +CONFIG_ESP32C3_REV_MIN_3=y +# CONFIG_ESP32C3_REV_MIN_4 is not set +# CONFIG_ESP32C3_REV_MIN_101 is not set +CONFIG_ESP32C3_REV_MIN_FULL=3 +CONFIG_ESP_REV_MIN_FULL=3 + +# +# Maximum Supported ESP32-C3 Revision (Rev v1.99) +# +CONFIG_ESP32C3_REV_MAX_FULL=199 +CONFIG_ESP_REV_MAX_FULL=199 +CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL=0 +CONFIG_ESP_EFUSE_BLOCK_REV_MAX_FULL=199 + +# +# Maximum Supported ESP32-C3 eFuse Block Revision (eFuse Block Rev v1.99) +# +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC is not set +# end of MAC Config + +# +# Sleep Config +# +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=0 +# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set +# CONFIG_ESP_SLEEP_DEBUG is not set +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +CONFIG_ESP_PERIPH_CTRL_FUNC_IN_IRAM=y +CONFIG_ESP_REGI2C_CTRL_FUNC_IN_IRAM=y +# end of Peripheral Control + +# +# GDMA Configurations +# +# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set +CONFIG_GDMA_ISR_HANDLER_IN_IRAM=y +CONFIG_GDMA_OBJ_DRAM_SAFE=y +# CONFIG_GDMA_ENABLE_DEBUG_LOG is not set +# end of GDMA Configurations + +# +# Main XTAL Config +# +CONFIG_XTAL_FREQ_40=y +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config + +# +# Power Supplier +# + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=7 +CONFIG_ESP_BROWNOUT_USE_INTR=y +# end of Brownout Detector +# end of Power Supplier + +CONFIG_ESP_INTR_IN_IRAM=y +# end of Hardware Settings + +# +# ESP-MM: Memory Management Configurations +# +# end of ESP-MM: Memory Management Configurations + +# +# Partition API Configuration +# +# end of Partition API Configuration + +# +# Power Management +# +CONFIG_PM_SLEEP_FUNC_IN_IRAM=y +# CONFIG_PM_ENABLE is not set +CONFIG_PM_SLP_IRAM_OPT=y +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +# end of Power Management + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP-ROM +# +CONFIG_ESP_ROM_PRINT_IN_IRAM=y +# end of ESP-ROM + +# +# ESP Security Specific +# +# end of ESP Security Specific + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 +CONFIG_ESP_SYSTEM_IN_IRAM=y +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0 +CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y +CONFIG_ESP_SYSTEM_NO_BACKTRACE=y +# CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set +# CONFIG_ESP_SYSTEM_USE_FRAME_POINTER is not set + +# +# Memory protection +# +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=y +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=y +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y +CONFIG_ESP_SYSTEM_HW_STACK_GUARD=y +CONFIG_ESP_SYSTEM_HW_PC_RECORD=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +# end of IPC (Inter-Processor Call) + +# +# ESP Timer (High Resolution Timer) +# +CONFIG_ESP_TIMER_IN_IRAM=y +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set +CONFIG_ESP_TIMER_TASK_AFFINITY=0x0 +CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y +CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of ESP Timer (High Resolution Timer) + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +CONFIG_FREERTOS_UNICORE=y +CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_USE_TIMERS=y +CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" +# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set +CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y +CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y +# CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# end of Port + +# +# Extra +# +# end of Extra + +CONFIG_FREERTOS_PORT=y +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y +CONFIG_FREERTOS_NUMBER_OF_CORES=1 +CONFIG_FREERTOS_IN_IRAM=y +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +CONFIG_HAL_GPIO_USE_ROM_IMPL=y +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_USE_HOOKS is not set +# CONFIG_HEAP_TASK_TRACKING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH is not set +# end of Heap memory debugging + +# +# Log +# +CONFIG_LOG_VERSION_1=y +# CONFIG_LOG_VERSION_2 is not set +CONFIG_LOG_VERSION=1 + +# +# Log Level +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=3 + +# +# Level Settings +# +# CONFIG_LOG_MASTER_LEVEL is not set +CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=y +# CONFIG_LOG_TAG_LEVEL_IMPL_NONE is not set +# CONFIG_LOG_TAG_LEVEL_IMPL_LINKED_LIST is not set +CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_AND_LINKED_LIST=y +# CONFIG_LOG_TAG_LEVEL_CACHE_ARRAY is not set +CONFIG_LOG_TAG_LEVEL_CACHE_BINARY_MIN_HEAP=y +CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_SIZE=31 +# end of Level Settings +# end of Log Level + +# +# Format +# +# CONFIG_LOG_COLORS is not set +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Format + +# +# Settings +# +CONFIG_LOG_MODE_TEXT_EN=y +CONFIG_LOG_MODE_TEXT=y +# end of Settings + +CONFIG_LOG_IN_IRAM=y +# end of Log + +# +# mbedTLS +# + +# +# Core Configuration +# +CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_NONE=y +# CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_MBEDTLS_THREADING_C is not set +CONFIG_MBEDTLS_ERROR_STRINGS=y +CONFIG_MBEDTLS_VERSION_C=y +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_VERSION_FEATURES is not set +# CONFIG_MBEDTLS_DEBUG is not set +CONFIG_MBEDTLS_SELF_TEST=y +# end of Core Configuration + +# +# Certificates +# +CONFIG_MBEDTLS_X509_USE_C=y +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_PK_C=y +CONFIG_MBEDTLS_PK_PARSE_C=y +CONFIG_MBEDTLS_PK_WRITE_C=y +# CONFIG_MBEDTLS_X509_REMOVE_INFO is not set +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CRT_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# CONFIG_MBEDTLS_X509_CREATE_C is not set +CONFIG_MBEDTLS_X509_RSASSA_PSS_SUPPORT=y +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +CONFIG_MBEDTLS_ASN1_PARSE_C=y +CONFIG_MBEDTLS_ASN1_WRITE_C=y +CONFIG_MBEDTLS_OID_C=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y + +# +# Certificate Bundle Configuration +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle Configuration + +# CONFIG_MBEDTLS_ALLOW_WEAK_CERTIFICATE_VERIFICATION is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_CROSS_SIGNED_VERIFY is not set +# end of Certificates + +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Protocol Configuration +# +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +# CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_CACHE_C=y +CONFIG_MBEDTLS_SSL_ALL_ALERT_MESSAGES=y + +# +# TLS Key Exchange Configuration +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Configuration + +CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION=y +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_SSL_MAX_FRAGMENT_LENGTH=y +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y +# CONFIG_MBEDTLS_SSL_KEYING_MATERIAL_EXPORT is not set +# end of TLS Protocol Configuration + +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_CIPHER_C=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +CONFIG_MBEDTLS_ARIA_C=y +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_CIPHER_MODE_CBC=y +CONFIG_MBEDTLS_CIPHER_MODE_CFB=y +CONFIG_MBEDTLS_CIPHER_MODE_CTR=y +CONFIG_MBEDTLS_CIPHER_MODE_OFB=y +CONFIG_MBEDTLS_CIPHER_MODE_XTS=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +CONFIG_MBEDTLS_CIPHER_PADDING=y +CONFIG_MBEDTLS_CIPHER_PADDING_PKCS7=y +CONFIG_MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS=y +CONFIG_MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN=y +CONFIG_MBEDTLS_CIPHER_PADDING_ZEROS=y +CONFIG_MBEDTLS_AES_ROM_TABLES=y +# CONFIG_MBEDTLS_AES_FEWER_TABLES is not set +# CONFIG_MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH is not set +CONFIG_MBEDTLS_CMAC_C=y +# end of Symmetric Ciphers + +# +# Asymmetric Ciphers +# +CONFIG_MBEDTLS_BIGNUM_C=y +CONFIG_MBEDTLS_GENPRIME=y +CONFIG_MBEDTLS_RSA_C=y +CONFIG_MBEDTLS_ECP_C=y + +# +# Supported Curves +# +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +# end of Supported Curves + +# +# Elliptic Curve Ciphers Configuration +# +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +# CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM is not set +CONFIG_MBEDTLS_DHM_C=y +CONFIG_MBEDTLS_ECDH_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECDSA_C=y +CONFIG_MBEDTLS_PK_PARSE_EC_EXTENDED=y +CONFIG_MBEDTLS_PK_PARSE_EC_COMPRESSED=y +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# end of Elliptic Curve Ciphers Configuration +# end of Asymmetric Ciphers + +# +# Hash functions +# +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_RIPEMD160_C is not set +CONFIG_MBEDTLS_MD_C=y +CONFIG_MBEDTLS_MD5_C=y +CONFIG_MBEDTLS_SHA1_C=y +# CONFIG_MBEDTLS_SHA224_C is not set +CONFIG_MBEDTLS_SHA256_C=y +CONFIG_MBEDTLS_SHA384_C=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_SHA3_C=y +CONFIG_MBEDTLS_ROM_MD5=y +# end of Hash functions + +# +# Hardware Acceleration +# +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI=y +CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y +CONFIG_MBEDTLS_MPI_INTERRUPT_LEVEL=0 +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER=y +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +CONFIG_MBEDTLS_AES_INTERRUPT_LEVEL=0 +CONFIG_MBEDTLS_PK_RSA_ALT_SUPPORT=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +# end of Hardware Acceleration + +# +# Entropy and Random Number Generation +# +CONFIG_MBEDTLS_ENTROPY_C=y +# CONFIG_MBEDTLS_ENTROPY_FORCE_SHA256 is not set +CONFIG_MBEDTLS_CTR_DRBG_C=y +CONFIG_MBEDTLS_HMAC_DRBG_C=y +# end of Entropy and Random Number Generation + +# +# Encoding/Decoding +# +CONFIG_MBEDTLS_BASE64_C=y +CONFIG_MBEDTLS_PKCS5_C=y +CONFIG_MBEDTLS_PKCS7_C=y +CONFIG_MBEDTLS_PKCS12_C=y +CONFIG_MBEDTLS_PKCS1_V15=y +CONFIG_MBEDTLS_PKCS1_V21=y +# end of Encoding/Decoding + +# +# Stream Cipher +# +# CONFIG_MBEDTLS_CHACHA20_C is not set +# end of Stream Cipher +# end of mbedTLS + +# +# LibC +# +CONFIG_LIBC_NEWLIB=y +CONFIG_LIBC_MISC_IN_IRAM=y +CONFIG_LIBC_LOCKS_PLACE_IN_IRAM=y +# CONFIG_LIBC_NEWLIB_NANO_FORMAT is not set +CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_LIBC_TIME_SYSCALL_USE_RTC is not set +# CONFIG_LIBC_TIME_SYSCALL_USE_HRT is not set +# CONFIG_LIBC_TIME_SYSCALL_USE_NONE is not set +# CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS is not set +# end of LibC + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# Main Flash configuration +# + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +# CONFIG_SPI_FLASH_AUTO_SUSPEND is not set +CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50 +# CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND is not set +# CONFIG_SPI_FLASH_FORCE_ENABLE_C6_H2_SUSPEND is not set +CONFIG_SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM=y +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# CONFIG_SPI_FLASH_ROM_IMPL is not set +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_VENDOR_XMC_SUPPORT_ENABLED=y +CONFIG_SPI_FLASH_VENDOR_GD_SUPPORT_ENABLED=y +CONFIG_SPI_FLASH_VENDOR_ISSI_SUPPORT_ENABLED=y +CONFIG_SPI_FLASH_VENDOR_MXIC_SUPPORT_ENABLED=y +CONFIG_SPI_FLASH_VENDOR_WINBOND_SUPPORT_ENABLED=y +CONFIG_SPI_FLASH_VENDOR_BOYA_SUPPORT_ENABLED=y +CONFIG_SPI_FLASH_VENDOR_TH_SUPPORT_ENABLED=y +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver +# end of Component config + +# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set + +# Deprecated options for backward compatibility +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +# CONFIG_NO_BLOBS is not set +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP32C3_RTC_CLK_SRC_INT_RC=y +# CONFIG_ESP32C3_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32C3_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32C3_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_ESP32C3_RTC_CLK_CAL_CYCLES=1024 +CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y +CONFIG_BROWNOUT_DET=y +CONFIG_ESP32C3_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_7=y +CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_2 is not set +CONFIG_BROWNOUT_DET_LVL=7 +CONFIG_ESP32C3_BROWNOUT_DET_LVL=7 +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y +# CONFIG_ESP32C3_DEFAULT_CPU_FREQ_80 is not set +CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y +CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ=160 +CONFIG_ESP32C3_MEMPROT_FEATURE=y +CONFIG_ESP32C3_MEMPROT_FEATURE_LOCK=y +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP32C3_DEBUG_OCDAWARE=y +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC_SYSTIMER=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_ESP32C3_TIME_SYSCALL_USE_SYSTIMER is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# CONFIG_ESP32C3_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# End of deprecated options diff --git a/lispBM/lispBM/examples/esp32c3/sdkconfig.ci b/lispBM/lispBM/examples/esp32c3/sdkconfig.ci new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lispBM/lispBM/frama-c/Makefile b/lispBM/lispBM/frama-c/Makefile new file mode 100644 index 0000000000..43e5743235 --- /dev/null +++ b/lispBM/lispBM/frama-c/Makefile @@ -0,0 +1,35 @@ + + +LISPBM := ../ + +include $(LISPBM)/lispbm.mk + +PLATFORM_INCLUDE = -I$(LISPBM)/platform/linux/include +PLATFORM_SRC = $(LISPBM)/platform/linux/src/platform_mutex.c + +#CCFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wconversion -Wclobbered -pedantic -std=c99 + +# -DLBM_ALWAYS_GC + +LBMFLAGS = -DFULL_RTS_LIB -DLBM_USE_DYN_FUNS -DLBM_USE_DYN_MACROS -DLBM_USE_DYN_LOOPS -DLBM_USE_DYN_ARRAYS + +CCFLAGS = -m32 -O0 -Wall -Wextra -Wshadow -Wconversion -Wclobbered -pedantic -std=c99 $(LBMFLAGS) + +CC=gcc + +SRC = src + +SOURCES = $(wildcard *.c) +EXECS = $(patsubst %.c, %.exe, $(SOURCES)) + +SOURCES = $(wildcard *.c) +TARGETS = $(SOURCES:.c=.exe) + +all: $(TARGETS) + +%.exe: %.c + $(CC) $(CCFLAGS) $(LISPBM_SRC) $(PLATFORM_SRC) $(LISPBM_FLAGS) $< -o $@ -I$(LISPBM)include $(PLATFORM_INCLUDE) -lpthread -lm + +clean: + rm -f $(TARGETS) + diff --git a/lispBM/lispBM/frama-c/frama-c.sh b/lispBM/lispBM/frama-c/frama-c.sh new file mode 100755 index 0000000000..aab8c8f450 --- /dev/null +++ b/lispBM/lispBM/frama-c/frama-c.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +## run bear -- make + +frama-c -json-compilation-database compile_commands.json main.c ../src/*.c ../platform/linux/src/*.c -save parse.sav + +## frama-c -load parse.sav -eva -eva-precision 3 -save eva.sav + +## ivette -load eva.sav diff --git a/lispBM/lispBM/frama-c/main.c b/lispBM/lispBM/frama-c/main.c new file mode 100644 index 0000000000..d63b727cb6 --- /dev/null +++ b/lispBM/lispBM/frama-c/main.c @@ -0,0 +1,185 @@ +#define _GNU_SOURCE // MAP_ANON +#define _POSIX_C_SOURCE 200809L // nanosleep? +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lispbm.h" +#include "lbm_image.h" +#include "lbm_channel.h" + +#include "extensions/lbm_dyn_lib.h" + +#define IMAGE_STORAGE_SIZE (128 * 1024) // bytes: +#define IMAGE_FIXED_VIRTUAL_ADDRESS (void*)0xA0000000 +static uint32_t *image_storage = NULL; +static size_t image_storage_size = IMAGE_STORAGE_SIZE; + +#define GC_STACK_SIZE 256 +#define PRINT_STACK_SIZE 256 +#define EXTENSION_STORAGE_SIZE 1024 +#define HEAP_SIZE 4096 + +lbm_extension_t extensions[EXTENSION_STORAGE_SIZE]; +static size_t lbm_memory_size = LBM_MEMORY_SIZE_10K; +static size_t lbm_memory_bitmap_size = LBM_MEMORY_BITMAP_SIZE_10K; +static lbm_cons_t heap_storage[HEAP_SIZE]; + +static lbm_uint *memory=NULL; +static lbm_uint *bitmap=NULL; + +bool image_write(uint32_t w, int32_t ix, bool const_heap) { // ix >= 0 and ix <= image_size + (void) const_heap; + if (image_storage[ix] == 0xffffffff) { + image_storage[ix] = w; + return true; + } else if (image_storage[ix] == w) { + return true; + } + return false; +} + +bool image_clear(void) { + memset(image_storage, 0xff, image_storage_size); + return true; +} + +void *eval_thd_wrapper(void *v) { + (void) v; + lbm_run_eval(); + return NULL; +} + +void critical(void) { + printf("CRITICAL ERROR\n"); +} + +uint32_t timestamp(void) { + struct timeval tv; + gettimeofday(&tv,NULL); + return (uint32_t)(tv.tv_sec * 1000000 + tv.tv_usec); +} + +typedef struct done_cid_s { + lbm_cid id; + lbm_value r; + struct done_cid_s *next; +} done_cid_t; + +done_cid_t *done_list = NULL; + +void sleep_callback(uint32_t us); // Forward declaration + +lbm_value wait_cid(lbm_cid id) { + + if (id < 0) return ENC_SYM_NIL; + + while (true) { + + done_cid_t *prev = NULL; + done_cid_t *curr = done_list; + while (curr) { + if (curr->id == id) { + if (prev != NULL) { + prev->next = curr->next; + } else { + done_list = curr->next; + } + lbm_value result = curr->r; + free(curr); + return result; // only still valid if no GC has happened. + } + prev = curr; + curr = curr->next; + } + sleep_callback(100); + } +} + +void done_callback(eval_context_t *ctx) { + + //char output[1024]; + //lbm_value t = ctx->r; + //lbm_print_value(output, 1024, t); + //printf("done: %d, %s\n", ctx->id, output); + + done_cid_t *new = malloc(sizeof(done_cid_t)); + new->id = ctx->id; + new->r = ctx->r; + new->next = done_list; + + done_list = new; + + //printf("ctx %d exits with value: %s\n", ctx->id, output); +} + +int error_print(const char *format, ...) { + va_list args; + va_start (args, format); + int n = vprintf(format, args); + va_end(args); + return n; +} + +void sleep_callback(uint32_t us) { + struct timespec s; + struct timespec r; + s.tv_sec = 0; + s.tv_nsec = (long)us * 1000; + nanosleep(&s, &r); +} + +bool dynamic_loader(const char *str, const char **code) { + return lbm_dyn_lib_find(str, code); +} + +int main(void) { + + // Frama-c does not seem to understand a mmapped address as valid. + // using malloc until I understand frama-c enough. + image_storage = malloc(image_storage_size * sizeof(lbm_uint)); + + memory = (lbm_uint*)malloc(lbm_memory_size * sizeof(lbm_uint)); + bitmap = (lbm_uint*)malloc(lbm_memory_bitmap_size * sizeof(lbm_uint)); + + if (memory == NULL || bitmap == NULL) return 0; + + if (!lbm_init(heap_storage, HEAP_SIZE, + memory, lbm_memory_size, + bitmap, lbm_memory_bitmap_size, + GC_STACK_SIZE, + PRINT_STACK_SIZE, + extensions, + EXTENSION_STORAGE_SIZE)) { + return 0; + } + + lbm_set_critical_error_callback(critical); + lbm_set_ctx_done_callback(done_callback); + lbm_set_timestamp_us_callback(timestamp); + lbm_set_usleep_callback(sleep_callback); + lbm_set_printf_callback(error_print); + lbm_set_dynamic_load_callback(dynamic_loader); + + lbm_image_init(image_storage, + image_storage_size / sizeof(uint32_t), //sizeof(lbm_uint), + image_write); + image_clear(); + lbm_image_create("bepa_1"); + lbm_image_boot(); + + lbm_add_eval_symbols(); + lbm_dyn_lib_init(); + + // GO into evaluation loop. + eval_thd_wrapper(NULL); + + return 0; +} + diff --git a/lispBM/lispBM/include/lbm_version.h b/lispBM/lispBM/include/lbm_version.h index 145e72f252..0e7e4f79fe 100644 --- a/lispBM/lispBM/include/lbm_version.h +++ b/lispBM/lispBM/include/lbm_version.h @@ -32,7 +32,7 @@ extern "C" { /** LBM minor version */ #define LBM_MINOR_VERSION 33u /** LBM patch revision */ -#define LBM_PATCH_VERSION 0u +#define LBM_PATCH_VERSION 1u #define LBM_VERSION_STRING STR(LBM_MAJOR_VERSION) "." STR(LBM_MINOR_VERSION) "." STR(LBM_PATCH_VERSION) diff --git a/lispBM/lispBM/platform/chibios/include/platform_timestamp.h b/lispBM/lispBM/platform/chibios/include/platform_timestamp.h new file mode 100644 index 0000000000..a778a27057 --- /dev/null +++ b/lispBM/lispBM/platform/chibios/include/platform_timestamp.h @@ -0,0 +1,26 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PLATFORM_TIMESTAMP_H_ +#define PLATFORM_TIMESTAMP_H_ + +#include + +// timestamp interface +extern uint32_t timestamp(void); + +#endif diff --git a/lispBM/lispBM/platform/chibios/src/platform_timestamp.c b/lispBM/lispBM/platform/chibios/src/platform_timestamp.c new file mode 100644 index 0000000000..a1255c9ecf --- /dev/null +++ b/lispBM/lispBM/platform/chibios/src/platform_timestamp.c @@ -0,0 +1,29 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "platform_timestamp.h" +#include +#include +#include +#include +#include + +uint32_t timestamp(void) { + systime_t t = chVTGetSystemTime(); + uint32_t ts = (uint32_t) ((1000000 / CH_CFG_ST_FREQUENCY) * t); + return ts; +} diff --git a/lispBM/lispBM/platform/freertos/include/platform_timestamp.h b/lispBM/lispBM/platform/freertos/include/platform_timestamp.h new file mode 100644 index 0000000000..7ff5945b5f --- /dev/null +++ b/lispBM/lispBM/platform/freertos/include/platform_timestamp.h @@ -0,0 +1,28 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PLATFORM_TIMESTAMP_H_ +#define PLATFORM_TIMESTAMP_H_ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include + +// timestamp interface +extern uint32_t timestamp(void); + +#endif diff --git a/lispBM/lispBM/platform/freertos/src/platform_timestamp.c b/lispBM/lispBM/platform/freertos/src/platform_timestamp.c new file mode 100644 index 0000000000..badb0fa3e1 --- /dev/null +++ b/lispBM/lispBM/platform/freertos/src/platform_timestamp.c @@ -0,0 +1,23 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "platform_timestamp.h" + +uint32_t timestamp(void) { + TickType_t t = xTaskGetTickCount(); + return (uint32_t) ((1000 / portTICK_PERIOD_MS) * t); +} diff --git a/lispBM/lispBM/platform/linux/include/platform_timestamp.h b/lispBM/lispBM/platform/linux/include/platform_timestamp.h new file mode 100644 index 0000000000..518f1b9008 --- /dev/null +++ b/lispBM/lispBM/platform/linux/include/platform_timestamp.h @@ -0,0 +1,30 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PLATFORM_TIMESTAMP_H_ +#define PLATFORM_TIMESTAMP_H_ + +#include + +// Only on OS where timestamp is expensive +extern void *timestamp_cacher(void *v); + +// timestamp interface +extern uint32_t timestamp(void); + + +#endif diff --git a/lispBM/lispBM/platform/linux/src/platform_timestamp.c b/lispBM/lispBM/platform/linux/src/platform_timestamp.c new file mode 100644 index 0000000000..77347e9185 --- /dev/null +++ b/lispBM/lispBM/platform/linux/src/platform_timestamp.c @@ -0,0 +1,45 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define _POSIX_C_SOURCE 200809L // nanosleep? +#include "platform_timestamp.h" +#include +#include +#include +#include +#include + +static atomic_uint_least32_t timestamp_cache = ATOMIC_VAR_INIT(0); + +void *timestamp_cacher(void *v) { + (void) v; + while(true) { + struct timeval tv; + gettimeofday(&tv,NULL); + atomic_store(×tamp_cache, (uint32_t)(tv.tv_sec * 1000000 + tv.tv_usec)); + long us = 100; // sleep 100 us between cache updates. + struct timespec s; + struct timespec r; + s.tv_sec = 0; + s.tv_nsec = (long)us * 1000; + nanosleep(&s, &r); + } +} + +uint32_t timestamp(void) { + return (uint32_t)atomic_load(×tamp_cache); +} diff --git a/lispBM/lispBM/platform/windows/include/platform_timestamp.h b/lispBM/lispBM/platform/windows/include/platform_timestamp.h new file mode 100644 index 0000000000..518f1b9008 --- /dev/null +++ b/lispBM/lispBM/platform/windows/include/platform_timestamp.h @@ -0,0 +1,30 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PLATFORM_TIMESTAMP_H_ +#define PLATFORM_TIMESTAMP_H_ + +#include + +// Only on OS where timestamp is expensive +extern void *timestamp_cacher(void *v); + +// timestamp interface +extern uint32_t timestamp(void); + + +#endif diff --git a/lispBM/lispBM/platform/windows/src/platform_timestamp.c b/lispBM/lispBM/platform/windows/src/platform_timestamp.c new file mode 100644 index 0000000000..57e648fa5c --- /dev/null +++ b/lispBM/lispBM/platform/windows/src/platform_timestamp.c @@ -0,0 +1,37 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "platform_timestamp.h" +#include +#include +#include +#include + +static atomic_uint_least32_t timestamp_cache = ATOMIC_VAR_INIT(0); + +void *timestamp_cacher(void *v) { + while(true) { + struct timeval tv; + gettimeofday(&tv,NULL); + atomic_store(×tamp_cache, (uint32_t)(tv.tv_sec * 1000000 + tv.tv_usec)); + sleep_callback(100); + } +} + +uint32_t timestamp(void) { + return (uint32_t)atomic_load(×tamp_cache); +} diff --git a/lispBM/lispBM/platform/zephyr/include/platform_timestamp.h b/lispBM/lispBM/platform/zephyr/include/platform_timestamp.h new file mode 100644 index 0000000000..351a7176fb --- /dev/null +++ b/lispBM/lispBM/platform/zephyr/include/platform_timestamp.h @@ -0,0 +1,27 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PLATFORM_TIMESTAMP_H_ +#define PLATFORM_TIMESTAMP_H_ + +#include +#include + +// timestamp interface +extern uint32_t timestamp(void); + +#endif \ No newline at end of file diff --git a/lispBM/lispBM/platform/zephyr/src/platform_timestamp.c b/lispBM/lispBM/platform/zephyr/src/platform_timestamp.c new file mode 100644 index 0000000000..ff74dbbd93 --- /dev/null +++ b/lispBM/lispBM/platform/zephyr/src/platform_timestamp.c @@ -0,0 +1,22 @@ +/* + Copyright 2025 Joel Svensson svenssonjoel@yahoo.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "platform_timestamp.h" + +uint32_t timestamp(void) { + return (uint32_t)k_cyc_to_us_floor32(k_cycle_get_32()); +} \ No newline at end of file diff --git a/lispBM/lispBM/repl/Makefile b/lispBM/lispBM/repl/Makefile index 7c45fb4716..61fee7d53f 100644 --- a/lispBM/lispBM/repl/Makefile +++ b/lispBM/lispBM/repl/Makefile @@ -4,7 +4,8 @@ LISPBM := ../ include $(LISPBM)/lispbm.mk PLATFORM_INCLUDE = -I$(LISPBM)/platform/linux/include -PLATFORM_SRC = $(LISPBM)/platform/linux/src/platform_mutex.c +PLATFORM_SRC = $(LISPBM)/platform/linux/src/platform_mutex.c \ + $(LISPBM)/platform/linux/src/platform_timestamp.c LBMFLAGS = -DFULL_RTS_LIB \ -DLBM_USE_DYN_MACROS \ @@ -13,7 +14,8 @@ LBMFLAGS = -DFULL_RTS_LIB \ -DLBM_USE_DYN_ARRAYS \ -DLBM_USE_DYN_DEFSTRUCT \ -DLBM_USE_TIME_QUOTA \ - -DLBM_USE_ERROR_LINENO + -DLBM_USE_ERROR_LINENO \ + -DLBM_USE_MACRO_REST_ARGS LDFLAGS = @@ -25,7 +27,9 @@ ifeq ($(PLATFORM), macos-arm64) endif -CCFLAGS = -g -O2 -Wall -Wconversion -Wsign-compare -pedantic -std=c11 $(LBMFLAGS) -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -fno-pie -no-pie +# -Wjump-misses-init +# -fsanitize=address +CCFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wconversion -Wsign-compare -pedantic -std=c11 $(LBMFLAGS) -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -fno-pie -no-pie PICCFLAGS = -O2 -Wall -Wconversion -pedantic -std=c11 PI64CCFLAGS = -O2 -Wall -Wconversion -pedantic -std=c11 -DLBM64 diff --git a/lispBM/lispBM/repl/WinMakefile b/lispBM/lispBM/repl/WinMakefile index 2733471382..4614b59931 100644 --- a/lispBM/lispBM/repl/WinMakefile +++ b/lispBM/lispBM/repl/WinMakefile @@ -8,7 +8,8 @@ LISPBM := ../ include $(LISPBM)/lispbm.mk PLATFORM_INCLUDE = -I$(LISPBM)/platform/windows/include -PLATFORM_SRC = $(LISPBM)/platform/windows/src/platform_mutex.c +PLATFORM_SRC = $(LISPBM)/platform/windows/src/platform_mutex.c \ + $(LISPBM)/platform/windows/src/platform_timestamp.c LBMFLAGS = -DFULL_RTS_LIB \ -DLBM_USE_DYN_MACROS \ diff --git a/lispBM/lispBM/repl/bldc_extension_stubs.c b/lispBM/lispBM/repl/bldc_extension_stubs.c index 92b058fd9c..ca2ed28f2f 100644 --- a/lispBM/lispBM/repl/bldc_extension_stubs.c +++ b/lispBM/lispBM/repl/bldc_extension_stubs.c @@ -3,1350 +3,1798 @@ // Function stubs: static lbm_value ext_print(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_print - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_print + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_print_prefix(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_print_prefix - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_print_prefix + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_puts(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_puts - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_puts + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_servo(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_servo - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_servo + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_reset_timeout(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_reset_timeout - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_reset_timeout + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_ppm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_ppm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_ppm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_ppm_age(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_ppm_age - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_ppm_age + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_vin(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_vin - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_vin + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_select_motor(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_select_motor - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_select_motor + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_selected_motor(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_selected_motor - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_selected_motor + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_bms_val(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_bms_val - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_bms_val + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_bms_val(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_bms_val - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_bms_val + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_send_bms_can(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_send_bms_can - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_send_bms_can + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_bms_chg_allowed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_bms_chg_allowed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_bms_chg_allowed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bms_force_balance(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bms_force_balance - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bms_force_balance + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bms_zero_offset(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bms_zero_offset - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bms_zero_offset + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_adc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_adc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_adc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_override_temp_motor(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_override_temp_motor - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_override_temp_motor + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_adc_decoded(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_adc_decoded - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_adc_decoded + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_systime(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_systime - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_systime + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_secs_since(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_secs_since - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_secs_since + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_aux(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_aux - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_aux + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_rpy(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_rpy - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_rpy + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_quat(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_quat - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_quat + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_acc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_acc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_acc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_gyro(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_gyro - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_gyro + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_mag(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_mag - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_mag + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_acc_derot(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_acc_derot - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_acc_derot + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_gyro_derot(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_gyro_derot - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_gyro_derot + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_send_data(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_send_data - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_send_data + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_recv_data(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_recv_data - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_recv_data + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_remote_state(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_remote_state - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_remote_state + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_store_f(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_store_f - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_store_f + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_read_f(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_read_f - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_read_f + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_store_i(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_store_i - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_store_i + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_read_i(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_read_i - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_read_i + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_sysinfo(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_sysinfo - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_sysinfo + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_odometer(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_odometer - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_odometer + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_stats(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_stats - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_stats + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_stats_reset(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_stats_reset - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_stats_reset + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_cmd(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_cmd - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_cmd + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_local_id(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_local_id - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_local_id + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_update_baud(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_update_baud - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_update_baud + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_adc_detach(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_adc_detach - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_adc_detach + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_adc_override(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_adc_override - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_adc_override + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_adc_range_ok(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_adc_range_ok - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_adc_range_ok + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_ppm_detach(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_ppm_detach - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_ppm_detach + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_ppm_override(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_ppm_override - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_ppm_override + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_remote_state(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_remote_state - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_remote_state + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_disable_output(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_disable_output - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_disable_output + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_is_output_disabled(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_is_output_disabled - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_is_output_disabled + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_app_pas_get_rpm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_app_pas_get_rpm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_app_pas_get_rpm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_current_rel(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_current_rel - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_current_rel + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_brake(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_brake - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_brake + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_brake_rel(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_brake_rel - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_brake_rel + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_handbrake(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_handbrake - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_handbrake + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_handbrake_rel(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_handbrake_rel - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_handbrake_rel + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_rpm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_rpm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_rpm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_pos(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_pos - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_pos + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_openloop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_openloop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_openloop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_openloop_phase(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_openloop_phase - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_openloop_phase + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_kill_sw(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_kill_sw - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_kill_sw + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_beep(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_beep - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_beep + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_play_tone(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_play_tone - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_play_tone + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_play_samples(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_play_samples - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_play_samples + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_play_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_play_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_play_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_current_dir(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_current_dir - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_current_dir + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_current_in(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_current_in - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_current_in + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_id(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_id - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_id + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_iq(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_iq - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_iq + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_id_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_id_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_id_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_iq_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_iq_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_iq_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_vd(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_vd - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_vd + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_vq(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_vq - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_vq + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_est_lambda(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_est_lambda - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_est_lambda + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_est_res(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_est_res - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_est_res + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_est_ind(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_est_ind - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_est_ind + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_foc_hfi_res(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_foc_hfi_res - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_foc_hfi_res + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_rpm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_rpm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_rpm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_rpm_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_rpm_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_rpm_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_rpm_fast(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_rpm_fast - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_rpm_fast + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_rpm_faster(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_rpm_faster - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_rpm_faster + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_pos(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_pos - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_pos + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_temp_fet(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_temp_fet - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_temp_fet + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_temp_mot(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_temp_mot - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_temp_mot + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_speed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_speed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_speed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_speed_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_speed_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_speed_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_dist(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_dist - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_dist + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_dist_abs(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_dist_abs - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_dist_abs + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_batt(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_batt - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_batt + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_fault(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_fault - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_fault + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_ah(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_ah - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_ah + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_wh(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_wh - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_wh + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_ah_chg(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_ah_chg - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_ah_chg + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_wh_chg(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_wh_chg - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_wh_chg + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_setup_ah(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_setup_ah - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_setup_ah + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_setup_ah_chg(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_setup_ah_chg - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_setup_ah_chg + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_setup_wh(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_setup_wh - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_setup_wh + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_setup_wh_chg(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_setup_wh_chg - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_setup_wh_chg + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_setup_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_setup_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_setup_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_setup_current_in(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_setup_current_in - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_setup_current_in + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_setup_num_vescs(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_setup_num_vescs - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_setup_num_vescs + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_encoder(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_encoder - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_encoder + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_encoder(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_encoder - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_encoder + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_encoder_error_rate(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_encoder_error_rate - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_encoder_error_rate + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pos_pid_now(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pos_pid_now - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pos_pid_now + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pos_pid_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pos_pid_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pos_pid_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pos_pid_error(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pos_pid_error - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pos_pid_error + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_phase_motor(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_phase_motor - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_phase_motor + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_phase_encoder(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_phase_encoder - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_phase_encoder + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_phase_hall(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_phase_hall - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_phase_hall + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_phase_observer(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_phase_observer - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_phase_observer + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_observer_error(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_observer_error - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_observer_error + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_msg_age(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_msg_age - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_msg_age + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_current_rel(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_current_rel - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_current_rel + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_brake(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_brake - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_brake + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_brake_rel(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_brake_rel - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_brake_rel + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_rpm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_rpm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_rpm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_pos(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_pos - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_pos + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_current_dir(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_current_dir - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_current_dir + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_current_in(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_current_in - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_current_in + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_rpm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_rpm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_rpm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_temp_fet(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_temp_fet - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_temp_fet + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_temp_motor(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_temp_motor - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_temp_motor + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_speed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_speed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_speed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_dist(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_dist - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_dist + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_ppm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_ppm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_ppm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_adc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_adc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_adc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_vin(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_vin - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_vin + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_list_devs(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_list_devs - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_list_devs + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_scan(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_scan - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_scan + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_ping(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_ping - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_ping + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_send_sid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_send_sid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_send_sid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_send_eid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_send_eid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_send_eid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_recv_sid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_recv_sid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_recv_sid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_recv_eid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_recv_eid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_recv_eid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_throttle_curve(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_throttle_curve - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_throttle_curve + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_rand(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_rand - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_rand + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_rand_max(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_rand_max - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_rand_max + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bits_enc_int(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bits_enc_int - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bits_enc_int + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bits_dec_int(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bits_dec_int - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bits_dec_int + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_enable_event(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_enable_event - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_enable_event + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_raw_adc_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_raw_adc_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_raw_adc_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_raw_adc_voltage(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_raw_adc_voltage - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_raw_adc_voltage + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_raw_mod_alpha(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_raw_mod_alpha - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_raw_mod_alpha + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_raw_mod_beta(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_raw_mod_beta - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_raw_mod_beta + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_raw_mod_alpha_measured(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_raw_mod_alpha_measured - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_raw_mod_alpha_measured + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_raw_mod_beta_measured(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_raw_mod_beta_measured - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_raw_mod_beta_measured + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_raw_hall(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_raw_hall - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_raw_hall + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_read(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_read - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_read + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_i2c_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_i2c_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_i2c_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_i2c_tx_rx(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_i2c_tx_rx - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_i2c_tx_rx + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_i2c_detect_addr(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_i2c_detect_addr - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_i2c_detect_addr + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_i2c_restore(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_i2c_restore - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_i2c_restore + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_configure(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_configure - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_configure + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_read(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_read - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_read + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_get(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_get - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_get + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_store(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_store - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_store + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_detect_foc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_detect_foc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_detect_foc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_set_pid_offset(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_set_pid_offset - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_set_pid_offset + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_measure_res(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_measure_res - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_measure_res + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_measure_ind(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_measure_ind - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_measure_ind + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_restore_mc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_restore_mc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_restore_mc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_restore_app(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_restore_app - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_restore_app + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_dc_cal(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_dc_cal - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_dc_cal + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_dc_cal_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_dc_cal_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_dc_cal_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_enc_sincos(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_enc_sincos - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_enc_sincos + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_get_limits(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_get_limits - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_get_limits + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_detect_lambda_enc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_detect_lambda_enc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_detect_lambda_enc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uavcan_last_rawcmd(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uavcan_last_rawcmd - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uavcan_last_rawcmd + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uavcan_last_rpmcmd(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uavcan_last_rpmcmd - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uavcan_last_rpmcmd + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_lbm_set_quota(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_lbm_set_quota - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_lbm_set_quota + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_lbm_set_gc_stack_size(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_lbm_set_gc_stack_size - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_lbm_set_gc_stack_size + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_init(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_init - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_init + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_add_graph(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_add_graph - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_add_graph + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_set_graph(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_set_graph - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_set_graph + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_send_points(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_send_points - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_send_points + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_get_adc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_get_adc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_get_adc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_get_digital(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_get_digital - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_get_digital + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_set_digital(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_set_digital - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_set_digital + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_set_pwm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_set_pwm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_set_pwm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_config_field(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_config_field - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_config_field + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_send_f32(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_send_f32 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_send_f32 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_send_f64(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_send_f64 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_send_f64 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_lat_lon(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_lat_lon - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_lat_lon + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_height(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_height - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_height + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_speed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_speed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_speed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_hdop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_hdop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_hdop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_date_time(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_date_time - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_date_time + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_age(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_age - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_age + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_empty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_empty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_empty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_load_native_lib(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_load_native_lib - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_load_native_lib + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_unload_native_lib(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_unload_native_lib - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_unload_native_lib + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_icu_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_icu_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_icu_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_icu_width(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_icu_width - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_icu_width + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_icu_period(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_icu_period - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_icu_period + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_crc16(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_crc16 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_crc16 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_crc32(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_crc32 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_crc32 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_buf_resize - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_buf_resize + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_shutdown_hold(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_shutdown_hold - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_shutdown_hold + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_override_speed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_override_speed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_override_speed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_canmsg_recv(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_canmsg_recv - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_canmsg_recv + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_canmsg_send(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_canmsg_send - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_canmsg_send + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pwm_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pwm_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pwm_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pwm_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pwm_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pwm_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pwm_set_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pwm_set_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pwm_set_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_image_save(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_image_save - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_image_save + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_cmds_start_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_cmds_start_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_cmds_start_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_cmds_proc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_cmds_proc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_cmds_proc + return lbm_enc_sym(SYM_EERROR); } // Extension registration function: void load_bldc_extensions(void) { - lbm_add_extension("print", ext_print); - lbm_add_extension("set-print-prefix", ext_set_print_prefix); - lbm_add_extension("puts", ext_puts); - lbm_add_extension("set-servo", ext_set_servo); - lbm_add_extension("reset-timeout", ext_reset_timeout); - lbm_add_extension("get-ppm", ext_get_ppm); - lbm_add_extension("get-ppm-age", ext_get_ppm_age); - lbm_add_extension("get-vin", ext_get_vin); - lbm_add_extension("select-motor", ext_select_motor); - lbm_add_extension("get-selected-motor", ext_get_selected_motor); - lbm_add_extension("get-bms-val", ext_get_bms_val); - lbm_add_extension("set-bms-val", ext_set_bms_val); - lbm_add_extension("send-bms-can", ext_send_bms_can); - lbm_add_extension("set-bms-chg-allowed", ext_set_bms_chg_allowed); - lbm_add_extension("bms-force-balance", ext_bms_force_balance); - lbm_add_extension("bms-zero-offset", ext_bms_zero_offset); - lbm_add_extension("get-adc", ext_get_adc); - lbm_add_extension("override-temp-motor", ext_override_temp_motor); - lbm_add_extension("get-adc-decoded", ext_get_adc_decoded); - lbm_add_extension("systime", ext_systime); - lbm_add_extension("secs-since", ext_secs_since); - lbm_add_extension("set-aux", ext_set_aux); - lbm_add_extension("get-imu-rpy", ext_get_imu_rpy); - lbm_add_extension("get-imu-quat", ext_get_imu_quat); - lbm_add_extension("get-imu-acc", ext_get_imu_acc); - lbm_add_extension("get-imu-gyro", ext_get_imu_gyro); - lbm_add_extension("get-imu-mag", ext_get_imu_mag); - lbm_add_extension("get-imu-acc-derot", ext_get_imu_acc_derot); - lbm_add_extension("get-imu-gyro-derot", ext_get_imu_gyro_derot); - lbm_add_extension("send-data", ext_send_data); - lbm_add_extension("recv-data", ext_recv_data); - lbm_add_extension("get-remote-state", ext_get_remote_state); - lbm_add_extension("eeprom-store-f", ext_eeprom_store_f); - lbm_add_extension("eeprom-read-f", ext_eeprom_read_f); - lbm_add_extension("eeprom-store-i", ext_eeprom_store_i); - lbm_add_extension("eeprom-read-i", ext_eeprom_read_i); - lbm_add_extension("sysinfo", ext_sysinfo); - lbm_add_extension("set-odometer", ext_set_odometer); - lbm_add_extension("stats", ext_stats); - lbm_add_extension("stats-reset", ext_stats_reset); - lbm_add_extension("can-cmd", ext_can_cmd); - lbm_add_extension("can-local-id", ext_can_local_id); - lbm_add_extension("can-update-baud", ext_can_update_baud); - lbm_add_extension("app-adc-detach", ext_app_adc_detach); - lbm_add_extension("app-adc-override", ext_app_adc_override); - lbm_add_extension("app-adc-range-ok", ext_app_adc_range_ok); - lbm_add_extension("app-ppm-detach", ext_app_ppm_detach); - lbm_add_extension("app-ppm-override", ext_app_ppm_override); - lbm_add_extension("set-remote-state", ext_set_remote_state); - lbm_add_extension("app-disable-output", ext_app_disable_output); - lbm_add_extension("app-is-output-disabled", ext_app_is_output_disabled); - lbm_add_extension("app-pas-get-rpm", ext_app_pas_get_rpm); - lbm_add_extension("set-current", ext_set_current); - lbm_add_extension("set-current-rel", ext_set_current_rel); - lbm_add_extension("set-duty", ext_set_duty); - lbm_add_extension("set-brake", ext_set_brake); - lbm_add_extension("set-brake-rel", ext_set_brake_rel); - lbm_add_extension("set-handbrake", ext_set_handbrake); - lbm_add_extension("set-handbrake-rel", ext_set_handbrake_rel); - lbm_add_extension("set-rpm", ext_set_rpm); - lbm_add_extension("set-pos", ext_set_pos); - lbm_add_extension("foc-openloop", ext_foc_openloop); - lbm_add_extension("foc-openloop-phase", ext_foc_openloop_phase); - lbm_add_extension("set-kill-sw", ext_set_kill_sw); - lbm_add_extension("foc-beep", ext_foc_beep); - lbm_add_extension("foc-play-tone", ext_foc_play_tone); - lbm_add_extension("foc-play-samples", ext_foc_play_samples); - lbm_add_extension("foc-play-stop", ext_foc_play_stop); - lbm_add_extension("get-current", ext_get_current); - lbm_add_extension("get-current-dir", ext_get_current_dir); - lbm_add_extension("get-current-in", ext_get_current_in); - lbm_add_extension("get-id", ext_get_id); - lbm_add_extension("get-iq", ext_get_iq); - lbm_add_extension("get-id-set", ext_get_id_set); - lbm_add_extension("get-iq-set", ext_get_iq_set); - lbm_add_extension("get-vd", ext_get_vd); - lbm_add_extension("get-vq", ext_get_vq); - lbm_add_extension("foc-est-lambda", ext_foc_est_lambda); - lbm_add_extension("foc-est-res", ext_foc_est_res); - lbm_add_extension("foc-est-ind", ext_foc_est_ind); - lbm_add_extension("foc-hfi-res", ext_foc_hfi_res); - lbm_add_extension("get-duty", ext_get_duty); - lbm_add_extension("get-rpm", ext_get_rpm); - lbm_add_extension("get-rpm-set", ext_get_rpm_set); - lbm_add_extension("get-rpm-fast", ext_get_rpm_fast); - lbm_add_extension("get-rpm-faster", ext_get_rpm_faster); - lbm_add_extension("get-pos", ext_get_pos); - lbm_add_extension("get-temp-fet", ext_get_temp_fet); - lbm_add_extension("get-temp-mot", ext_get_temp_mot); - lbm_add_extension("get-speed", ext_get_speed); - lbm_add_extension("get-speed-set", ext_get_speed_set); - lbm_add_extension("get-dist", ext_get_dist); - lbm_add_extension("get-dist-abs", ext_get_dist_abs); - lbm_add_extension("get-batt", ext_get_batt); - lbm_add_extension("get-fault", ext_get_fault); - lbm_add_extension("get-ah", ext_get_ah); - lbm_add_extension("get-wh", ext_get_wh); - lbm_add_extension("get-ah-chg", ext_get_ah_chg); - lbm_add_extension("get-wh-chg", ext_get_wh_chg); - lbm_add_extension("setup-ah", ext_setup_ah); - lbm_add_extension("setup-ah-chg", ext_setup_ah_chg); - lbm_add_extension("setup-wh", ext_setup_wh); - lbm_add_extension("setup-wh-chg", ext_setup_wh_chg); - lbm_add_extension("setup-current", ext_setup_current); - lbm_add_extension("setup-current-in", ext_setup_current_in); - lbm_add_extension("setup-num-vescs", ext_setup_num_vescs); - lbm_add_extension("get-encoder", ext_get_encoder); - lbm_add_extension("set-encoder", ext_set_encoder); - lbm_add_extension("get-encoder-error-rate", ext_get_encoder_error_rate); - lbm_add_extension("pos-pid-now", ext_pos_pid_now); - lbm_add_extension("pos-pid-set", ext_pos_pid_set); - lbm_add_extension("pos-pid-error", ext_pos_pid_error); - lbm_add_extension("phase-motor", ext_phase_motor); - lbm_add_extension("phase-encoder", ext_phase_encoder); - lbm_add_extension("phase-hall", ext_phase_hall); - lbm_add_extension("phase-observer", ext_phase_observer); - lbm_add_extension("observer-error", ext_observer_error); - lbm_add_extension("can-msg-age", ext_can_msg_age); - lbm_add_extension("can-current", ext_can_current); - lbm_add_extension("can-current-rel", ext_can_current_rel); - lbm_add_extension("can-duty", ext_can_duty); - lbm_add_extension("can-brake", ext_can_brake); - lbm_add_extension("can-brake-rel", ext_can_brake_rel); - lbm_add_extension("can-rpm", ext_can_rpm); - lbm_add_extension("can-pos", ext_can_pos); - lbm_add_extension("can-get-current", ext_can_get_current); - lbm_add_extension("can-get-current-dir", ext_can_get_current_dir); - lbm_add_extension("can-get-current-in", ext_can_get_current_in); - lbm_add_extension("can-get-duty", ext_can_get_duty); - lbm_add_extension("can-get-rpm", ext_can_get_rpm); - lbm_add_extension("can-get-temp-fet", ext_can_get_temp_fet); - lbm_add_extension("can-get-temp-motor", ext_can_get_temp_motor); - lbm_add_extension("can-get-speed", ext_can_get_speed); - lbm_add_extension("can-get-dist", ext_can_get_dist); - lbm_add_extension("can-get-ppm", ext_can_get_ppm); - lbm_add_extension("can-get-adc", ext_can_get_adc); - lbm_add_extension("can-get-vin", ext_can_get_vin); - lbm_add_extension("can-list-devs", ext_can_list_devs); - lbm_add_extension("can-scan", ext_can_scan); - lbm_add_extension("can-ping", ext_can_ping); - lbm_add_extension("can-send-sid", ext_can_send_sid); - lbm_add_extension("can-send-eid", ext_can_send_eid); - lbm_add_extension("can-recv-sid", ext_can_recv_sid); - lbm_add_extension("can-recv-eid", ext_can_recv_eid); - lbm_add_extension("throttle-curve", ext_throttle_curve); - lbm_add_extension("rand", ext_rand); - lbm_add_extension("rand-max", ext_rand_max); - lbm_add_extension("bits-enc-int", ext_bits_enc_int); - lbm_add_extension("bits-dec-int", ext_bits_dec_int); - lbm_add_extension("enable-event", ext_enable_event); - lbm_add_extension("raw-adc-current", ext_raw_adc_current); - lbm_add_extension("raw-adc-voltage", ext_raw_adc_voltage); - lbm_add_extension("raw-mod-alpha", ext_raw_mod_alpha); - lbm_add_extension("raw-mod-beta", ext_raw_mod_beta); - lbm_add_extension("raw-mod-alpha-measured", ext_raw_mod_alpha_measured); - lbm_add_extension("raw-mod-beta-measured", ext_raw_mod_beta_measured); - lbm_add_extension("raw-hall", ext_raw_hall); - lbm_add_extension("uart-start", ext_uart_start); - lbm_add_extension("uart-stop", ext_uart_stop); - lbm_add_extension("uart-write", ext_uart_write); - lbm_add_extension("uart-read", ext_uart_read); - lbm_add_extension("i2c-start", ext_i2c_start); - lbm_add_extension("i2c-tx-rx", ext_i2c_tx_rx); - lbm_add_extension("i2c-detect-addr", ext_i2c_detect_addr); - lbm_add_extension("i2c-restore", ext_i2c_restore); - lbm_add_extension("gpio-configure", ext_gpio_configure); - lbm_add_extension("gpio-write", ext_gpio_write); - lbm_add_extension("gpio-read", ext_gpio_read); - lbm_add_extension("conf-set", ext_conf_set); - lbm_add_extension("conf-get", ext_conf_get); - lbm_add_extension("conf-store", ext_conf_store); - lbm_add_extension("conf-detect-foc", ext_conf_detect_foc); - lbm_add_extension("conf-set-pid-offset", ext_conf_set_pid_offset); - lbm_add_extension("conf-measure-res", ext_conf_measure_res); - lbm_add_extension("conf-measure-ind", ext_conf_measure_ind); - lbm_add_extension("conf-restore-mc", ext_conf_restore_mc); - lbm_add_extension("conf-restore-app", ext_conf_restore_app); - lbm_add_extension("conf-dc-cal", ext_conf_dc_cal); - lbm_add_extension("conf-dc-cal-set", ext_conf_dc_cal_set); - lbm_add_extension("conf-enc-sincos", ext_conf_enc_sincos); - lbm_add_extension("conf-get-limits", ext_conf_get_limits); - lbm_add_extension("conf-detect-lambda-enc", ext_conf_detect_lambda_enc); - lbm_add_extension("uavcan-last-rawcmd", ext_uavcan_last_rawcmd); - lbm_add_extension("uavcan-last-rpmcmd", ext_uavcan_last_rpmcmd); - lbm_add_extension("lbm-set-quota", ext_lbm_set_quota); - lbm_add_extension("lbm-set-gc-stack-size", ext_lbm_set_gc_stack_size); - lbm_add_extension("plot-init", ext_plot_init); - lbm_add_extension("plot-add-graph", ext_plot_add_graph); - lbm_add_extension("plot-set-graph", ext_plot_set_graph); - lbm_add_extension("plot-send-points", ext_plot_send_points); - lbm_add_extension("ioboard-get-adc", ext_ioboard_get_adc); - lbm_add_extension("ioboard-get-digital", ext_ioboard_get_digital); - lbm_add_extension("ioboard-set-digital", ext_ioboard_set_digital); - lbm_add_extension("ioboard-set-pwm", ext_ioboard_set_pwm); - lbm_add_extension("log-start", ext_log_start); - lbm_add_extension("log-stop", ext_log_stop); - lbm_add_extension("log-config-field", ext_log_config_field); - lbm_add_extension("log-send-f32", ext_log_send_f32); - lbm_add_extension("log-send-f64", ext_log_send_f64); - lbm_add_extension("gnss-lat-lon", ext_gnss_lat_lon); - lbm_add_extension("gnss-height", ext_gnss_height); - lbm_add_extension("gnss-speed", ext_gnss_speed); - lbm_add_extension("gnss-hdop", ext_gnss_hdop); - lbm_add_extension("gnss-date-time", ext_gnss_date_time); - lbm_add_extension("gnss-age", ext_gnss_age); - lbm_add_extension("empty", ext_empty); - lbm_add_extension("load-native-lib", ext_load_native_lib); - lbm_add_extension("unload-native-lib", ext_unload_native_lib); - lbm_add_extension("icu-start", ext_icu_start); - lbm_add_extension("icu-width", ext_icu_width); - lbm_add_extension("icu-period", ext_icu_period); - lbm_add_extension("crc16", ext_crc16); - lbm_add_extension("crc32", ext_crc32); - lbm_add_extension("buf-resize", ext_buf_resize); - lbm_add_extension("shutdown-hold", ext_shutdown_hold); - lbm_add_extension("override-speed", ext_override_speed); - lbm_add_extension("canmsg-recv", ext_canmsg_recv); - lbm_add_extension("canmsg-send", ext_canmsg_send); - lbm_add_extension("pwm-start", ext_pwm_start); - lbm_add_extension("pwm-stop", ext_pwm_stop); - lbm_add_extension("pwm-set-duty", ext_pwm_set_duty); - lbm_add_extension("image-save", ext_image_save); - lbm_add_extension("cmds-start-stop", ext_cmds_start_stop); - lbm_add_extension("cmds-proc", ext_cmds_proc); + lbm_add_extension("print", ext_print); + lbm_add_extension("set-print-prefix", ext_set_print_prefix); + lbm_add_extension("puts", ext_puts); + lbm_add_extension("set-servo", ext_set_servo); + lbm_add_extension("reset-timeout", ext_reset_timeout); + lbm_add_extension("get-ppm", ext_get_ppm); + lbm_add_extension("get-ppm-age", ext_get_ppm_age); + lbm_add_extension("get-vin", ext_get_vin); + lbm_add_extension("select-motor", ext_select_motor); + lbm_add_extension("get-selected-motor", ext_get_selected_motor); + lbm_add_extension("get-bms-val", ext_get_bms_val); + lbm_add_extension("set-bms-val", ext_set_bms_val); + lbm_add_extension("send-bms-can", ext_send_bms_can); + lbm_add_extension("set-bms-chg-allowed", ext_set_bms_chg_allowed); + lbm_add_extension("bms-force-balance", ext_bms_force_balance); + lbm_add_extension("bms-zero-offset", ext_bms_zero_offset); + lbm_add_extension("get-adc", ext_get_adc); + lbm_add_extension("override-temp-motor", ext_override_temp_motor); + lbm_add_extension("get-adc-decoded", ext_get_adc_decoded); + lbm_add_extension("systime", ext_systime); + lbm_add_extension("secs-since", ext_secs_since); + lbm_add_extension("set-aux", ext_set_aux); + lbm_add_extension("get-imu-rpy", ext_get_imu_rpy); + lbm_add_extension("get-imu-quat", ext_get_imu_quat); + lbm_add_extension("get-imu-acc", ext_get_imu_acc); + lbm_add_extension("get-imu-gyro", ext_get_imu_gyro); + lbm_add_extension("get-imu-mag", ext_get_imu_mag); + lbm_add_extension("get-imu-acc-derot", ext_get_imu_acc_derot); + lbm_add_extension("get-imu-gyro-derot", ext_get_imu_gyro_derot); + lbm_add_extension("send-data", ext_send_data); + lbm_add_extension("recv-data", ext_recv_data); + lbm_add_extension("get-remote-state", ext_get_remote_state); + lbm_add_extension("eeprom-store-f", ext_eeprom_store_f); + lbm_add_extension("eeprom-read-f", ext_eeprom_read_f); + lbm_add_extension("eeprom-store-i", ext_eeprom_store_i); + lbm_add_extension("eeprom-read-i", ext_eeprom_read_i); + lbm_add_extension("sysinfo", ext_sysinfo); + lbm_add_extension("set-odometer", ext_set_odometer); + lbm_add_extension("stats", ext_stats); + lbm_add_extension("stats-reset", ext_stats_reset); + lbm_add_extension("can-cmd", ext_can_cmd); + lbm_add_extension("can-local-id", ext_can_local_id); + lbm_add_extension("can-update-baud", ext_can_update_baud); + lbm_add_extension("app-adc-detach", ext_app_adc_detach); + lbm_add_extension("app-adc-override", ext_app_adc_override); + lbm_add_extension("app-adc-range-ok", ext_app_adc_range_ok); + lbm_add_extension("app-ppm-detach", ext_app_ppm_detach); + lbm_add_extension("app-ppm-override", ext_app_ppm_override); + lbm_add_extension("set-remote-state", ext_set_remote_state); + lbm_add_extension("app-disable-output", ext_app_disable_output); + lbm_add_extension("app-is-output-disabled", ext_app_is_output_disabled); + lbm_add_extension("app-pas-get-rpm", ext_app_pas_get_rpm); + lbm_add_extension("set-current", ext_set_current); + lbm_add_extension("set-current-rel", ext_set_current_rel); + lbm_add_extension("set-duty", ext_set_duty); + lbm_add_extension("set-brake", ext_set_brake); + lbm_add_extension("set-brake-rel", ext_set_brake_rel); + lbm_add_extension("set-handbrake", ext_set_handbrake); + lbm_add_extension("set-handbrake-rel", ext_set_handbrake_rel); + lbm_add_extension("set-rpm", ext_set_rpm); + lbm_add_extension("set-pos", ext_set_pos); + lbm_add_extension("foc-openloop", ext_foc_openloop); + lbm_add_extension("foc-openloop-phase", ext_foc_openloop_phase); + lbm_add_extension("set-kill-sw", ext_set_kill_sw); + lbm_add_extension("foc-beep", ext_foc_beep); + lbm_add_extension("foc-play-tone", ext_foc_play_tone); + lbm_add_extension("foc-play-samples", ext_foc_play_samples); + lbm_add_extension("foc-play-stop", ext_foc_play_stop); + lbm_add_extension("get-current", ext_get_current); + lbm_add_extension("get-current-dir", ext_get_current_dir); + lbm_add_extension("get-current-in", ext_get_current_in); + lbm_add_extension("get-id", ext_get_id); + lbm_add_extension("get-iq", ext_get_iq); + lbm_add_extension("get-id-set", ext_get_id_set); + lbm_add_extension("get-iq-set", ext_get_iq_set); + lbm_add_extension("get-vd", ext_get_vd); + lbm_add_extension("get-vq", ext_get_vq); + lbm_add_extension("foc-est-lambda", ext_foc_est_lambda); + lbm_add_extension("foc-est-res", ext_foc_est_res); + lbm_add_extension("foc-est-ind", ext_foc_est_ind); + lbm_add_extension("foc-hfi-res", ext_foc_hfi_res); + lbm_add_extension("get-duty", ext_get_duty); + lbm_add_extension("get-rpm", ext_get_rpm); + lbm_add_extension("get-rpm-set", ext_get_rpm_set); + lbm_add_extension("get-rpm-fast", ext_get_rpm_fast); + lbm_add_extension("get-rpm-faster", ext_get_rpm_faster); + lbm_add_extension("get-pos", ext_get_pos); + lbm_add_extension("get-temp-fet", ext_get_temp_fet); + lbm_add_extension("get-temp-mot", ext_get_temp_mot); + lbm_add_extension("get-speed", ext_get_speed); + lbm_add_extension("get-speed-set", ext_get_speed_set); + lbm_add_extension("get-dist", ext_get_dist); + lbm_add_extension("get-dist-abs", ext_get_dist_abs); + lbm_add_extension("get-batt", ext_get_batt); + lbm_add_extension("get-fault", ext_get_fault); + lbm_add_extension("get-ah", ext_get_ah); + lbm_add_extension("get-wh", ext_get_wh); + lbm_add_extension("get-ah-chg", ext_get_ah_chg); + lbm_add_extension("get-wh-chg", ext_get_wh_chg); + lbm_add_extension("setup-ah", ext_setup_ah); + lbm_add_extension("setup-ah-chg", ext_setup_ah_chg); + lbm_add_extension("setup-wh", ext_setup_wh); + lbm_add_extension("setup-wh-chg", ext_setup_wh_chg); + lbm_add_extension("setup-current", ext_setup_current); + lbm_add_extension("setup-current-in", ext_setup_current_in); + lbm_add_extension("setup-num-vescs", ext_setup_num_vescs); + lbm_add_extension("get-encoder", ext_get_encoder); + lbm_add_extension("set-encoder", ext_set_encoder); + lbm_add_extension("get-encoder-error-rate", ext_get_encoder_error_rate); + lbm_add_extension("pos-pid-now", ext_pos_pid_now); + lbm_add_extension("pos-pid-set", ext_pos_pid_set); + lbm_add_extension("pos-pid-error", ext_pos_pid_error); + lbm_add_extension("phase-motor", ext_phase_motor); + lbm_add_extension("phase-encoder", ext_phase_encoder); + lbm_add_extension("phase-hall", ext_phase_hall); + lbm_add_extension("phase-observer", ext_phase_observer); + lbm_add_extension("observer-error", ext_observer_error); + lbm_add_extension("can-msg-age", ext_can_msg_age); + lbm_add_extension("can-current", ext_can_current); + lbm_add_extension("can-current-rel", ext_can_current_rel); + lbm_add_extension("can-duty", ext_can_duty); + lbm_add_extension("can-brake", ext_can_brake); + lbm_add_extension("can-brake-rel", ext_can_brake_rel); + lbm_add_extension("can-rpm", ext_can_rpm); + lbm_add_extension("can-pos", ext_can_pos); + lbm_add_extension("can-get-current", ext_can_get_current); + lbm_add_extension("can-get-current-dir", ext_can_get_current_dir); + lbm_add_extension("can-get-current-in", ext_can_get_current_in); + lbm_add_extension("can-get-duty", ext_can_get_duty); + lbm_add_extension("can-get-rpm", ext_can_get_rpm); + lbm_add_extension("can-get-temp-fet", ext_can_get_temp_fet); + lbm_add_extension("can-get-temp-motor", ext_can_get_temp_motor); + lbm_add_extension("can-get-speed", ext_can_get_speed); + lbm_add_extension("can-get-dist", ext_can_get_dist); + lbm_add_extension("can-get-ppm", ext_can_get_ppm); + lbm_add_extension("can-get-adc", ext_can_get_adc); + lbm_add_extension("can-get-vin", ext_can_get_vin); + lbm_add_extension("can-list-devs", ext_can_list_devs); + lbm_add_extension("can-scan", ext_can_scan); + lbm_add_extension("can-ping", ext_can_ping); + lbm_add_extension("can-send-sid", ext_can_send_sid); + lbm_add_extension("can-send-eid", ext_can_send_eid); + lbm_add_extension("can-recv-sid", ext_can_recv_sid); + lbm_add_extension("can-recv-eid", ext_can_recv_eid); + lbm_add_extension("throttle-curve", ext_throttle_curve); + lbm_add_extension("rand", ext_rand); + lbm_add_extension("rand-max", ext_rand_max); + lbm_add_extension("bits-enc-int", ext_bits_enc_int); + lbm_add_extension("bits-dec-int", ext_bits_dec_int); + lbm_add_extension("enable-event", ext_enable_event); + lbm_add_extension("raw-adc-current", ext_raw_adc_current); + lbm_add_extension("raw-adc-voltage", ext_raw_adc_voltage); + lbm_add_extension("raw-mod-alpha", ext_raw_mod_alpha); + lbm_add_extension("raw-mod-beta", ext_raw_mod_beta); + lbm_add_extension("raw-mod-alpha-measured", ext_raw_mod_alpha_measured); + lbm_add_extension("raw-mod-beta-measured", ext_raw_mod_beta_measured); + lbm_add_extension("raw-hall", ext_raw_hall); + lbm_add_extension("uart-start", ext_uart_start); + lbm_add_extension("uart-stop", ext_uart_stop); + lbm_add_extension("uart-write", ext_uart_write); + lbm_add_extension("uart-read", ext_uart_read); + lbm_add_extension("i2c-start", ext_i2c_start); + lbm_add_extension("i2c-tx-rx", ext_i2c_tx_rx); + lbm_add_extension("i2c-detect-addr", ext_i2c_detect_addr); + lbm_add_extension("i2c-restore", ext_i2c_restore); + lbm_add_extension("gpio-configure", ext_gpio_configure); + lbm_add_extension("gpio-write", ext_gpio_write); + lbm_add_extension("gpio-read", ext_gpio_read); + lbm_add_extension("conf-set", ext_conf_set); + lbm_add_extension("conf-get", ext_conf_get); + lbm_add_extension("conf-store", ext_conf_store); + lbm_add_extension("conf-detect-foc", ext_conf_detect_foc); + lbm_add_extension("conf-set-pid-offset", ext_conf_set_pid_offset); + lbm_add_extension("conf-measure-res", ext_conf_measure_res); + lbm_add_extension("conf-measure-ind", ext_conf_measure_ind); + lbm_add_extension("conf-restore-mc", ext_conf_restore_mc); + lbm_add_extension("conf-restore-app", ext_conf_restore_app); + lbm_add_extension("conf-dc-cal", ext_conf_dc_cal); + lbm_add_extension("conf-dc-cal-set", ext_conf_dc_cal_set); + lbm_add_extension("conf-enc-sincos", ext_conf_enc_sincos); + lbm_add_extension("conf-get-limits", ext_conf_get_limits); + lbm_add_extension("conf-detect-lambda-enc", ext_conf_detect_lambda_enc); + lbm_add_extension("uavcan-last-rawcmd", ext_uavcan_last_rawcmd); + lbm_add_extension("uavcan-last-rpmcmd", ext_uavcan_last_rpmcmd); + lbm_add_extension("lbm-set-quota", ext_lbm_set_quota); + lbm_add_extension("lbm-set-gc-stack-size", ext_lbm_set_gc_stack_size); + lbm_add_extension("plot-init", ext_plot_init); + lbm_add_extension("plot-add-graph", ext_plot_add_graph); + lbm_add_extension("plot-set-graph", ext_plot_set_graph); + lbm_add_extension("plot-send-points", ext_plot_send_points); + lbm_add_extension("ioboard-get-adc", ext_ioboard_get_adc); + lbm_add_extension("ioboard-get-digital", ext_ioboard_get_digital); + lbm_add_extension("ioboard-set-digital", ext_ioboard_set_digital); + lbm_add_extension("ioboard-set-pwm", ext_ioboard_set_pwm); + lbm_add_extension("log-start", ext_log_start); + lbm_add_extension("log-stop", ext_log_stop); + lbm_add_extension("log-config-field", ext_log_config_field); + lbm_add_extension("log-send-f32", ext_log_send_f32); + lbm_add_extension("log-send-f64", ext_log_send_f64); + lbm_add_extension("gnss-lat-lon", ext_gnss_lat_lon); + lbm_add_extension("gnss-height", ext_gnss_height); + lbm_add_extension("gnss-speed", ext_gnss_speed); + lbm_add_extension("gnss-hdop", ext_gnss_hdop); + lbm_add_extension("gnss-date-time", ext_gnss_date_time); + lbm_add_extension("gnss-age", ext_gnss_age); + lbm_add_extension("empty", ext_empty); + lbm_add_extension("load-native-lib", ext_load_native_lib); + lbm_add_extension("unload-native-lib", ext_unload_native_lib); + lbm_add_extension("icu-start", ext_icu_start); + lbm_add_extension("icu-width", ext_icu_width); + lbm_add_extension("icu-period", ext_icu_period); + lbm_add_extension("crc16", ext_crc16); + lbm_add_extension("crc32", ext_crc32); + lbm_add_extension("buf-resize", ext_buf_resize); + lbm_add_extension("shutdown-hold", ext_shutdown_hold); + lbm_add_extension("override-speed", ext_override_speed); + lbm_add_extension("canmsg-recv", ext_canmsg_recv); + lbm_add_extension("canmsg-send", ext_canmsg_send); + lbm_add_extension("pwm-start", ext_pwm_start); + lbm_add_extension("pwm-stop", ext_pwm_stop); + lbm_add_extension("pwm-set-duty", ext_pwm_set_duty); + lbm_add_extension("image-save", ext_image_save); + lbm_add_extension("cmds-start-stop", ext_cmds_start_stop); + lbm_add_extension("cmds-proc", ext_cmds_proc); } diff --git a/lispBM/lispBM/repl/examples/compile.lisp b/lispBM/lispBM/repl/examples/compile.lisp index eff55d6c94..6b550abfc2 100644 --- a/lispBM/lispBM/repl/examples/compile.lisp +++ b/lispBM/lispBM/repl/examples/compile.lisp @@ -214,13 +214,13 @@ (compile-fun '((f 1 2 3))) -(let ((y 10)) - (compile-fun (lambda (x) (+ x y))) - ) +;;(let ((y 10)) +;; (compile-fun (lambda (x) (+ x y))) +;; ) -(define f (lambda (x) (+ x 1))) +;;(define f (lambda (x) (+ x 1))) -(define f-c (compile-fun f)) +;;(define f-c (compile-fun f)) -(compile-fun (lambda (xs) (length xs))) +;;(compile-fun (lambda (xs) (length xs))) diff --git a/lispBM/lispBM/repl/examples/microkanren.lisp b/lispBM/lispBM/repl/examples/microkanren.lisp index 4794967245..a077cab780 100644 --- a/lispBM/lispBM/repl/examples/microkanren.lisp +++ b/lispBM/lispBM/repl/examples/microkanren.lisp @@ -1,97 +1,294 @@ +;; ============================================================================= +;; MicroKanren: A Minimal Logic Programming System +;; ============================================================================= +;; This is an implementation of microKanren in LispBM, based on the paper +;; "μKanren: A Minimal Functional Core for Relational Programming" by +;; Jason Hemann and Daniel P. Friedman. +;; +;; Key concepts: +;; - Logic variables: Represented as arrays containing a unique counter +;; - Substitutions: Association lists mapping variables to values +;; - States: Pairs of (substitution . counter) tracking the search state +;; - Goals: Functions that take a state and return a stream of states +;; - Streams: Lists of states representing multiple solution paths + +;; ============================================================================= +;; UTILITY FUNCTIONS +;; ============================================================================= + +;; Find first association in alist where predicate p returns true for the key (defun assp (p al) (if (eq al nil) nil - (if (p (car (car al)) (cdr (car al))) - (assp (p (cdr al)))))) + (if (p (car (car al))) + (car al) ; return the match + (assp p (cdr al))))) ; continue searching + +;; Test if value is a pair (cons cell) +(defun pair? (a) + (match a ((_ . _) t) + (_ nil))) + +;; ============================================================================= +;; LOGIC VARIABLES +;; ============================================================================= +;; Logic variables are represented as single-element arrays containing +;; a unique integer counter. This allows them to be distinguished from +;; regular values and compared for equality. +;; Create a new logic variable with given counter (defun kan-var (c) (list-to-array (list c))) + +;; Test if value is a logic variable (defun kan-var? (x) (array? x)) + +;; Test if two logic variables are the same (defun kan-var=? (x1 x2) (= (ix x1 0) (ix x2 0))) +;; ============================================================================= +;; SUBSTITUTION AND UNIFICATION +;; ============================================================================= +;; The core of microKanren is unification - the process of making two terms +;; equal by finding appropriate variable bindings. + +;; Ultimate value of U +;; 1: U is not a value -> U is ultimate +;; 2: U is unbound variable -> U is ultimate (the variable itself) +;; 3: U is bound to V, V is bound to .... is bound to X (chain leading to either 1. or 2.) X is ultimate value of U. + +;; Follow variable bindings in substitution to find the ultimate value +;; This is called "walking" the substitution chain (defun walk (u s) - (let ((pr (and (kan-var? u) (assp (lambda (v) (kan-var=? u v)) s)))) + (let ((pr (and (kan-var? u) (assp (lambda (v) (kan-var=? u v)) (ix s 0))))) (if pr (walk (cdr pr) s) u))) -(defun extend-s (x v s) `((,x . ,v) . ,s)) +;; Extend substitution with new variable binding x -> v +;; Returns new substitution as a wrapped array +(defun extend-s (x v s) + (let ((new-list `((,x . ,v) . ,(ix s 0)))) + (list-to-array (list new-list)))) +;; ============================================================================= +;; GOALS AND GOAL CONSTRUCTORS +;; ============================================================================= +;; Goals are functions that take a state and return a stream of states. +;; The unification goal (==) attempts to make two terms equal. + +;; Create a unification goal that tries to make u and v equal (defun kan== (u v) - (lambda (s/c) - (let ((s (unify u v (car s/c)))) - (if s (unit `(,s . ,(cdr s/c))) mzero)))) + (lambda (sc) + (let ((s (unify u v (car sc)))) + (if s (unit `(,s . ,(cdr sc))) mzero)))) +;; Create a singleton stream containing one state (defun unit (s/c) (cons s/c mzero)) + +;; The empty stream (represents failure) (define mzero '()) +;; Unify two terms u and v given substitution s +;; Returns new substitution if unification succeeds, nil if it fails (defun unify (u v s) (let ((u (walk u s)) (v (walk v s))) (cond + ;; Same variable - unification succeeds with current substitution ((and (kan-var? u) (kan-var? v) (kan-var=? u v)) s) + ;; u is unbound variable - bind it to v ((kan-var? u) (extend-s u v s)) + ;; v is unbound variable - bind it to u ((kan-var? v) (extend-s v u s)) + ;; Both are pairs - unify components recursively ((and (pair? u) (pair? v)) (let ((s (unify (car u) (car v) s))) (and s (unify (cdr u) (cdr v) s)))) - (else (and (eqv? u v) s))))) + ;; Neither is variable - succeed only if they're equal + (t (and (eq u v) s))))) +;; Introduce a fresh logic variable and apply function f to it +;; This increments the variable counter to ensure uniqueness (defun call/fresh (f) (lambda (s/c) (let ((c (cdr s/c))) ((f (kan-var c)) `(,(car s/c) . ,(+ c 1)))))) +;; ============================================================================= +;; GOAL COMBINATORS +;; ============================================================================= +;; These combine multiple goals to create more complex logical relationships + +;; Disjunction (OR): Goal succeeds if either g1 OR g2 succeeds +;; Returns a stream containing solutions from both goals (defun disj (g1 g2) (lambda (s/c) (mplus (g1 s/c) (g2 s/c)))) + +;; Conjunction (AND): Goal succeeds only if both g1 AND g2 succeed +;; Applies g2 to each solution produced by g1 (defun conj (g1 g2) (lambda (s/c) (bind (g1 s/c) g2))) +;; ============================================================================= +;; STREAM PROCESSING +;; ============================================================================= +;; Streams represent multiple solution paths. They can be: +;; - Empty lists (no solutions) +;; - Lists of states (finite solutions) +;; - Closures (delayed/infinite streams) + +;; Merge two streams, ensuring fair interleaving of solutions +;; This prevents one infinite stream from blocking another (defun mplus (a b) (match a - (nil b) - ((closure _ _ _ _) lambda () (mplus b (a))) + (nil b) ; First stream empty - return second + ;; First stream is delayed - swap and delay the merge + ((closure _ _ _ _) (lambda () (mplus b (a)))) + ;; First stream has solutions - take one and merge rest with b (_ (cons (car a) (mplus (cdr a) b))))) +;; Apply goal g to each state in stream a +;; This is the monadic bind operation for the stream monad (defun bind (a g) (match a - (nil mzero) - ((closure _ _ _ _) (lambda () bind (a) g)) + (nil mzero) ; Empty stream - return empty + ;; Delayed stream - delay the bind operation + ((closure _ _ _ _) (lambda () (bind (a) g))) + ;; Stream with solutions - apply g to first, bind to rest (_ (mplus (g (car a)) (bind (cdr a) g))))) -(define empty-state '(() . 0)) +;; ============================================================================= +;; INITIAL STATE +;; ============================================================================= + +;; Empty substitution (wrapped in array to be truthy) +(define empty-sub [| () |]) + +;; Initial state: empty substitution with variable counter 0 +(define empty-state `(,empty-sub . 0)) +;; ============================================================================= +;; EXAMPLE PROGRAMS +;; ============================================================================= + +;; Example 1: Simple variable unification +;; This shows how to unify a fresh variable with the value 5 +;; Result would be: '(((#(0) . 5)) . 1) ;; (let ((a ((call/fresh (lambda (q) (kan== q 5))) empty-state))) ;; (car a)) -;;'(((#(0) . 5)) . 1)) - +;; Example 2: Conjunction with disjunction +;; Create variable 'a' that equals 7, AND variable 'b' that equals either 5 OR 6 (define a-and-b - (conj + (conj (call/fresh (lambda (a) (kan== a 7))) - (call/fresh - (lambda (b) + (call/fresh + (lambda (b) (disj (kan== b 5) (kan== b 6)))))) +;; Example 3: Building a sentence "I love you" +;; Shows how to construct complex terms using fresh variables (define love (call/fresh (lambda (res) (call/fresh (lambda (a) (call/fresh (lambda (b) (call/fresh (lambda (c) (conj (kan== a 'i) - (conj + (conj (kan== b 'love) - (conj + (conj (kan== c 'you) (kan== res (list a b c)))))))))))))) +;; Utility function to substitute variables in a list with their values (define var-subst (lambda (ls as) (if (eq nil ls ) nil (let (( a (car ls)) ( b (assoc as a))) (if b (cons b (var-subst (cdr ls) as)) (cons a (var-subst (cdr ls) as))))))) - -(cdr (let ((res (love empty-state))) (var-subst (car (car (car res))) (cdr (car (car res)))))) -;; (test-check "second-set t1" -;; (let (($ ((call/fresh (lambda (q) (== q 5))) empty-state))) -;; (car $)) -;; '(((#(0) . 5)) . 1)) +;; Execute the love relation and extract the result +;; This demonstrates how to run a relation and process the results +(cdr (let ((res (love empty-state))) + (let ((subst (ix (car (car res)) 0))) + (var-subst subst subst)))) + + +;; ============================================================================= +;; MATHEMATICAL RELATIONS +;; ============================================================================= +;; These demonstrate how to encode mathematical concepts as logical relations + +;; Natural number relation using Peano arithmetic +;; A number is either 'zero or 'succ of another natural number +;; This creates an infinite relation that can generate all natural numbers +(define nato + (lambda (x) + (disj + ;; Base case: zero is a natural number + (kan== x 'zero) + ;; Recursive case: succ(n) is natural if n is natural + (call/fresh (lambda (n) + (conj + (kan== x `(succ ,n)) + (nato n))))))) + +;; Addition relation: pluso(X, Y, Z) means X + Y = Z +;; Encodes the recursive definition: +;; - 0 + Y = Y (base case) +;; - succ(X) + Y = succ(Z) if X + Y = Z (recursive case) +(define pluso + (lambda (x y z) + (disj + ;; Base case: zero + Y = Y + (conj (kan== x 'zero) (kan== y z)) + ;; Recursive case: succ(X) + Y = succ(Z) if X + Y = Z + (call/fresh (lambda (x1) + (call/fresh (lambda (z1) + (conj + (kan== x `(succ ,x1)) + (conj + (kan== z `(succ ,z1)) + (pluso x1 y z1)))))))))) + +;; ============================================================================= +;; TEST CASES AND DEMONSTRATIONS +;; ============================================================================= + +;; Define some concrete numbers in Peano arithmetic +(define two '(succ (succ zero))) +(define three '(succ (succ (succ zero)))) +(define five '(succ (succ (succ (succ (succ zero)))))) + +;; Test: Verify that 2 + 3 = 5 +(define verify-addition + (pluso two three five)) + +(print "Proving 2 + 3 = 5:") +(let ((result (verify-addition empty-state))) + (if (eq result mzero) + (print "FAILED") + (print "SUCCESS: 2 + 3 = 5 is proven!"))) + +;; Test: Try a false statement to ensure the system rejects incorrect math +(define seven '(succ (succ (succ (succ (succ (succ (succ zero)))))))) +(define false-addition (pluso two three seven)) + +(print "Testing false statement: 2 + 3 = 7:") +(let ((result (false-addition empty-state))) + (if (eq result mzero) + (print "CORRECTLY FAILED: 2 + 3 != 7") + (print "ERROR: False statement succeeded!"))) + +;; Test: Basic unification sanity check +(print "Testing simple unification (5 = 5):") +(let ((result ((kan== 5 5) empty-state))) + (if (eq result mzero) + (print "FAILED") + (print "SUCCESS: Simple unification works"))) + +;; Test: Verify the base case of addition (0 + 0 = 0) +(print "Testing 0 + 0 = 0:") +(let ((result ((pluso 'zero 'zero 'zero) empty-state))) + (if (eq result mzero) + (print "FAILED") + (print "SUCCESS: 0 + 0 = 0 proven!"))) diff --git a/lispBM/lispBM/repl/examples/monads.lisp b/lispBM/lispBM/repl/examples/monads.lisp index a5d9ea450d..357a598a2f 100644 --- a/lispBM/lispBM/repl/examples/monads.lisp +++ b/lispBM/lispBM/repl/examples/monads.lisp @@ -43,32 +43,29 @@ (defun test4 () (>>= listmonad (list "bunny" "rabbit") (generation 2))) ;; macro -(defmacro do (m body) - (match body - ( (((? a) <- (? b)) . (? xs)) - `(>>= ,m ,b (lambda (,a) (do ,m ,xs)))) +(defmacro do (m) + (match (rest-args) + ( (((? a) <- (? b)) . (? xs)) + `(>>= ,m ,b (lambda (,a) (do ,m ,@xs)))) ( ((? a) . nil) a) ( ((? a) . (? xs)) - `(>>= ,m ,a (lambda (_) (do ,m ,xs)))) + `(>>= ,m ,a (lambda (_) (do ,m ,@xs)))) )) (defun test5 () (do listmonad - ( (a <- (list 1 2 3 4)) (b <- (list 5 6 7 8)) (mret listmonad (* a b)) - ) )) ;; Generic monad operation (defun zip-combos (m f ma mb) (do m - ( (a <- ma) (b <- mb) - (mret m (f a b))))) + (mret m (f a b)))) (defun test6 () (zip-combos listmonad (lambda (a b) (* a b)) (list 1 2 3 4) (list 5 6 7 8))) @@ -87,11 +84,10 @@ (defun test8 () (do idmonad - ( (print "hello") - (a <- (+ 1 2)) - (print "the result of (+ 1 2) is " a) - ))) + (kurt <- (+ 1 2)) + (print "the result of (+ 1 2) is " kurt) + )) (defun test9 () ;; PROGN is { } in LBM { @@ -130,7 +126,6 @@ (defun test10 () (do statemonad - ( (a <- (get)) (mret statemonad (print "state0 is " a)) (put 1) @@ -142,7 +137,6 @@ (put 100) (a <- (get)) (mret statemonad (print "state3 is " a)) - ) )) @@ -150,14 +144,12 @@ (defun lift1 (m f) (lambda (ma) (do m - ( (a <- ma) (mret m (f a)) - )))) + ))) (defun test11 () (do statemonad - ( (put 111) ((lift1 statemonad (lambda (x) (print "state is " x))) (get)) - ))) + )) diff --git a/lispBM/lispBM/repl/examples/tree_search.lisp b/lispBM/lispBM/repl/examples/tree_search.lisp index fb7d81d3ac..33981661f9 100644 --- a/lispBM/lispBM/repl/examples/tree_search.lisp +++ b/lispBM/lispBM/repl/examples/tree_search.lisp @@ -23,14 +23,17 @@ (or (search (left-tree tree) n) (search (right-tree tree) n))))) -(defun search-ret (tree n) +;; The continuation is caught outside of the recursive function. +;; I think this is more efficient than what is possible with defunret. +(defun search-cc (cc tree n) (if (eq tree NIL) nil (if (= (car tree) n) - (pop-ret 't) ;; saves a lot of oring on the way up from discovery. - (or (search (left-tree tree) n) - (search (right-tree tree) n))))) - + (cc 't) ;; saves a lot of oring on the way up from discovery. + { + (search-cc cc (left-tree tree) n) + (search-cc cc (right-tree tree) n) + }))) (defun search-efficient (tree n) - (push-ret (search-ret tree n))) + (call-cc (lambda (cc) (search-cc cc tree n)))) diff --git a/lispBM/lispBM/repl/game/lisprunner/Ubuntu-Regular.ttf b/lispBM/lispBM/repl/game/lisprunner/Ubuntu-Regular.ttf new file mode 100644 index 0000000000..d748728a20 Binary files /dev/null and b/lispBM/lispBM/repl/game/lisprunner/Ubuntu-Regular.ttf differ diff --git a/lispBM/lispBM/repl/game/lisprunner/demo.lisp b/lispBM/lispBM/repl/game/lisprunner/demo.lisp new file mode 100644 index 0000000000..9ceb4dd695 --- /dev/null +++ b/lispBM/lispBM/repl/game/lisprunner/demo.lisp @@ -0,0 +1,422 @@ +(hide-trapped-error) +(if (not (eq (trap sdl-init) + '(exit-ok sdl-init))) + { + (print "You need a LispBM REPL compiled with SDL support to run this application.") + (exit-error 'no-sdl) + } + ) + +(define demo-running t) + +(defun event-loop (w) + (let ((event-loop-running t)) + (loopwhile event-loop-running + { + (match (sdl-poll-event) + (sdl-quit-event + { + (custom-destruct w) + (setq demo-running nil) + }) + ((sdl-key-down-event . (? k)) + nil) ;; Do not process keydown yet + ((sdl-key-up-event . (? k)) + nil) ;; Do not process keyup yet + (_ nil) ;; unused command + ) + (yield 5000) + }))) + + +;; Start the game +(sdl-init) +(define win (sdl-create-window "DEMO" 400 400)) +(define rend (sdl-create-soft-renderer win)) + +(sdl-renderer-set-color rend 0 0 0) +(sdl-clear rend) +(sdl-renderer-set-color rend 255 255 255) +(sdl-set-active-renderer rend) ;; Connect the renderer to the display library + +(define font-file (fopen "Ubuntu-Regular.ttf" "r")) +(define font (load-file font-file)) +(define ttf (ttf-prepare font 32 'indexed4 "abcdefghijklmnopqrstuvxyz1234567890+-*/")) +(define aa-text '(0 8 1 1)) + +(define disp (img-buffer 'indexed16 400 400)) + +(spawn 100 event-loop win) + + +(defun max (a b) (if (> a b) a b)) +(defun min (a b) (if (< a b) a b)) + +(defun apply-max (lst) + (let ((result (first lst))) + { + (map (lambda (x) (if (> x result) (setq result x) nil)) lst) + result + })) + +;; Camera system +(define camera-x 0) ;; World x position of camera +(define camera-target 0) ;; Target x position for smooth following + +;; Dynamic environment that gets populated as we scroll +(define environment '()) + +;; Generate environment segments for scrolling +(defun generate-environment-segment (start-x) + { + ;; Generate a ground segment + (let ((y1 (+ 280 (* 20 (sin (* start-x 0.01))))) ;; Wavy ground + (y2 (+ 280 (* 20 (sin (* (+ start-x 100) 0.01)))))) + (list start-x y1 (+ start-x 100) y2)) + }) + +;; Update environment based on camera position +(defun update-environment () + { + ;; Clear old segments that are too far behind camera + (setq environment (filter (lambda (seg) (> (ix seg 2) (- camera-x 100))) environment)) + + ;; Add new segments ahead of camera + (let ((rightmost-x (if (eq environment '()) + (- camera-x 200) + (apply-max (map (lambda (seg) (ix seg 2)) environment))))) + (loopwhile (< rightmost-x (+ camera-x 600)) + { + (setq environment (cons (generate-environment-segment rightmost-x) environment)) + (setq rightmost-x (+ rightmost-x 100)) + })) + }) + +;; Draw environment line segments with camera offset +(defun draw-environment () + { + (img-clear disp) + (update-environment) + (map (lambda (seg) + (let ((screen-x1 (- (ix seg 0) camera-x)) + (y1 (ix seg 1)) + (screen-x2 (- (ix seg 2) camera-x)) + (y2 (ix seg 3))) + ;; Only draw if segment is visible on screen + (if (and (< screen-x1 450) (> screen-x2 -50)) + (img-line disp screen-x1 y1 screen-x2 y2 1) + nil))) + environment) + }) + +;; Stick figure data structure: (x y direction state task-id color phase) +;; direction: 1=right, -1=left +;; state: 'running 'idle +;; phase: animation frame counter +(define stick-figures '()) + +;; Running animation frames with subtle, natural running motion +(defun get-running-frame (phase) + (let ((frame (mod phase 16))) ;; 16-frame running cycle + (cond + ;; Frame 0-3: Left leg forward stride, right arm forward + ((< frame 4) + '(-3 -12 -6 -10 ;; Left arm back (subtle swing) + 6 -12 10 -10 ;; Right arm forward (gentle swing) + 8 3 12 12 ;; Left leg forward (moderate stride) + -4 6 -6 12)) ;; Right leg back (slight bend) + + ;; Frame 4-7: Contact/midstance phase + ((< frame 8) + '(0 -15 2 -12 ;; Left arm neutral + 3 -15 5 -12 ;; Right arm neutral + 4 6 6 12 ;; Left leg under body + -2 6 -4 12)) ;; Right leg under body + + ;; Frame 8-11: Right leg forward stride, left arm forward + ((< frame 12) + '(6 -12 10 -10 ;; Left arm forward (gentle swing) + -3 -12 -6 -10 ;; Right arm back (subtle swing) + -4 6 -6 12 ;; Left leg back (slight bend) + 8 3 12 12)) ;; Right leg forward (moderate stride) + + ;; Frame 12-15: Transition phase + (t + '(3 -15 5 -12 ;; Left arm transitioning + 0 -15 2 -12 ;; Right arm transitioning + -2 6 -4 12 ;; Left leg transitioning + 4 6 6 12))))) + +;; Joint position indices in frame data: +;; 0,1: left-elbow-x,y 2,3: left-hand-x,y 4,5: right-elbow-x,y 6,7: right-hand-x,y +;; 8,9: left-knee-x,y 10,11: left-foot-x,y 12,13: right-knee-x,y 14,15: right-foot-x,y + +;; Draw a stick figure with proper running animation (camera-relative) +(defun draw-stick-figure (fig) + (let ((world-x (ix fig 0)) ;; World coordinate + (world-y (ix fig 1)) ;; World coordinate + (dir (ix fig 2)) + (state (ix fig 3)) + (task-id (ix fig 4)) + (color-idx (ix fig 5)) ;; Color index (2-15) + (phase (ix fig 6))) + { + ;; Convert world coordinates to screen coordinates + (let ((screen-x (- world-x camera-x)) + (screen-y world-y)) + { + ;; Only draw if figure is visible on screen + (if (and (> screen-x -50) (< screen-x 450)) + { + ;; Head + (img-circle disp screen-x (- screen-y 30) 6 color-idx) + + ;; Body + (img-line disp screen-x (- screen-y 24) screen-x (- screen-y 5) color-idx) + + (if (eq state 'running) + { + ;; Get animation frame data + (let ((frame-data (get-running-frame (/ phase 3)))) ;; Slower animation + { + ;; Left arm (shoulder -> elbow -> hand) + (let ((left-elbow-x (+ screen-x (ix frame-data 0))) + (left-elbow-y (+ screen-y (ix frame-data 1))) + (left-hand-x (+ screen-x (ix frame-data 2))) + (left-hand-y (+ screen-y (ix frame-data 3)))) + { + (img-line disp screen-x (- screen-y 20) left-elbow-x left-elbow-y color-idx) + (img-line disp left-elbow-x left-elbow-y left-hand-x left-hand-y color-idx) + }) + + ;; Right arm (shoulder -> elbow -> hand) + (let ((right-elbow-x (+ screen-x (ix frame-data 4))) + (right-elbow-y (+ screen-y (ix frame-data 5))) + (right-hand-x (+ screen-x (ix frame-data 6))) + (right-hand-y (+ screen-y (ix frame-data 7)))) + { + (img-line disp screen-x (- screen-y 20) right-elbow-x right-elbow-y color-idx) + (img-line disp right-elbow-x right-elbow-y right-hand-x right-hand-y color-idx) + }) + + ;; Left leg (hip -> knee -> foot) + (let ((left-knee-x (+ screen-x (ix frame-data 8))) + (left-knee-y (+ screen-y (ix frame-data 9))) + (left-foot-x (+ screen-x (ix frame-data 10))) + (left-foot-y (+ screen-y (ix frame-data 11)))) + { + (img-line disp screen-x (- screen-y 5) left-knee-x left-knee-y color-idx) + (img-line disp left-knee-x left-knee-y left-foot-x left-foot-y color-idx) + }) + + ;; Right leg (hip -> knee -> foot) + (let ((right-knee-x (+ screen-x (ix frame-data 12))) + (right-knee-y (+ screen-y (ix frame-data 13))) + (right-foot-x (+ screen-x (ix frame-data 14))) + (right-foot-y (+ screen-y (ix frame-data 15)))) + { + (img-line disp screen-x (- screen-y 5) right-knee-x right-knee-y color-idx) + (img-line disp right-knee-x right-knee-y right-foot-x right-foot-y color-idx) + }) + }) + } + { + ;; Static pose for idle state + (img-line disp screen-x (- screen-y 20) (- screen-x 10) (- screen-y 12) color-idx) + (img-line disp screen-x (- screen-y 20) (+ screen-x 10) (- screen-y 12) color-idx) + (img-line disp screen-x (- screen-y 5) (- screen-x 8) (+ screen-y 12) color-idx) + (img-line disp screen-x (- screen-y 5) (+ screen-x 8) (+ screen-y 12) color-idx) + }) + } + nil) ;; Don't draw if off-screen + }) + })) + +;; Find ground level at world x position +;;(defun find-ground-y (world-x) +;; (let ((ground-y (+ 280 (* 20 (sin (* world-x 0.01)))))) ;; Generated ground height +;; (- ground-y 12))) ;; Position stick figures 12 pixels above ground + +(defun in-segment (x seg) + (if (and (>= x (ix seg 0)) + (<= x (ix seg 2))) + t + nil)) + +(defun find (pred segs) + (car (filter pred segs))) + +(defun interpolate-y (x x1 y1 x2 y2) + (+ y1 (* (/ (- x x1) (- x2 x1)) (- y2 y1)))) + +(defun find-ground-y (world-x) + (let ((pred (lambda (seg) (in-segment world-x seg))) + (seg (find pred environment))) + (if seg + (- (interpolate-y world-x (ix seg 0) (ix seg 1) (ix seg 2) (ix seg 3)) 12) + 0) + )) + + +;; Stick figure task behavior (always running rightward) +(defun stick-figure-task (initial-x task-id color-idx) + (let ((x initial-x) + (direction 1) ;; Always rightward + (state 'running) + (phase 0) + (speed 1) + ) + (loopwhile demo-running + { + (let ((ground-y (find-ground-y x))) + { + (setq x (+ x speed)) + + ;; Update animation phase + (setq phase (+ phase 1)) + + ;; Update stick figure in global list + (let ((fig-index (- task-id 1))) + (if (< fig-index (length stick-figures)) + (setix stick-figures fig-index + (list x ground-y direction state task-id color-idx phase)) + nil)) + + (yield 10000) + }) + }))) + +;; Find the leading (rightmost) stick figure for camera tracking +(defun find-leading-runner () + (let ((leader-x 0)) + { + (map (lambda (fig) + (let ((fig-x (ix fig 0))) + (if (> fig-x leader-x) + (setq leader-x fig-x) + nil))) + stick-figures) + leader-x + })) + +;; Update camera to follow leading runner with smooth movement (centered) +(defun update-camera () + { + (let ((leader-x (find-leading-runner))) + { + ;; Set camera target to center the leading runner (screen center is at x=200) + (let ((new-camera-target (- leader-x 200))) ;; Center leader in 400px wide window + { + ;; Only move camera forward (rightward), never backward + (if (> new-camera-target camera-target) + (setq camera-target new-camera-target) + nil) + + ;; Smooth camera movement (lerp) - always forward + (let ((camera-speed 0.05)) ;; Responsive camera movement + (if (> camera-target camera-x) + (setq camera-x (+ camera-x (* camera-speed (- camera-target camera-x)))) + nil)) + }) + }) + }) + +;; Create initial stick figures in world coordinates (all running rightward) +(defun spawn-stick-figures () + { + (setq stick-figures + '((50 280 1 running 1 2 0) + (100 280 1 running 2 3 10) + (150 280 1 running 3 4 20) + (200 280 1 running 4 5 30) + (250 280 1 running 5 6 40))) + + ;; Spawn a task for each stick figure + (spawn 100 stick-figure-task 50 1 2) + (spawn 100 stick-figure-task 100 2 3) + (spawn 100 stick-figure-task 150 3 4) + (spawn 100 stick-figure-task 200 4 5) + (spawn 100 stick-figure-task 250 5 6) + }) + +(defun time-waster (i) + (loopwhile demo-running { + (print "time-waster " i ) + (looprange i 0 10000 + (+ 1 2) ;; Wasting time + ) + })) + + +(defun spawn-timewasters () + { + (spawn 100 time-waster 0) + (spawn 100 time-waster 1) + }) + + +;; Task scheduling visualization +(defun draw-task-info () + (let ((leader-x (find-leading-runner))) + { + (let ((visible-count 0)) + { + (map (lambda (fig) + (let ((screen-x (- (ix fig 0) camera-x))) + (if (and (> screen-x -50) (< screen-x 450)) + (setq visible-count (+ visible-count 1)) + nil))) + stick-figures) + + (ttf-text disp 350 25 aa-text ttf (to-str visible-count)) + }) + (ttf-text disp 10 25 aa-text ttf (to-str num-overflows)) + })) + +;; Color palette for indexed16 format (16 colors: indices 0-15) +(define color-palette '(0x000000 ;; 0: Black (background) + 0xffffff ;; 1: White (environment lines) + 0xff0000 ;; 2: Red (stick figure 1) + 0x00ff00 ;; 3: Green (stick figure 2) + 0x0000ff ;; 4: Blue (stick figure 3) + 0xffff00 ;; 5: Yellow (stick figure 4) + 0xff00ff ;; 6: Magenta (stick figure 5) + 0x00ffff ;; 7: Cyan + 0x808080 ;; 8: Gray + 0xff8000 ;; 9: Orange + 0x8000ff ;; 10: Purple + 0x008000 ;; 11: Dark green + 0x800000 ;; 12: Dark red + 0x000080 ;; 13: Dark blue + 0x808000 ;; 14: Olive + 0x800080)) ;; 15: Maroon + +(define num-overflows 0) + +(define main-loop + (lambda () + { + (spawn-stick-figures) + (spawn-timewasters) + (var systime-last (systime)) + (loopwhile demo-running { + (var systime-now (systime)) + (if (> systime-last systime-now) (setq num-overflows (+ 1 num-overflows))) + (setq systime-last systime-now) + (update-camera) ;; Update camera to follow leading runner + (draw-environment) ;; Draw scrolling environment + (map draw-stick-figure stick-figures) ;; Draw all stick figures + (draw-task-info) + (disp-render disp 0 0 color-palette) + (sdl-present rend) + (yield 33000) ;; ~30 FPS + }) + })) + +(spawn main-loop) + + + + + + diff --git a/lispBM/lispBM/repl/game/lisprunner/rundemo.sh b/lispBM/lispBM/repl/game/lisprunner/rundemo.sh new file mode 100755 index 0000000000..afff2b4aba --- /dev/null +++ b/lispBM/lispBM/repl/game/lisprunner/rundemo.sh @@ -0,0 +1,8 @@ +#!/bin/bash + + +if [ -f ../../repl ]; then + ../../repl -M 11 -H 32000 -s demo.lisp +else + echo "Go to directory ../../ and run 'make sdl_old' to build the repl with SDL support" +fi diff --git a/lispBM/lispBM/repl/game/lispwizard/Ubuntu-Regular.ttf b/lispBM/lispBM/repl/game/lispwizard/Ubuntu-Regular.ttf new file mode 100644 index 0000000000..d748728a20 Binary files /dev/null and b/lispBM/lispBM/repl/game/lispwizard/Ubuntu-Regular.ttf differ diff --git a/lispBM/lispBM/repl/game/lispwizard/game.lisp b/lispBM/lispBM/repl/game/lispwizard/game.lisp new file mode 100644 index 0000000000..df844db0fc --- /dev/null +++ b/lispBM/lispBM/repl/game/lispwizard/game.lisp @@ -0,0 +1,201 @@ +(hide-trapped-error) +(if (not (eq (trap sdl-init) + '(exit-ok sdl-init))) + { + (print "You need a LispBM REPL compiled with SDL support to play this game.") + (exit-error 'no-sdl) + } + ) + +;; grid of rooms +;; extract room x/y by (ix (ix map-of-rooms x) y) +(define map-of-rooms + '((not-a-room "test_room.lisp" not-a-room not-a-room) + ("start_room.lisp" "practice_room.lisp" "snake_room.lisp" not-a-room))) + +(define game-state '((room-cid . -1))) + +;; Load and execute a room. after a room function completes to execute +;; it can garbage collected. +(define load-room + (lambda (pos) + (let (((x . y) pos) + (room-file (ix (ix map-of-rooms y) x)) + (room-h (fopen room-file "r")) + (room (load-file room-h)) + (room-fun (read-eval-program room)) + (room-cid (spawn room-file room-fun))) + { + (fclose room-h) + (setq game-state (setassoc game-state 'room-cid room-cid)) + }))) + +;; Load the tile system +(define load-tile-system (lambda () + { + (var tile-file (fopen "room_tiles.lisp" "r")) + (var tile-code (load-file tile-file)) + (fclose tile-file) + (read-eval-program tile-code) + })) + +(load-tile-system) + +(define game-running t) + +(defun event-loop (w) + (let ((event-loop-running t)) + (loopwhile event-loop-running + { + (match (sdl-poll-event) + (sdl-quit-event + { + (var room-cid (assoc game-state 'room-cid)) + (if (> room-cid 0) { + (print "killing the room thread") + (print "':quit' to exit the REPL") + (kill room-cid 0) + (wait room-cid) + (setq event-loop-running nil) + }) + (custom-destruct w) + (setq game-running nil) + }) + ((sdl-key-down-event . (? k)) + nil) ;; Do not process keydown yet + ((sdl-key-up-event . (? k)) + nil) ;; Do not process keyup yet + (_ nil) ;; unused command + ) + (yield 5000) + }))) + + +;; Define player interface + +(defstruct stats (quota life)) + +(define player (make-stats 10 100)) + +(define look (macro (x) + `(send (assoc game-state 'room-cid) '(look ,x)))) + +(define go (macro (x) + `(send (assoc game-state 'room-cid) '(go ,x )))) + +(define open (macro (x) + `(send (assoc game-state 'room-cid) '(open ,x)))) + +(define move (macro (x y) + `(send (assoc game-state 'room-cid) '(move ,x ,y)))) + + +;; Manhattan distance is the cost of movement. +(define manhattan-distance (lambda (x1 y1 x2 y2) + (+ (abs (- x1 x2)) (abs (- y1 y2))))) + +;; Check if there is a wall in the currently loaded "room-tiles" at x y +(define walkable (lambda (x y) + (= (eq (get-tile room-tiles x y) 0)))) + +;; Display player stats +(define stats (lambda () + { + (print "quota: " (stats-quota player)) + (print "life: " (stats-life player)) + })) + +(define help + (lambda () + { + (print "You interact with the environment by writing code in the REPL.") + (print "The following commands control the players interaction with the room.") + (print " - (look ) : example (look wizard) to look at the wizard") + (print " - (go ) : example (go north)") + (print " - (open ) : example (open door)") + (print "") + (print "The arguments vary depending on room but should make sense if looking at the graphical representation") + (print "") + (print "Arbitrary lisp code can be entered into the REPL in order to solve the rooms.") + })) + + +;; Start the game +(sdl-init) +(define win (sdl-create-window "GAME" 400 400)) +(define rend (sdl-create-soft-renderer win)) + +(sdl-renderer-set-color rend 0 0 0) +(sdl-clear rend) +(sdl-renderer-set-color rend 255 255 255) +(sdl-set-active-renderer rend) ;; Connect the renderer to the display library + +(define font-file (fopen "Ubuntu-Regular.ttf" "r")) +(define font (load-file font-file)) +(define ttf (ttf-prepare font 32 'indexed4 "abcdefghijklmnopqrstuvxyz1234567890+-*/")) +(define aa-green '(0 17408 39168 65280)) +(define disp (img-buffer 'rgb332 400 400)) + +(spawn 100 event-loop win) + +(setq game-state (acons 'disp disp game-state)) + +;;(print game-state) + +;; TODO: put everything needed by the room code into game-state. + +;; testing and example + +(define room-x 0) +(define room-y 1) +(define done nil) + +(load-room (cons room-x room-y)) + +(define main-loop + (lambda () { + (setq game-state (acons 'main-cid (self) game-state)) + (loopwhile (not done) { + (recv ((room-change (? dir)) + (match dir + (north (setq room-y (- room-y 1))) + (south (setq room-y (+ room-y 1))) + (east (setq room-x (+ room-x 1))) + (west (setq room-x (- room-x 1))))) + (_ (print "You are a bit sneaky!")) + ) + (if (and (< room-y (length map-of-rooms)) + (< room-x (length (ix map-of-rooms room-y)))) + (if (eq (type-of (ix (ix map-of-rooms room-y) room-x)) type-array) + (load-room (cons room-x room-y)) + (print "Your magic is strong!")) + (print "Where are you going?")) + }) + (print "exit main loop") + })) + + + +;; Rendering thread +(define render-thd + (lambda () { + (var room-tiles (bufcreate (* 8 8))) ;; an initial buffer to not need to check for nil + (var player-x 1) ;; Maybe list of characters to draw ? + (var player-y 1) + (var animations nil) + (loopwhile (not done) { + (recv-to 0.016 + ((new-room-data (? d)) (setq room-tiles d)) + ((player-pos (? x) (? y)) { (setq player-x x) (setq player-y y)}) + ) + (img-clear disp) + (render-room-from-tiles disp room-tiles) + (render-player disp player-x player-y) + (disp-render disp 0 0 (list)) + }) + } + ) + ) + +;;(define render-cid (spawn render-thd)) +(spawn main-loop) diff --git a/lispBM/lispBM/repl/game/lispwizard/practice_room.lisp b/lispBM/lispBM/repl/game/lispwizard/practice_room.lisp new file mode 100644 index 0000000000..41956cd873 --- /dev/null +++ b/lispBM/lispBM/repl/game/lispwizard/practice_room.lisp @@ -0,0 +1,109 @@ + +(define practice-room-persistant-assoc + (acons 'player-y 3 + (acons 'player-x 4 + (acons 'wizard-y 2 + (acons 'wizard-x 2 + (acons 'cleared t + (acons 'door-open nil + '()))))))) + +(define room-tiles [ 1 2 1 2 2 1 2 1 + 2 0 0 0 0 0 0 2 + 1 0 0 0 0 0 0 1 + 11 0 0 0 0 0 0 7 + 12 0 0 0 0 0 0 8 + 1 0 0 0 0 0 0 1 + 2 0 0 0 0 0 0 2 + 1 2 1 2 2 1 2 1 ]) + +(define practice-room-done nil) + +;; room thread +(lambda () + { + ;; Get display buffer from game state + (var disp (assoc game-state 'disp)) + + (print "The wizard speaks") + (print "\"This room holds the runes of offense and defense") + (print "") + + (loopwhile (not practice-room-done) + { + + (if (not (assoc practice-room-persistant-assoc 'cleared)) + () ;; room clear logic + ) + + (img-clear disp) + (render-room-from-tiles disp room-tiles) + + ;(render-evil-snake-wielder disp 250 250) + (render-wizard disp + (assoc practice-room-persistant-assoc 'wizard-x) + (assoc practice-room-persistant-assoc 'wizard-y)) + (render-player disp + (assoc practice-room-persistant-assoc 'player-x) + (assoc practice-room-persistant-assoc 'player-y)) + + (disp-render disp 0 0 (list)) + + ;; Handle messages + (recv-to 0.1 ; Wait 10ms for messages + ((look wizard) { + (setq looked-wizard t) + (print "The wizard is old and wise.\n") + }) + ((look door) + (print "There is a door leading east.\n")) + ((look runes) { + (print "There are three groups of runes organised under the titles:") + (print "movement-runes, attack-runes, defense-runes") + }) + ((look movement-runes) + (print "To be decided")) + ((look attack-runes) + (print "To be decided")) + ((look defense-runes) + (print "To be decided")) + ((look _) { + (print "There is a wizard in the room and a door leading east.") + (print "Strange runes are covering the walls.") + }) + + ((go east) + (if (not (assoc practice-room-persistant-assoc 'door-open)) + (print "The door is sealed shut.") + { + (send (assoc game-state 'main-cid) '(room-change east)) + (setq practice-room-done t) + } + ) + ) + ((go _) + (print "There is no passage in that direction!")) + + ((open door) + { + (if (assoc practice-room-persistant-assoc 'cleared) + { + (open-door room-tiles 7 3) + (open-door room-tiles 7 4) + (setassoc practice-room-persistant-assoc 'door-open t) + (print "The door opens with a grinding sound of ancient stone.") + } + (print "Impossible! The door is locked!")) + }) + ((open (? x)) + (print "The " x " cannot be opened.") + ) + + (quit break) ; Add quit message handler + (no-more break) + + (timeout ()) + ((? x) (print x))) ; Timeout - continue loop + }) + (print "Leaving the practice room.") + }) diff --git a/lispBM/lispBM/repl/game/lispwizard/room_tiles.lisp b/lispBM/lispBM/repl/game/lispwizard/room_tiles.lisp new file mode 100644 index 0000000000..a09b050e30 --- /dev/null +++ b/lispBM/lispBM/repl/game/lispwizard/room_tiles.lisp @@ -0,0 +1,558 @@ +;; Room Tile System +;; 8x8 grid = 64 bytes, each tile is 50x50 pixels (400x400 total) +;; Tile types: 0=empty, 1=wall, 2=wall+hieroglyph, 3=door, 4=open_door, +;; 5=door_left, 6=door_right, 7=door_top, 8=door_bottom, +;; 9=open_door_left, 10=open_door_right, 11=open_door_top, 12=open_door_bottom, +;; 13=closed_chest, 14=open_chest + +;; Tile rendering functions +(define render-tile (lambda (img tile-x tile-y tile-type) + { + (var pixel-x (* tile-x 50)) + (var pixel-y (* tile-y 50)) + + (cond + ((eq tile-type 0) + { + ;; Empty space - dark stone floor + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Add subtle floor texture + (img-rectangle img (+ pixel-x 10) (+ pixel-y 10) 4 4 0x303030) + (img-rectangle img (+ pixel-x 35) (+ pixel-y 35) 4 4 0x303030) + }) + + ((eq tile-type 1) + { + ;; Wall - light gray stone + (img-rectangle img pixel-x pixel-y 50 50 0x808080) + ;; Add texture lines + (img-line img pixel-x (+ pixel-y 12) (+ pixel-x 49) (+ pixel-y 12) 0x606060) + (img-line img pixel-x (+ pixel-y 25) (+ pixel-x 49) (+ pixel-y 25) 0x606060) + (img-line img pixel-x (+ pixel-y 37) (+ pixel-x 49) (+ pixel-y 37) 0x606060) + ;; Vertical texture + (img-line img (+ pixel-x 15) pixel-y (+ pixel-x 15) (+ pixel-y 49) 0x606060) + (img-line img (+ pixel-x 35) pixel-y (+ pixel-x 35) (+ pixel-y 49) 0x606060) + ;; Add right and bottom border lines + (img-line img (+ pixel-x 49) pixel-y (+ pixel-x 49) (+ pixel-y 49) 0x606060) + (img-line img pixel-x (+ pixel-y 49) (+ pixel-x 49) (+ pixel-y 49) 0x606060) + }) + + ((eq tile-type 2) + { + ;; Wall with hieroglyph + (img-rectangle img pixel-x pixel-y 50 50 0x808080) + ;; Add texture + (img-line img pixel-x (+ pixel-y 12) (+ pixel-x 49) (+ pixel-y 12) 0x606060) + (img-line img pixel-x (+ pixel-y 37) (+ pixel-x 49) (+ pixel-y 37) 0x606060) + ;; Add right and bottom border lines + (img-line img (+ pixel-x 49) pixel-y (+ pixel-x 49) (+ pixel-y 49) 0x606060) + (img-line img pixel-x (+ pixel-y 49) (+ pixel-x 49) (+ pixel-y 49) 0x606060) + ;; Add hieroglyph - larger cross pattern + (img-rectangle img (+ pixel-x 20) (+ pixel-y 8) 10 34 0xFF4000) + (img-rectangle img (+ pixel-x 8) (+ pixel-y 20) 34 10 0xFF4000) + ;; Add dots for decoration + (img-rectangle img (+ pixel-x 12) (+ pixel-y 12) 6 6 0xFF4000) + (img-rectangle img (+ pixel-x 32) (+ pixel-y 32) 6 6 0xFF4000) + }) + + ((eq tile-type 3) + { + (img-rectangle img pixel-x pixel-y 50 50 0x808080) + ;; Large golden seal in center + (img-rectangle img (+ pixel-x 12) (+ pixel-y 12) 26 26 0xFFFF00) + (img-rectangle img (+ pixel-x 18) (+ pixel-y 18) 14 14 0xFF4000) + ;; Inner detail + (img-rectangle img (+ pixel-x 22) (+ pixel-y 22) 6 6 0xFFFF00) + }) + + ((eq tile-type 4) + { + ;; Open door - dark opening with archway + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Stone archway frame + (img-rectangle img pixel-x pixel-y 50 8 0x808080) + (img-rectangle img pixel-x (+ pixel-y 42) 50 8 0x808080) + (img-rectangle img pixel-x pixel-y 8 50 0x808080) + (img-rectangle img (+ pixel-x 42) pixel-y 8 50 0x808080) + ;; Archway details + (img-rectangle img (+ pixel-x 8) (+ pixel-y 8) 4 4 0x606060) + (img-rectangle img (+ pixel-x 38) (+ pixel-y 8) 4 4 0x606060) + }) + + ((eq tile-type 5) + { + ;; Left part of horizontal double door - closed + (img-rectangle img pixel-x pixel-y 50 50 0x808080) + ;; Left half of golden seal + (img-rectangle img (+ pixel-x 18) (+ pixel-y 12) 20 26 0xFFFF00) + (img-rectangle img (+ pixel-x 24) (+ pixel-y 18) 14 14 0xFF4000) + ;; Left border detail + (img-rectangle img pixel-x pixel-y 8 50 0x606060) + }) + + ((eq tile-type 6) + { + ;; Right part of horizontal double door - closed + (img-rectangle img pixel-x pixel-y 50 50 0x808080) + ;; Right half of golden seal + (img-rectangle img (+ pixel-x 12) (+ pixel-y 12) 20 26 0xFFFF00) + (img-rectangle img (+ pixel-x 12) (+ pixel-y 18) 14 14 0xFF4000) + ;; Right border detail + (img-rectangle img (+ pixel-x 42) pixel-y 8 50 0x606060) + }) + + ((eq tile-type 7) + { + ;; Top part of vertical double door - closed + (img-rectangle img pixel-x pixel-y 50 50 0x808080) + ;; Top half of golden seal + (img-rectangle img (+ pixel-x 12) (+ pixel-y 18) 26 20 0xFFFF00) + (img-rectangle img (+ pixel-x 18) (+ pixel-y 24) 14 14 0xFF4000) + ;; Top border detail + (img-rectangle img pixel-x pixel-y 50 8 0x606060) + }) + + ((eq tile-type 8) + { + ;; Bottom part of vertical double door - closed + (img-rectangle img pixel-x pixel-y 50 50 0x808080) + ;; Bottom half of golden seal + (img-rectangle img (+ pixel-x 12) (+ pixel-y 12) 26 20 0xFFFF00) + (img-rectangle img (+ pixel-x 18) (+ pixel-y 12) 14 14 0xFF4000) + ;; Bottom border detail + (img-rectangle img pixel-x (+ pixel-y 42) 50 8 0x606060) + }) + + ((eq tile-type 9) + { + ;; Left part of horizontal double door - open + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Left archway frame + (img-rectangle img pixel-x pixel-y 50 8 0x808080) + (img-rectangle img pixel-x (+ pixel-y 42) 50 8 0x808080) + (img-rectangle img pixel-x pixel-y 8 50 0x808080) + ;; Left archway detail + (img-rectangle img (+ pixel-x 8) (+ pixel-y 8) 4 4 0x606060) + }) + + ((eq tile-type 10) + { + ;; Right part of horizontal double door - open + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Right archway frame + (img-rectangle img pixel-x pixel-y 50 8 0x808080) + (img-rectangle img pixel-x (+ pixel-y 42) 50 8 0x808080) + (img-rectangle img (+ pixel-x 42) pixel-y 8 50 0x808080) + ;; Right archway detail + (img-rectangle img (+ pixel-x 38) (+ pixel-y 8) 4 4 0x606060) + }) + + ((eq tile-type 11) + { + ;; Top part of vertical double door - open + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Top archway frame + (img-rectangle img pixel-x pixel-y 50 8 0x808080) + (img-rectangle img pixel-x pixel-y 8 50 0x808080) + (img-rectangle img (+ pixel-x 42) pixel-y 8 50 0x808080) + ;; Top archway detail + (img-rectangle img (+ pixel-x 8) (+ pixel-y 8) 4 4 0x606060) + }) + + ((eq tile-type 12) + { + ;; Bottom part of vertical double door - open + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Bottom archway frame + (img-rectangle img pixel-x (+ pixel-y 42) 50 8 0x808080) + (img-rectangle img pixel-x pixel-y 8 50 0x808080) + (img-rectangle img (+ pixel-x 42) pixel-y 8 50 0x808080) + ;; Bottom archway detail + (img-rectangle img (+ pixel-x 8) (+ pixel-y 38) 4 4 0x606060) + }) + + ((eq tile-type 13) + { + ;; Closed chest - dark stone floor background + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Chest body - brown wood + (img-rectangle img (+ pixel-x 8) (+ pixel-y 20) 34 20 0x8B4513) + ;; Chest lid - darker brown + (img-rectangle img (+ pixel-x 8) (+ pixel-y 15) 34 8 0x654321) + ;; Metal bands - dark gray + (img-rectangle img (+ pixel-x 6) (+ pixel-y 18) 38 3 0x404040) + (img-rectangle img (+ pixel-x 6) (+ pixel-y 35) 38 3 0x404040) + ;; Lock - golden + (img-rectangle img (+ pixel-x 22) (+ pixel-y 22) 6 8 0xFFD700) + ;; Lock detail + (img-rectangle img (+ pixel-x 24) (+ pixel-y 24) 2 4 0x000000) + }) + + ((eq tile-type 14) + { + ;; Open chest - dark stone floor background + (img-rectangle img pixel-x pixel-y 50 50 0x202020) + ;; Chest body - brown wood + (img-rectangle img (+ pixel-x 8) (+ pixel-y 25) 34 15 0x8B4513) + ;; Open lid - tilted back, darker brown + (img-rectangle img (+ pixel-x 10) (+ pixel-y 8) 30 12 0x654321) + ;; Lid hinge shadow + (img-rectangle img (+ pixel-x 8) (+ pixel-y 20) 34 3 0x404040) + ;; Metal bands on body + (img-rectangle img (+ pixel-x 6) (+ pixel-y 35) 38 3 0x404040) + ;; Interior - dark with golden glow + (img-rectangle img (+ pixel-x 10) (+ pixel-y 27) 30 10 0x1A1A1A) + ;; Golden treasure glow + (img-rectangle img (+ pixel-x 20) (+ pixel-y 30) 10 4 0xFFD700) + (img-rectangle img (+ pixel-x 22) (+ pixel-y 28) 6 2 0xFFF8DC) + }) + +) + })) + +;; Render entire room from tile array (8x8) with background and characters +(define render-room-from-tiles (lambda (img tile-array) + { + (var tile-index 0) + (looprange y 0 8 { + (looprange x 0 8{ + (var tile-type (bufget-u8 tile-array tile-index)) + (render-tile img x y tile-type) + (setq x (+ x 1)) + (setq tile-index (+ tile-index 1)) + }) + (setq y (+ y 1)) + }) + })) + +;; Helper function to set a tile in the byte array +(define set-tile (lambda (tile-array x y tile-type) + (bufset-u8 tile-array (+ (* y 8) x) tile-type))) + +;; Helper function to get a tile from the byte array +(define get-tile (lambda (tile-array x y) + (bufget-u8 tile-array (+ (* y 8) x)))) + +;; Helper function to open a door at specific position +(define open-door (lambda (tile-array x y) + { + (var current-tile (bufget-u8 tile-array (+ (* y 8) x))) + (var new-tile (match current-tile + (3 4) ; door -> open_door + (5 9) ; door_left -> open_door_left + (6 10) ; door_right -> open_door_right + (7 11) ; door_top -> open_door_top + (8 12) ; door_bottom -> open_door_bottom + (_ current-tile))) ; no change for non-door tiles + (bufset-u8 tile-array (+ (* y 8) x) new-tile) + })) + +;; Character rendering functions +;; Legacy pixel-coordinate versions (deprecated - use tile versions instead) +(define render-wizard-pixels (lambda (img x y) + { + ;; Wizard robe - dark blue + (img-rectangle img (+ x 18) (+ y 15) 14 30 0x0000FF) + ;; Wizard hat - pointed hat + (img-rectangle img (+ x 22) (+ y 8) 6 12 0x0000FF) + (img-rectangle img (+ x 24) (+ y 5) 2 8 0x0000FF) + ;; Face - light skin + (img-rectangle img (+ x 22) (+ y 12) 6 6 0xFFCCBB) + ;; Staff - brown with crystal + (img-rectangle img (+ x 12) (+ y 10) 3 25 0x8B4513) + (img-rectangle img (+ x 10) (+ y 8) 7 4 0x00FFFF) + })) + +;; Tile-coordinate version (preferred) +(define render-wizard (lambda (img tile-x tile-y) + (render-wizard-pixels img (* tile-x 50) (* tile-y 50)))) + +;; Legacy pixel-coordinate version (deprecated - use tile version instead) +(define render-player-pixels (lambda (img x y) + { + ;; Player body - green tunic + (img-rectangle img (+ x 20) (+ y 18) 10 22 0x00AA00) + ;; Head - light skin + (img-rectangle img (+ x 22) (+ y 12) 6 6 0xFFCCBB) + ;; Hair - brown + (img-rectangle img (+ x 21) (+ y 10) 8 4 0x8B4513) + ;; Arms - skin colored + (img-rectangle img (+ x 16) (+ y 20) 4 12 0xFFCCBB) + (img-rectangle img (+ x 30) (+ y 20) 4 12 0xFFCCBB) + ;; Legs - brown pants + (img-rectangle img (+ x 20) (+ y 40) 4 8 0x654321) + (img-rectangle img (+ x 26) (+ y 40) 4 8 0x654321) + })) + +;; Tile-coordinate version (preferred) +(define render-player (lambda (img tile-x tile-y) + (render-player-pixels img (* tile-x 50) (* tile-y 50)))) + +;; Legacy pixel-coordinate version (deprecated - use tile version instead) +(define render-evil-snake-wielder-pixels (lambda (img x y) + { + ;; Corrupted wizard - dark robes with red accents + (img-rectangle img (+ x 18) (+ y 15) 14 30 0x2B2B2B) ; Dark gray robe + ;; Evil red trim on robe + (img-rectangle img (+ x 17) (+ y 15) 16 2 0xFF0000) + (img-rectangle img (+ x 17) (+ y 43) 16 2 0xFF0000) + ;; Twisted pointed hat - dark with red tip + (img-rectangle img (+ x 22) (+ y 8) 6 12 0x2B2B2B) + (img-rectangle img (+ x 24) (+ y 5) 2 8 0x2B2B2B) + (img-rectangle img (+ x 24) (+ y 5) 2 3 0xFF0000) ; Red tip + ;; Pale corrupted face + (img-rectangle img (+ x 22) (+ y 12) 6 6 0xDDDDDD) + ;; Red glowing eyes + (img-rectangle img (+ x 23) (+ y 13) 2 2 0xFF0000) + (img-rectangle img (+ x 27) (+ y 13) 2 2 0xFF0000) + ;; Snake staff - twisted with serpent head + (img-rectangle img (+ x 10) (+ y 10) 3 25 0x4A4A4A) ; Dark staff + ;; Serpent head on staff + (img-rectangle img (+ x 8) (+ y 8) 7 6 0x006600) ; Green snake head + (img-rectangle img (+ x 7) (+ y 9) 2 2 0xFF0000) ; Red eyes + (img-rectangle img (+ x 6) (+ y 10) 2 1 0xFF6600) ; Forked tongue + ;; Dark aura around feet + (img-rectangle img (+ x 16) (+ y 44) 18 4 0x1A1A1A) + })) + +;; Tile-coordinate version (preferred) +(define render-evil-snake-wielder (lambda (img tile-x tile-y) + (render-evil-snake-wielder-pixels img (* tile-x 50) (* tile-y 50)))) + +;; Snake sprite system for representing lists +;; Snake colors: head=red, body=green, different shades for depth + +;; Snake head with triangular snout for better direction indication +(define render-snake-head + (lambda (img x y direction) + (cond + ((eq direction 'east) + (progn + ;; Main head body (rectangular) + (img-rectangle img (+ x 17) (+ y 18) 18 14 0xFF0000) + ;; Eyes on the head body + (img-rectangle img (+ x 29) (+ y 21) 3 3 0xFFFFFF) + (img-rectangle img (+ x 29) (+ y 27) 3 3 0xFFFFFF) + ;; Triangular snout pointing west + (img-rectangle img (+ x 13) (+ y 22) 4 6 0xCC0000) ; base of triangle + (img-rectangle img (+ x 11) (+ y 23) 2 4 0xCC0000) ; middle of triangle + (img-rectangle img (+ x 10) (+ y 24) 1 2 0xCC0000) ; tip of triangle + )) + ((eq direction 'west) + (progn + ;; Main head body (rectangular) + (img-rectangle img (+ x 15) (+ y 18) 18 14 0xFF0000) + ;; Eyes on the head body + (img-rectangle img (+ x 18) (+ y 21) 3 3 0xFFFFFF) + (img-rectangle img (+ x 18) (+ y 27) 3 3 0xFFFFFF) + ;; Triangular snout pointing east (made with rectangles) + (img-rectangle img (+ x 33) (+ y 22) 4 6 0xCC0000) ; base of triangle + (img-rectangle img (+ x 37) (+ y 23) 2 4 0xCC0000) ; middle of triangle + (img-rectangle img (+ x 39) (+ y 24) 1 2 0xCC0000) ; tip of triangle + )) + ((eq direction 'north) + (progn + ;; Main head body (rectangular) + (img-rectangle img (+ x 18) (+ y 17) 14 18 0xFF0000) + ;; Eyes on the head body + (img-rectangle img (+ x 21) (+ y 29) 3 3 0xFFFFFF) + (img-rectangle img (+ x 27) (+ y 29) 3 3 0xFFFFFF) + ;; Triangular snout pointing north + (img-rectangle img (+ x 22) (+ y 13) 6 4 0xCC0000) ; base of triangle + (img-rectangle img (+ x 23) (+ y 11) 4 2 0xCC0000) ; middle of triangle + (img-rectangle img (+ x 24) (+ y 10) 2 1 0xCC0000) ; tip of triangle + )) + ((eq direction 'south) + (progn + ;; Main head body (rectangular) + (img-rectangle img (+ x 18) (+ y 15) 14 18 0xFF0000) + ;; Eyes on the head body + (img-rectangle img (+ x 21) (+ y 18) 3 3 0xFFFFFF) + (img-rectangle img (+ x 27) (+ y 18) 3 3 0xFFFFFF) + ;; Triangular snout pointing south + (img-rectangle img (+ x 22) (+ y 33) 6 4 0xCC0000) ; base of triangle + (img-rectangle img (+ x 23) (+ y 37) 4 2 0xCC0000) ; middle of triangle + (img-rectangle img (+ x 24) (+ y 39) 2 1 0xCC0000) ; tip of triangle + )) + (t (img-rectangle img (+ x 20) (+ y 20) 10 10 0xFF0000))))) + +;; Snake body segment - horizontal +(define render-snake-body-h (lambda (img x y) + (img-rectangle img (+ x 10) (+ y 20) 30 10 0x00AA00))) + +;; Snake body segment - vertical +(define render-snake-body-v (lambda (img x y) + (img-rectangle img (+ x 20) (+ y 10) 10 30 0x00AA00))) + +;; Snake corner pieces - 4 basic shapes cover all 8 transitions +;; NE corner (north-east turn and east-north turn) +(define render-snake-corner-ne (lambda (img x y) + (progn + ;; Vertical part (north connection) + (img-rectangle img (+ x 20) (+ y 10) 10 20 0x00AA00) + ;; Horizontal part (east connection) + (img-rectangle img (+ x 25) (+ y 20) 15 10 0x00AA00)))) + +;; NW corner (north-west turn and west-north turn) +(define render-snake-corner-nw (lambda (img x y) + (progn + ;; Vertical part (north connection) + (img-rectangle img (+ x 20) (+ y 10) 10 20 0x00AA00) + ;; Horizontal part (west connection) + (img-rectangle img (+ x 10) (+ y 20) 15 10 0x00AA00)))) + +;; SE corner (south-east turn and east-south turn) +(define render-snake-corner-se (lambda (img x y) + (progn + ;; Vertical part (south connection) + (img-rectangle img (+ x 20) (+ y 20) 10 20 0x00AA00) + ;; Horizontal part (east connection) + (img-rectangle img (+ x 25) (+ y 20) 15 10 0x00AA00)))) + +;; SW corner (south-west turn and west-south turn) +(define render-snake-corner-sw (lambda (img x y) + (progn + ;; Vertical part (south connection) + (img-rectangle img (+ x 20) (+ y 20) 10 20 0x00AA00) + ;; Horizontal part (west connection) + (img-rectangle img (+ x 10) (+ y 20) 15 10 0x00AA00)))) + + +(define render-snake-tail (lambda (img x y) + (img-rectangle img (+ x 20) (+ y 20) 10 10 0x006600))) + +(define translate-snake-render-pos + (lambda (x y direction) + (match direction + ;; Straight segments + (ew (cons (- x 50) y)) + (we (cons (+ x 50) y)) + (ns (cons x (+ y 50))) + (sn (cons x (- y 50))) + ;; Corner transitions - position depends on turn direction + (ne (cons (+ x 50) y)) + (en (cons x (- y 50))) + (nw (cons x (+ y 50))) + (wn (cons x (- y 50))) + (se (cons (+ x 50) y)) + (sw (cons (- x 50) y)) + (ws (cons x (+ y 50)))))) + +(define is-snake + (let ((is-snake-part + (lambda (x) + (match x + (ew t) + (we t) + (ns t) + (sn t) + (ne t) ; north->east turn, head faces south + (en t) ; east->north turn, head faces west + (nw t) ; north->west turn, head faces south + (wn t) ; west->north turn, head faces east + (se t) ; south->east turn, head faces north + (es t) ; east->south turn, head faces west + (sw t) ; south->west turn, head faces north + (ws t))))) + (lambda (ls) + (cond ((eq ls nil) t) + ((eq (type-of ls) type-list) + (if (eq ls nil) t + (and (is-snake-part (car ls)) (is-snake (cdr ls))))))))) + + +(define is-prefix + (lambda (a b) + (if (eq a nil) t + (if (eq (car a) (car b)) + (is-prefix (cdr a) (cdr b)) + nil)))) + +(define is-suffix + (lambda (a b) + (is-prefix (reverse a) (reverse b)))) + + +;; Legacy pixel-coordinate version (deprecated - use tile version instead) +(define render-snake-from-path-pixels (lambda (img head-x head-y directions) + (if (eq directions nil) + ;; Empty list - render tombstone (defeated snake) centered in 50x50 tile + (progn + ;; Tombstone base (dark gray stone) - centered in tile + (img-rectangle img (+ head-x 15) (+ head-y 20) 20 25 0x606060 '(filled)) + ;; Tombstone top (rounded with smaller rectangle) + (img-arc img (+ head-x 25) (+ head-y 20) 10 180 360 0x606060 '(filled)) + ) + ;; Non-empty list - render snake from directions + (progn + ;; Draw head facing opposite of first direction + (var first-dir (car directions)) + (var head-facing (match first-dir + (ew 'west) + (we 'east) + (ns 'north) + (sn 'south) + ;; Corner transitions - head faces the "from" direction + (ne 'south) ; north->east turn, head faces south + (en 'west) ; east->north turn, head faces west + (nw 'south) ; north->west turn, head faces south + (wn 'east) ; west->north turn, head faces east + (se 'north) ; south->east turn, head faces north + (es 'west) ; east->south turn, head faces west + (sw 'north) ; south->west turn, head faces north + (ws 'east) ; west->south turn, head faces east + (_ 'east))) + (render-snake-head img head-x head-y head-facing) + ;; Draw body segments + + (var (curr-x . curr-y) (translate-snake-render-pos head-x head-y first-dir)) + + (var dir-list (cdr directions)) + (loopwhile dir-list { + (var dir (car dir-list)) + ;; Move to next position based on direction + ;; Draw appropriate segment + ;; Body segment or corner + (match dir + ;; Corner pieces + (ne (render-snake-corner-ne img curr-x curr-y)) + (en (render-snake-corner-ne img curr-x curr-y)) + (nw (render-snake-corner-nw img curr-x curr-y)) + (wn (render-snake-corner-nw img curr-x curr-y)) + (se (render-snake-corner-se img curr-x curr-y)) + (es (render-snake-corner-se img curr-x curr-y)) + (sw (render-snake-corner-sw img curr-x curr-y)) + (ws (render-snake-corner-sw img curr-x curr-y)) + ;; Straight body segments + (ew (render-snake-body-h img curr-x curr-y)) + (we (render-snake-body-h img curr-x curr-y)) + (ns (render-snake-body-v img curr-x curr-y)) + (sn (render-snake-body-v img curr-x curr-y))) + + (var (new-x . new-y) (translate-snake-render-pos curr-x curr-y dir)) + (setq curr-x new-x) + (setq curr-y new-y) + + (setq dir-list (cdr dir-list)) + }) + (render-snake-tail img curr-x curr-y) + ) + ))) + +;; Tile-coordinate version (preferred) +(define render-snake-from-path (lambda (img tile-x tile-y directions) + (render-snake-from-path-pixels img (* tile-x 50) (* tile-y 50) directions))) + +;; Demo function: render a sample snake representing list '(1 2 3) +(define demo-snake (lambda (img) + { + ;; Simple L-shaped snake: head east, corner, body down, tail + (var snake-path '((50 100 'east 'head) + (100 100 'east 'corner-se) + (100 150 'south 'body-v) + (100 200 'south 'tail))) + (render-snake-from-path img snake-path) + (var a-dead-snake '()) + (render-snake-from-path img a-dead-snake) + })) + diff --git a/lispBM/lispBM/repl/game/lispwizard/rungame.sh b/lispBM/lispBM/repl/game/lispwizard/rungame.sh new file mode 100755 index 0000000000..4581f2e5a1 --- /dev/null +++ b/lispBM/lispBM/repl/game/lispwizard/rungame.sh @@ -0,0 +1,8 @@ +#!/bin/bash + + +if [ -f ../../repl ]; then + ../../repl -M 11 -H 32000 -s game.lisp +else + echo "Go to directory ../../ and run 'make sdl_old' to build the repl with SDL support" +fi diff --git a/lispBM/lispBM/repl/game/lispwizard/snake_room.lisp b/lispBM/lispBM/repl/game/lispwizard/snake_room.lisp new file mode 100644 index 0000000000..4807b33902 --- /dev/null +++ b/lispBM/lispBM/repl/game/lispwizard/snake_room.lisp @@ -0,0 +1,140 @@ + +(define ernst-hugo '(sn se we we ws)) + +(define snake-room-persistant-assoc + (acons 'player-y 4 + (acons 'player-x 2 + (acons 'wizard-y 3 + (acons 'wizard-x 1 + (acons 'cleared nil + (acons 'door-open nil + '()))))))) + +;; Create the room tile map with variety: 0=floor, 1=wall, 2=hieroglyph, 3=door +(define room-tiles [ 1 2 1 5 6 1 2 1 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 11 0 0 0 0 0 0 1 + 12 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 1 1 1 1 1 1 1 1 ]) + +(define snake-room-done nil) + +;; room thread +(lambda () + { + ;; Get display buffer from game state + (var disp (assoc game-state 'disp)) + + (print "The wizard leans towards you and whispers:") + (print "\"The door is blocked by a serpentine monstrosity.\"") + (print "\"To battle this beast you must determine its name.\"") + (print "\"look at the snake (look snake) for clues to its identity.\"") + + (loopwhile (not snake-room-done) { + + (if (not (assoc snake-room-persistant-assoc 'cleared)) + (cond ((eq nil ernst-hugo) { + (print "Excellent! You cleared a path to the door.") + (setassoc snake-room-persistant-assoc 'cleared t) + }) + ((and (is-snake ernst-hugo) (<= (length ernst-hugo) 1)) { + (print "Fantastic! You cleared a path to the door.") + (print "Virtously you let the snake live.") + (setassoc snake-room-persistant-assoc 'cleared t) + }) + ((or (not (is-snake ernst-hugo)) + (not (is-suffix ernst-hugo'(sn se we we ws)))) { + (setq ernst-hugo '(sn se we we ws)) + (print "ernst-hugo is resisting your attack!") + }) + ) + ) + + (img-clear disp) + (render-room-from-tiles disp room-tiles) + (render-snake-from-path disp 2 2 ernst-hugo) + + (render-wizard disp + (assoc snake-room-persistant-assoc 'wizard-x) + (assoc snake-room-persistant-assoc 'wizard-y)) + (render-player disp + (assoc snake-room-persistant-assoc 'player-x) + (assoc snake-room-persistant-assoc 'player-y)) + + (disp-render disp 0 0 (list)) + + ;; Handle messages + (recv-to 0.1 ; Wait 10ms for messages + ((look wizard) { + (print "The wizard is old and wise.") + (print "") + (print "The wizard speaks:") + (print "\"You can always look around for clues.\"") + }) + ((look snake) { + (print "The snake is quite scary looking.") + (print "") + (print "The snake hisses:") + (print "\"Who dares disturb ernst-hugo?\"") + (print "") + (print "The wizard exclaims:") + (print "\"We are in luck the vicious serpent gives his name freely!\"") + (print "") + (print "ernst-hugo snaps back:") + (print "\"Puny mortals, you are no danger to me.\"") + (print "\"I was defined into existence by the ancient gods\"") + (print "\"and can only be destroyed by equally powerful magic.\"") + (print "") + }) + ((look grave) + (if (eq ernst-hugo nil) + (print "Here lies ernst-hugo loving father and caring husband.") + (Print "What grave?"); + ((look door) + (if (assoc snake-room-persistant-assoc 'door-open) + (print "The door towards the north is open.\n") + (print "The door towards the north is closed.\n"))) + ((look _) { + (print "You stand in an ancient stone chamber.") + (print "A wise wizard watches from the shadows.") + (print "To the north, a scaled beast coils before sealed doors.") + }) + + ((go north) + (if (not (assoc snake-room-persistant-assoc 'door-open)) + (print "The door is sealed shut.") + { + ;(print "You leave through the door towards the north") + (send (assoc game-state 'main-cid) '(room-change north)) + (setq snake-room-done t) + } + ) + ) + ((go west) + nil + ) + + + ((open door) + { + (if (assoc snake-room-persistant-assoc 'cleared) + { + (open-door room-tiles 3 0) + (open-door room-tiles 4 0) + (setassoc snake-room-persistant-assoc 'door-open t) + (print "The door opens with a grinding sound of ancient stone.") + } + (print "Impossible, there is a giant snake in the way")) + }) + + (quit break) ; Add quit message handler + (no-more break) + + (timeout ()) + ((? x) (print x))) ; Timeout - continue loop + }) + (print "Leaving the snake room.") + }) diff --git a/lispBM/lispBM/repl/game/lispwizard/start_room.lisp b/lispBM/lispBM/repl/game/lispwizard/start_room.lisp new file mode 100644 index 0000000000..cac7163a51 --- /dev/null +++ b/lispBM/lispBM/repl/game/lispwizard/start_room.lisp @@ -0,0 +1,159 @@ + +(define start-room-persistant-assoc + (acons 'player-y 3 + (acons 'player-x 4 + (acons 'wizard-y 2 + (acons 'wizard-x 2 + (acons 'cleared nil + (acons 'door-open nil + (acons 'chest-open nil + '())))))))) + +(define room-tiles [ 1 2 1 1 1 1 2 1 + 2 0 0 0 0 0 0 2 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 7 + 1 0 0 0 0 0 0 8 + 1 0 0 0 0 0 0 1 + 2 0 0 0 0 0 13 2 + 1 2 1 1 1 1 2 1 ]) + +(define start-room-done nil) + +;; room thread +(lambda () + { + ;; Get display buffer from game state + (var disp (assoc game-state 'disp)) + + (print "The wizard speaks to you in a thundering voice:") + (print "\"I have brought you here because the world is in trouble.\"") + (print "\"The language of the gods is fading from memory.\"") + (print "\"But you still have the potential to learn the language...\"") + (print "\"and to save us from the evil that is poisoning the minds of our young.\"") + (print "") + + (var t0 (systime)) + (var help1-displayed nil) + (var help2-displayed nil) + (var looked-wizard nil) + (var looked-wizard-displayed nil) + + (loopwhile (not start-room-done) + { + + (if (and (not help1-displayed) (< 10 (secs-since t0))) + { + (setq help1-displayed t) + (print "The wizard sighs and says more gently:") + (print "\"The language of the gods requires precise incantations.\"") + (print "\"You need to first figure out how to interact with your surroundings.\"") + (print "\"We can only act in, and on, this magic realm through incantations.\"") + (print "\"I can teach you the basics...\"") + (print "") + }) + + (if (and (not help2-displayed) (< 20 (secs-since t0))) + { + (setq help2-displayed t) + (print "The wizard continues:") + (print "\"First, try to perceive more details of your surroundings by looking at things.\"") + (print "\"Look at me by using the incantation (look wizard)\"") + (print "") + + }) + + (if (and looked-wizard (not looked-wizard-displayed)) + { + (setq looked-wizard-displayed t) + (print "The wizard smiles:") + (print "\"Very good. Now try to look at other things.\"") + (print "") + } + ) + + (if (not (assoc start-room-persistant-assoc 'cleared)) + () ;; room clear logic + ) + + + (img-clear disp) + (render-room-from-tiles disp room-tiles) + + ;(render-evil-snake-wielder disp 250 250) + (render-wizard disp + (assoc start-room-persistant-assoc 'wizard-x) + (assoc start-room-persistant-assoc 'wizard-y)) + (render-player disp + (assoc start-room-persistant-assoc 'player-x) + (assoc start-room-persistant-assoc 'player-y)) + + (disp-render disp 0 0 (list)) + + ;; Handle messages + (recv-to 0.1 ; Wait 10ms for messages + ((look wizard) { + (setq looked-wizard t) + (print "The wizard is old and wise.\n") + }) + ((look door) + (print "There is a door leading east.\n")) + ((look chest) + (print "The chest looks old. There does not seem to be any lock on it.\n")) + ((look runes) { + (print "The runes read:") + (print "nil cons cdr lambda eval") + }) + ((look _) { + (print "There is a wizard in the room and a door leading east.") + (print "Strange runes are covering the walls.") + (print "There is a chest in the corner of the room.") + }) + + ((go east) + (if (not (assoc start-room-persistant-assoc 'door-open)) + (print "The door is sealed shut.") + { + (send (assoc game-state 'main-cid) '(room-change east)) + (setq start-room-done t) + } + ) + ) + ((go _) + (print "There is no passage in that direction!")) + + ((open chest) { + (if (not (assoc start-room-persistant-assoc 'chest-open)) { + (set-tile room-tiles 6 6 14) + (setassoc start-room-persistant-assoc 'chest-open t) + (setassoc start-room-persistant-assoc 'cleared t) + (print "The chest opens with a creak. Inside you find the key to the door.") + (print "") + (print "The wizard nods approvingly:") + (print "\"The door will open for you now.\"") + } + (print "The chest is already open")) + }) + ((open door) + { + (if (assoc start-room-persistant-assoc 'cleared) + { + (open-door room-tiles 7 3) + (open-door room-tiles 7 4) + (setassoc start-room-persistant-assoc 'door-open t) + (print "The door opens with a grinding sound of ancient stone.") + } + (print "Impossible! The door is locked!")) + }) + ((open (? x)) + (print "The " x " cannot be opened.") + ) + + (quit break) ; Add quit message handler + (no-more break) + + (timeout ()) + ((? x) (print x))) ; Timeout - continue loop + }) + (print "Leaving the start room.") + }) diff --git a/lispBM/lispBM/repl/game/lispwizard/test_room.lisp b/lispBM/lispBM/repl/game/lispwizard/test_room.lisp new file mode 100644 index 0000000000..9ac6749423 --- /dev/null +++ b/lispBM/lispBM/repl/game/lispwizard/test_room.lisp @@ -0,0 +1,57 @@ + +(define test_room_persistant_assoc '()) + +;; Create the room tile map with variety: 0=floor, 1=wall, 2=hieroglyph, 3=door +(define room-tiles [ 1 2 1 1 1 1 2 1 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 1 0 0 0 0 0 0 1 + 1 1 1 1 1 1 1 1 ]) + + +;; room thread +(lambda () + { + ;; Get display buffer from game state + (var disp (assoc game-state 'disp)) + + (print "This is a test room") + (loopwhile t { + + (img-clear disp ) + ;; Render the room using the consolidated function + (render-room-from-tiles disp room-tiles) + + ;; Demo: test horizontal snake (using tile coordinates) + (render-snake-from-path disp 1 1 '()) + (render-snake-from-path disp 1 3 '(we wn )) + (render-snake-from-path disp 4 3 '(we ws ns ns)) + (disp-render disp 0 0 (list)) + + ;; Handle messages + (recv-to 0.1 ; Wait 10ms for messages + (look + { + (print "You are in the test room") + }) + + ((look _ ) + (print "The walls are covered in ancient texts written in an obscure language.\n")) + + ((go north ) + { + (if (assoc test_room_persistant_assoc 'door-open) + (print sender '(room-change 0 . 1)) + (print sender "The door is sealed shut.")) + }) + + (quit break) + (no-more break) + + (timeout ()) + ((? x) (print x))) ; Timeout - continue loop + }) + }) diff --git a/lispBM/lispBM/repl/lbm_sdl.c b/lispBM/lispBM/repl/lbm_sdl.c index fa7840c6a5..6785b989d4 100644 --- a/lispBM/lispBM/repl/lbm_sdl.c +++ b/lispBM/lispBM/repl/lbm_sdl.c @@ -1,5 +1,5 @@ /* - Copyright 2022 Joel Svensson svenssonjoel@yahoo.se + Copyright 2022, 2025 Joel Svensson svenssonjoel@yahoo.se This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -215,10 +215,27 @@ static lbm_value ext_sdl_present(lbm_value *args, lbm_uint argn) { static lbm_value ext_sdl_poll_event(lbm_value *args, lbm_uint argn) { SDL_Event event; + lbm_value r = lbm_enc_sym(lookup_sdl_event_symbol(0)); - if (SDL_PollEvent(&event) == 0) - return lbm_enc_sym(lookup_sdl_event_symbol(0)); - return lbm_enc_sym(lookup_sdl_event_symbol(event.type)); + SDL_PumpEvents(); + + if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0) { + + if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) { + lbm_value key = lbm_enc_i(event.key.keysym.sym); + lbm_value sym = lbm_enc_sym(lookup_sdl_event_symbol(event.type)); + + lbm_value res_pair = lbm_cons(sym,key); + if (res_pair == ENC_SYM_MERROR) goto poll_event_exit; + r = res_pair; + } else { + r = lbm_enc_sym(lookup_sdl_event_symbol(event.type)); + } + // This just drops the event from the queue. + SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); + } + poll_event_exit: + return r; } @@ -418,6 +435,10 @@ bool sdl_render_image(image_buffer_t *img, uint16_t x, uint16_t y, color_t *colo uint8_t bpp = img->fmt; SDL_Texture* tex = SDL_CreateTexture(active_rend, SDL_PIXELFORMAT_RGB888,SDL_TEXTUREACCESS_STREAMING, w, h); + if (!tex) { + printf("lbm_sdl: Failed allocating texture\n"); + return false; + } int pitch = 0; uint8_t* p = NULL; diff --git a/lispBM/lispBM/repl/repl.c b/lispBM/lispBM/repl/repl.c index 2e4dfd343d..12f9d2d4c4 100644 --- a/lispBM/lispBM/repl/repl.c +++ b/lispBM/lispBM/repl/repl.c @@ -42,6 +42,7 @@ #include #include #include +#include #endif //network @@ -73,6 +74,9 @@ #include "lbm_sdl.h" #endif +#include "platform_mutex.h" +#include "platform_timestamp.h" + // things directly copied from VESC_EXPRESS #include "packet.h" #include "comm_packet_id.h" @@ -81,6 +85,7 @@ typedef void (*send_func_t)(unsigned char *, unsigned int); +static void handle_repl_output(void); // //////////////////////////////////////////////////////////// // Stub loaders @@ -90,6 +95,7 @@ void load_bldc_extensions(void); // //////////////////////////////////////////////////////////// // win util + #ifdef LBM_WIN #define G 1000000000L @@ -119,6 +125,91 @@ int nanosleep(const struct timespec* ts, struct timespec* rem){ } #endif +// //////////////////////////////////////////////////////////// +// IO buffer + +#define IO_BUFFER_SIZE 8192 + +static char iobuffer[IO_BUFFER_SIZE]; +static int iobuffer_head = 0; +static int iobuffer_tail = 0; +static bool iobuffer_full = false; +static bool iobuffer_mutex_initialized = false; + +static mutex_t iobuffer_mutex; // use platform_mutex + +static void iobuffer_init(void) { + + iobuffer_head = 0; + iobuffer_tail = 0; + iobuffer_full = false; + if (!iobuffer_mutex_initialized) { + mutex_init(&iobuffer_mutex); + iobuffer_mutex_initialized = true; + } +} + +static int iobuffer_num(void) { + int res = IO_BUFFER_SIZE; + if (!iobuffer_full) { + if (iobuffer_head >= iobuffer_tail) { + res = iobuffer_head - iobuffer_tail; + } else { + res = IO_BUFFER_SIZE - iobuffer_tail + iobuffer_head; + } + } + return res; +} + +static void iobuffer_put(char c) { + + if (!iobuffer_full) { + iobuffer[iobuffer_head] = c; + iobuffer_head = (iobuffer_head + 1) % IO_BUFFER_SIZE; + iobuffer_full = iobuffer_head == iobuffer_tail; + } else { + iobuffer[iobuffer_head] = c; + iobuffer_head = (iobuffer_head + 1) % IO_BUFFER_SIZE; + iobuffer_tail = (iobuffer_tail + 1) % IO_BUFFER_SIZE; + } +} + +static void iobuffer_print(void) { + mutex_lock(&iobuffer_mutex); + if ((iobuffer_tail == iobuffer_head) && !iobuffer_full) { + mutex_unlock(&iobuffer_mutex); + return; // empty + } + + if (iobuffer_tail <= iobuffer_head) { + for (int i = iobuffer_tail; i < iobuffer_head; i++) { + putchar(iobuffer[i]); + } + } else { + for (int i = iobuffer_tail; i < IO_BUFFER_SIZE; i ++) { + putchar(iobuffer[i]); + } + for (int i = 0; i < iobuffer_head; i ++) { + putchar(iobuffer[i]); + } + } + iobuffer_head = 0; + iobuffer_tail = 0; + iobuffer_full = false; + mutex_unlock(&iobuffer_mutex); +} + +static void iobuffer_write(char *str) { + mutex_lock(&iobuffer_mutex); + for (; *str != 0; str++) { + iobuffer_put(*str); + } + mutex_unlock(&iobuffer_mutex); +} + + + + // //////////////////////////////////////////////////////////// // General @@ -174,7 +265,6 @@ static uint32_t *image_storage = NULL; static size_t constants_memory_size = 4096; // size words - // //////////////////////////////////////////////////////////// // LBM #define GC_STACK_SIZE 256 @@ -208,6 +298,26 @@ static pthread_t prof_thread; static HANDLE prof_thread; #endif +#ifndef LBM_WIN +static pthread_t timestamp_thread; +#else +static HANDLE timestamp_thread; +#endif + +#ifndef LBM_WIN +pthread_t lispbm_thd = 0; +#else +HANDLE lispbm_thd; +#endif + +unsigned int heap_size = 2048; // default +lbm_cons_t *heap_storage = NULL; +lbm_heap_state_t heap_state; +lbm_const_heap_t const_heap; + +static bool repl_mode = false; + + struct read_state_s { char *str; // String being read. lbm_cid cid; // Reader thread id. @@ -262,54 +372,29 @@ bool drop_reader(lbm_cid cid) { return r; } -typedef struct ctx_list_s { - lbm_cid cid; - struct ctx_list_s *next; -} ctx_list_t; - -static void add_ctx(ctx_list_t **list, lbm_cid cid) { - ctx_list_t *new_head = (ctx_list_t*)malloc(sizeof(ctx_list_t)); - if (new_head) { - new_head->cid = cid; - new_head->next = *list; - *list = new_head; - } else { - printf("Couldn't allocate ctx list\n"); - } -} - -static bool drop_ctx(ctx_list_t **list, lbm_cid cid) { - bool r = false; - ctx_list_t *prev = NULL; - ctx_list_t *curr = *list; - - while (curr) { - if (curr->cid == cid) { - if (prev) { - prev->next = curr->next; - } else { - *list = curr->next; - } - - free(curr); - r = true; - break; - } - prev = curr; - curr = curr->next; - } - return r; -} - -// List of contexts directly started by the REPL. -static ctx_list_t *repl_ctxs = NULL; - void shutdown_procedure(void); void terminate_repl(int exit_code) { + if (lispbm_thd && lbm_get_eval_state() != EVAL_CPS_STATE_DEAD) { + lbm_kill_eval(); +#ifdef LBM_WIN + WaitForSingleObject(lispbm_thd, INFINITE); +#else + int thread_r = 0; + pthread_join(lispbm_thd, (void*)&thread_r); +#endif + lispbm_thd = 0; + } if (!silent_mode) { printf("%s\n", repl_exit_message[exit_code]); } + rl_cleanup_after_signal(); + rl_callback_handler_remove(); + + if (heap_storage) { + free(heap_storage); + heap_storage = NULL; + } exit(exit_code); } @@ -325,6 +410,7 @@ bool const_heap_write(lbm_uint ix, lbm_uint w) { } bool image_write(uint32_t w, int32_t ix, bool const_heap) { // ix >= 0 and ix <= image_size + (void) const_heap; if (image_storage[ix] == 0xffffffff) { image_storage[ix] = w; return true; @@ -339,78 +425,34 @@ bool image_clear(void) { return true; } - +// TODO: These are shared state that can be abused! +// The readers list should containt string_tokenizers, not just strings. static lbm_char_channel_t string_tok; static lbm_string_channel_state_t string_tok_state; -static int vsprintf_allocate(char **result, const char *format, va_list args) { - va_list args_copy; - va_copy(args_copy, args); - int len_result = vsnprintf(NULL, 0, format, args_copy); - va_end(args_copy); - - if (len_result < 0) { - return len_result; - } - - // Allocate buffer - *result = malloc((size_t)len_result + 1); - if (!*result) { - return -1; - } - - len_result = vsnprintf(*result, (size_t)len_result + 1, format, args); - - return len_result; +static int printf_callback(const char *format, ...) { + char buffer[2048]; + va_list args; + va_start(args, format); + memset(buffer,0, 2048); + int len = vsnprintf(buffer, 2048, format, args); + if (len == 2048) buffer[2047] = 0; + iobuffer_write(buffer); + va_end(args); + return len; } -static volatile _Atomic bool readline_started = false; -static volatile _Atomic bool prompt_printed_last = false; - -/** - * Printf wrapper which redraws the readline prompt correctly. - * - * Automatically removes the previous prompt if it's safe to do so, prints the - * result, and redraws the prompt below if the result ended in a newline - * character. - * - * Makes sure that no non-readline text which was output via this function is - * replaced. The thread which is drawing the readline prompt can call `printf` - * safely, as long as it makes sure that the current line was empty when it - * starts the new prompt, i.e. it should end every `printf` call with '\n'. - */ -static int printf_redraw_prompt(const char *format, ...) { - // Print string to buffer +// Direct print callback for use when the when not in "REPL" mode. +static int printf_direct_callback(const char *format, ...) { + va_list args; va_start(args, format); - char *buffer; - int len = vsprintf_allocate(&buffer, format, args); + int len = vprintf(format, args); va_end(args); - if (len < 0) { - return len; - } - -#ifndef LBM_WIN - if (prompt_printed_last) { - rl_clear_visible_line(); - } -#endif - - fputs(buffer, stdout); - prompt_printed_last = false; - - // Redraw prompt if output ends with a newline. - if (len > 0 && buffer[len - 1] == '\n' && readline_started) { -#ifndef LBM_WIN - rl_redraw_prompt_last_line(); -#endif - prompt_printed_last = true; - } - free(buffer); - return len; } + #ifdef LBM_WIN DWORD WINAPI eval_thd_wrapper_win(LPVOID lpParam) { if (!silent_mode) { @@ -424,7 +466,7 @@ DWORD WINAPI eval_thd_wrapper_win(LPVOID lpParam) { } lbm_run_eval(); return 0; -} +} #else void *eval_thd_wrapper(void *v) { if (!silent_mode) { @@ -478,16 +520,17 @@ void done_callback(eval_context_t *ctx) { printf("ALERT: Unable to flatten result value\n"); } } - + // Only print result from contexts directly started by the REPL. - if (drop_ctx(&repl_ctxs, ctx->id)) { + bool dr = drop_reader(ctx->id); + if (!repl_mode || dr) { char output[1024]; lbm_value t = ctx->r; lbm_print_value(output, 1024, t); if (!silent_mode) { - printf_redraw_prompt("> %s\n", output); + printf_callback("> %s\n", output); } else { - printf_redraw_prompt("%s\n", output); + printf_callback("%s\n", output); } } @@ -623,18 +666,6 @@ void sym_it(const char *str) { str); } -#ifndef LBM_WIN -pthread_t lispbm_thd = 0; -#else -HANDLE lispbm_thd; -#endif - -unsigned int heap_size = 2048; // default -lbm_cons_t *heap_storage = NULL; -lbm_heap_state_t heap_state; -lbm_const_heap_t const_heap; - - // OPTIONS #define NO_SHORT_OPT 0x0400 @@ -1008,14 +1039,14 @@ bool load_flat_library(unsigned char *lib, unsigned int size) { int init_repl(void) { if (lispbm_thd && lbm_get_eval_state() != EVAL_CPS_STATE_DEAD) { - + lbm_kill_eval(); #ifdef LBM_WIN WaitForSingleObject(lispbm_thd, INFINITE); #else int thread_r = 0; pthread_join(lispbm_thd, (void*)&thread_r); -#endif +#endif lispbm_thd = 0; } @@ -1051,10 +1082,11 @@ int init_repl(void) { lbm_set_critical_error_callback(critical); lbm_set_ctx_done_callback(done_callback); - lbm_set_timestamp_us_callback(timestamp); lbm_set_usleep_callback(sleep_callback); lbm_set_dynamic_load_callback(dynamic_loader); - lbm_set_printf_callback(printf_redraw_prompt); + lbm_set_printf_callback(printf_direct_callback); + // print directly to stdout until the REPL is running + //Load an image @@ -1089,7 +1121,7 @@ int init_repl(void) { if (!silent_mode) printf("Image initialized!\n"); } - + if (lbm_image_get_version()) { if (!silent_mode) printf("Image version string: %s\n", lbm_image_get_version()); @@ -1130,14 +1162,14 @@ int init_repl(void) { if (!silent_mode) printf("creating eval thread\n"); #ifdef LBM_WIN - lispbm_thd = CreateThread( + lispbm_thd = CreateThread( NULL, // default security attributes 0, // use default stack size eval_thd_wrapper_win, // thread function name NULL, // argument to thread function 0, // use default creation flags NULL); // returns the thread identifier -#else +#else if (pthread_create(&lispbm_thd, NULL, eval_thd_wrapper, NULL)) { printf("Error creating evaluation thread\n"); return 0; @@ -1401,6 +1433,8 @@ int store_env(char *filename) { void shutdown_procedure(void) { + handle_repl_output(); + if (env_output_file) { int r = store_env(env_output_file); if (r != REPL_EXIT_SUCCESS) terminate_repl(r); @@ -1627,10 +1661,9 @@ bool vescif_restart(bool print, bool load_code, bool load_imports) { image_clear(); lbm_image_create("bepa_1"); lbm_image_boot(); - + lbm_set_critical_error_callback(critical); lbm_set_ctx_done_callback(vesc_lbm_done_callback); - lbm_set_timestamp_us_callback(timestamp); lbm_set_usleep_callback(sleep_callback); lbm_set_dynamic_load_callback(dynamic_loader); lbm_set_printf_callback(commands_printf_lisp); @@ -1646,7 +1679,7 @@ bool vescif_restart(bool print, bool load_code, bool load_imports) { if (use_vesc_express_stubs) { load_vesc_express_extensions(); } - + #ifdef WITH_SDL if (!lbm_sdl_init()) { return 0; @@ -1662,7 +1695,7 @@ bool vescif_restart(bool print, bool load_code, bool load_imports) { #endif #ifdef LBM_WIN - lispbm_thd = CreateThread( + lispbm_thd = CreateThread( NULL, // default security attributes 0, // use default stack size eval_thd_wrapper_win, // thread function name @@ -2039,7 +2072,7 @@ void repl_process_cmd(unsigned char *data, unsigned int len, #endif } lbm_prof_init(prof_data, PROF_DATA_NUM); - + #ifdef LBM_WIN prof_thread = CreateThread( NULL, @@ -2447,7 +2480,7 @@ void send_tcp_bytes(unsigned char *buffer, unsigned int len) { #else ssize_t written = write(connected_socket, buffer + ((int)len - to_write), (size_t)to_write); #endif - + if (written < 0) { error_cnt ++; if (error_cnt > SEND_MAX_RETRY) { @@ -2484,7 +2517,7 @@ DWORD WINAPI vesctcp_client_handler(LPVOID lpParam) { strncpy(ip, inet_ntoa(addr.sin_addr), 255); printf("Client %s connected\n",ip); - + vescif_restart(false,false,false); do { @@ -2532,12 +2565,92 @@ void *vesctcp_client_handler(void *arg) { return (void*)0; } #endif +// //////////////////////////////////////////////////////////// +// Readline callback mode +static char *current_line = NULL; +static bool line_ready = false; +void line_handler(char *line) { + if (line) { + current_line = line; + line_ready = true; + size_t n = strlen(line); + HISTORY_STATE *state = history_get_history_state(); + // Don't save history if command is empty or is repeat of last command. + if (n > 0 && !(state->length > 0 && strcmp(state->entries[state->length - 1]->line, line) == 0)) { + add_history(line); + if (history_file_path != NULL) { + int result = append_history(1, history_file_path); + if (result != 0) { + // History file probably doesn't exist yet. + result = write_history(history_file_path); + if (result != 0) { + fprintf( + stderr, + "Couldn't write to history file '%s': %s (%d)\n", + history_file_path, + strerror(result), + result + ); + exit(1); + } + } + } + } + } else { + current_line = NULL; + line_ready = true; + } +} + +static void handle_repl_output(void) { + + // Save current readline state + int saved_point = rl_point; + char *saved_line = rl_copy_text(0, rl_end); + mutex_lock(&iobuffer_mutex); + int num = iobuffer_num(); + mutex_unlock(&iobuffer_mutex); + if (num > 0) { + + // Clear current line and print output to real stdout + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + + iobuffer_print(); + fflush(stdout); + + // Restore readline state + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + + free(saved_line); + } +} // //////////////////////////////////////////////////////////// // int main(int argc, char **argv) { + iobuffer_init(); + + // //////////////////////////////////////////////////////////// + // start timestamp cacher +#ifdef LBM_WIN + timestamp_thread = CreateThread( + NULL, + 0, + timestamp_cacher, + NULL, + 0, + NULL); +#else + pthread_create(×tamp_thread, NULL, timestamp_cacher, NULL); +#endif + #ifdef LBM_WIN LPVOID image_address = VirtualAlloc((LPVOID)IMAGE_FIXED_VIRTUAL_ADDRESS, IMAGE_STORAGE_SIZE, @@ -2548,13 +2661,13 @@ int main(int argc, char **argv) { printf("Image storage successfully allocated at %p\n", image_address); } else { DWORD error = GetLastError(); - printf("VirtualAlloc failed for address %p: Windows error %lu\n", + printf("VirtualAlloc failed for address %p: Windows error %lu\n", IMAGE_FIXED_VIRTUAL_ADDRESS, error); printf("Try running with Administrator privileges or disable Windows ASLR\n"); terminate_repl(REPL_EXIT_CRITICAL_ERROR); } image_storage = (uint32_t *)image_address; -#else +#else image_storage = mmap(IMAGE_FIXED_VIRTUAL_ADDRESS, IMAGE_STORAGE_SIZE, PROT_READ | PROT_WRITE, @@ -2683,8 +2796,7 @@ int main(int argc, char **argv) { WSACleanup(); return 1; } - - + for (;;) { SOCKET client_socket = accept(ListenSocket, NULL, NULL); @@ -2714,7 +2826,6 @@ int main(int argc, char **argv) { vescif_program_flash_code_len = 0; vescif_program_flash=(uint8_t*)malloc(vescif_program_flash_size); if (vescif_program_flash == NULL) return 0; - // Start tcp server struct sockaddr_in server_sockaddr_in; server_sockaddr_in.sin_family = AF_INET; @@ -2755,275 +2866,270 @@ int main(int argc, char **argv) { char output[1024]; + if (silent_mode) { + rl_callback_handler_install("", line_handler); + } else { + rl_callback_handler_install("# ", line_handler); + } + + // REPL interaction starts here. print via the iobuffer. + lbm_set_printf_callback(printf_callback); + while (1) { - char *str; - prompt_printed_last = true; - readline_started = true; - if (silent_mode) { - str = readline(""); - } else { - str = readline("# "); - } - if (str == NULL) terminate_repl(REPL_EXIT_SUCCESS); - size_t n = strlen(str); - - HISTORY_STATE *state = history_get_history_state(); - // Don't save history if command is empty or is repeat of last command. - if (n > 0 && !(state->length > 0 && strcmp(state->entries[state->length - 1]->line, str) == 0)) { - add_history(str); - if (history_file_path != NULL) { - int result = append_history(1, history_file_path); - if (result != 0) { - // History file probably doesn't exist yet. - result = write_history(history_file_path); - if (result != 0) { - fprintf( - stderr, - "Couldn't write to history file '%s': %s (%d)\n", - history_file_path, - strerror(result), - result - ); - exit(1); - } - } - } + repl_mode = true; +#ifdef LBM_WIN + // Windows: Use WaitForSingleObject with console input handle + if (kbhit()) { + rl_callback_read_char(); } +#else + fd_set readfds; + int stdin_fd = fileno(stdin); - if (n >= 5 && strncmp(str, ":info", 5) == 0) { - printf("--(LISP HEAP)-----------------------------------------------\n"); - lbm_get_heap_state(&heap_state); - printf("Heap size: %u Bytes\n", heap_size * 8); - printf("Used cons cells: %"PRI_INT"\n", heap_size - lbm_heap_num_free()); - printf("Free cons cells: %"PRI_INT"\n", lbm_heap_num_free()); - printf("GC counter: %"PRI_INT"\n", heap_state.gc_num); - printf("Recovered: %"PRI_INT"\n", heap_state.gc_recovered); - printf("Recovered arrays: %"PRI_UINT"\n", heap_state.gc_recovered_arrays); - printf("Marked: %"PRI_INT"\n", heap_state.gc_marked); - printf("GC stack size: %"PRI_UINT"\n", lbm_get_gc_stack_size()); - printf("GC SP max: %"PRI_UINT"\n", lbm_get_gc_stack_max()); - printf("Global env cells: %"PRI_UINT"\n", lbm_get_global_env_size()); - printf("--(Symbol and Array memory)---------------------------------\n"); - printf("Memory size: %"PRI_UINT" Words\n", lbm_memory_num_words()); - printf("Memory free: %"PRI_UINT" Words\n", lbm_memory_num_free()); - printf("Maximum usage %f%%\n", 100.0 * ((float)lbm_memory_maximum_used() / (float)lbm_memory_num_words())); - printf("Allocated arrays: %"PRI_UINT"\n", heap_state.num_alloc_arrays); - printf("Symbol table size RAM: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size()); - printf("Symbol names size RAM: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size_names()); - printf("Symbol table size FLASH: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size_flash()); - printf("Symbol names size FLASH: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size_names_flash()); - printf("--(Flash)--\n"); - printf("Size: %"PRI_UINT" words\n", const_heap.size); - printf("Used words: %"PRI_UINT"\n", const_heap.next); - printf("Free words: %"PRI_UINT"\n", const_heap.size - const_heap.next); - printf("image location: %p \n", (void*)image_storage); - free(str); - } else if (strncmp(str, ":prof start", 11) == 0) { - lbm_prof_init(prof_data, - PROF_DATA_NUM); + FD_ZERO(&readfds); + FD_SET(stdin_fd, &readfds); + + struct timeval timeout = {0, 100000}; + int result = select(stdin_fd + 1, &readfds, NULL, NULL, &timeout); + if (result > 0 && FD_ISSET(stdin_fd, &readfds)) { + rl_callback_read_char(); + } +#endif + if (line_ready && current_line) { + char *str = current_line; + if (str == NULL) terminate_repl(REPL_EXIT_SUCCESS); + size_t n = strlen(str); + if (n >= 5 && strncmp(str, ":info", 5) == 0) { + printf("--(LISP HEAP)-----------------------------------------------\n"); + lbm_get_heap_state(&heap_state); + printf("Heap size: %u Bytes\n", heap_size * 8); + printf("Used cons cells: %"PRI_INT"\n", heap_size - lbm_heap_num_free()); + printf("Free cons cells: %"PRI_INT"\n", lbm_heap_num_free()); + printf("GC counter: %"PRI_INT"\n", heap_state.gc_num); + printf("Recovered: %"PRI_INT"\n", heap_state.gc_recovered); + printf("Recovered arrays: %"PRI_UINT"\n", heap_state.gc_recovered_arrays); + printf("Marked: %"PRI_INT"\n", heap_state.gc_marked); + printf("GC stack size: %"PRI_UINT"\n", lbm_get_gc_stack_size()); + printf("GC SP max: %"PRI_UINT"\n", lbm_get_gc_stack_max()); + printf("Global env cells: %"PRI_UINT"\n", lbm_get_global_env_size()); + printf("--(Symbol and Array memory)---------------------------------\n"); + printf("Memory size: %"PRI_UINT" Words\n", lbm_memory_num_words()); + printf("Memory free: %"PRI_UINT" Words\n", lbm_memory_num_free()); + printf("Maximum usage %f%%\n", 100.0 * ((float)lbm_memory_maximum_used() / (float)lbm_memory_num_words())); + printf("Allocated arrays: %"PRI_UINT"\n", heap_state.num_alloc_arrays); + printf("Symbol table size RAM: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size()); + printf("Symbol names size RAM: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size_names()); + printf("Symbol table size FLASH: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size_flash()); + printf("Symbol names size FLASH: %"PRI_UINT" Bytes\n", lbm_get_symbol_table_size_names_flash()); + printf("--(Flash)--\n"); + printf("Size: %"PRI_UINT" words\n", const_heap.size); + printf("Used words: %"PRI_UINT"\n", const_heap.next); + printf("Free words: %"PRI_UINT"\n", const_heap.size - const_heap.next); + printf("image location: %p \n", (void*)image_storage); + } else if (strncmp(str, ":prof start", 11) == 0) { + lbm_prof_init(prof_data, + PROF_DATA_NUM); #ifndef LBM_WIN - pthread_t thd; // just forget this id. - prof_running = true; - if (pthread_create(&thd, NULL, prof_thd, NULL)) { - printf("Error creating profiler thread\n"); - free(str); - continue; - } - printf("Profiler started\n"); + pthread_t thd; // just forget this id. + prof_running = true; + if (pthread_create(&thd, NULL, prof_thd, NULL)) { + printf("Error creating profiler thread\n"); + goto repl_next_iteration; + } + printf("Profiler started\n"); #else - printf("Profiler not supported on windows\n"); + printf("Profiler not supported on windows\n"); #endif - free(str); - } else if (strncmp(str, ":prof stop", 10) == 0) { - prof_running = false; - printf("Profiler stopped. Issue command ':prof report' for statistics\n."); - free(str); - } else if (strncmp(str, ":prof report", 12) == 0) { - lbm_uint num_sleep = lbm_prof_get_num_sleep_samples(); - lbm_uint num_system = lbm_prof_get_num_system_samples(); - lbm_uint tot_samples = lbm_prof_get_num_samples(); - lbm_uint tot_gc = 0; - printf("CID\tName\tSamples\t%%Load\t%%GC\n"); - for (int i = 0; i < PROF_DATA_NUM; i ++) { - if (prof_data[i].cid == -1) break; - tot_gc += prof_data[i].gc_count; - printf("%"PRI_VALUE"\t%s\t%"PRI_UINT"\t%f\t%f\n", - prof_data[i].cid, - prof_data[i].name, - prof_data[i].count, - 100.0 * ((float)prof_data[i].count) / (float) tot_samples, - 100.0 * ((float)prof_data[i].gc_count) / (float)prof_data[i].count); - } - printf("\n"); - printf("GC:\t%"PRI_UINT"\t%f%%\n", tot_gc, 100.0 * ((float)tot_gc / (float)tot_samples)); - printf("System:\t%"PRI_UINT"\t%f%%\n", num_system, 100.0 * ((float)num_system / (float)tot_samples)); - printf("Sleep:\t%"PRI_UINT"\t%f%%\n", num_sleep, 100.0 * ((float)num_sleep / (float)tot_samples)); - printf("Total:\t%"PRI_UINT" samples\n", tot_samples); - free(str); - } else if (strncmp(str, ":env", 4) == 0) { - for (int i = 0; i < GLOBAL_ENV_ROOTS; i ++) { - lbm_value *env = lbm_get_global_env(); - lbm_value curr = env[i]; - printf("Environment [%d]:\r\n", i); - while (lbm_type_of(curr) == LBM_TYPE_CONS) { - lbm_print_value(output,1024, lbm_car(curr)); - curr = lbm_cdr(curr); - printf(" %s\r\n",output); + } else if (strncmp(str, ":prof stop", 10) == 0) { + prof_running = false; + printf("Profiler stopped. Issue command ':prof report' for statistics\n."); + } else if (strncmp(str, ":prof report", 12) == 0) { + lbm_uint num_sleep = lbm_prof_get_num_sleep_samples(); + lbm_uint num_system = lbm_prof_get_num_system_samples(); + lbm_uint tot_samples = lbm_prof_get_num_samples(); + lbm_uint tot_gc = 0; + printf("CID\tName\tSamples\t%%Load\t%%GC\n"); + for (int i = 0; i < PROF_DATA_NUM; i ++) { + if (prof_data[i].cid == -1) break; + tot_gc += prof_data[i].gc_count; + printf("%"PRI_VALUE"\t%s\t%"PRI_UINT"\t%f\t%f\n", + prof_data[i].cid, + prof_data[i].name, + prof_data[i].count, + 100.0 * ((float)prof_data[i].count) / (float) tot_samples, + 100.0 * ((float)prof_data[i].gc_count) / (float)prof_data[i].count); } - } - free(str); - } else if (strncmp(str, ":state", 6) == 0) { - switch (lbm_get_eval_state()) { - case EVAL_CPS_STATE_DEAD: - printf("DEAD\n"); - break; - case EVAL_CPS_STATE_PAUSED: - printf("PAUSED\n"); - break; - case EVAL_CPS_STATE_NONE: - printf("NO STATE\n"); - break; - case EVAL_CPS_STATE_RUNNING: - printf("RUNNING\n"); - break; - case EVAL_CPS_STATE_KILL: - printf("KILLING\n"); - break; - } - free(str); - } - else if (n >= 5 && strncmp(str, ":load", 5) == 0) { - - char *file_str = load_file(&str[5]); - if (file_str) { - lbm_create_string_char_channel(&string_tok_state, - &string_tok, - file_str); - - /* Get exclusive access to the heap */ - lbm_pause_eval_with_gc(50); - while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { - sleep_callback(10); + printf("\n"); + printf("GC:\t%"PRI_UINT"\t%f%%\n", tot_gc, 100.0 * ((float)tot_gc / (float)tot_samples)); + printf("System:\t%"PRI_UINT"\t%f%%\n", num_system, 100.0 * ((float)num_system / (float)tot_samples)); + printf("Sleep:\t%"PRI_UINT"\t%f%%\n", num_sleep, 100.0 * ((float)num_sleep / (float)tot_samples)); + printf("Total:\t%"PRI_UINT" samples\n", tot_samples); + } else if (strncmp(str, ":env", 4) == 0) { + for (int i = 0; i < GLOBAL_ENV_ROOTS; i ++) { + lbm_value *env = lbm_get_global_env(); + lbm_value curr = env[i]; + printf("Environment [%d]:\r\n", i); + while (lbm_type_of(curr) == LBM_TYPE_CONS) { + lbm_print_value(output,1024, lbm_car(curr)); + curr = lbm_cdr(curr); + printf(" %s\r\n",output); + } } + } else if (strncmp(str, ":state", 6) == 0) { + switch (lbm_get_eval_state()) { + case EVAL_CPS_STATE_DEAD: + printf("DEAD\n"); + break; + case EVAL_CPS_STATE_PAUSED: + printf("PAUSED\n"); + break; + case EVAL_CPS_STATE_NONE: + printf("NO STATE\n"); + break; + case EVAL_CPS_STATE_RUNNING: + printf("RUNNING\n"); + break; + case EVAL_CPS_STATE_KILL: + printf("KILLING\n"); + break; + } + } else if (n >= 5 && strncmp(str, ":load", 5) == 0) { + + char *file_str = load_file(&str[5]); + if (file_str) { + lbm_create_string_char_channel(&string_tok_state, + &string_tok, + file_str); + + /* Get exclusive access to the heap */ + lbm_pause_eval_with_gc(50); + while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { + sleep_callback(10); + } - (void)lbm_load_and_eval_program_incremental(&string_tok, NULL); - lbm_continue_eval(); + lbm_cid loader = lbm_load_and_eval_program_incremental(&string_tok, NULL); + lbm_continue_eval(); - //printf("started ctx: %"PRI_UINT"\n", cid); - // TODO: Should free the file_str at some point!! - // but it is hard to figure out when to do that if loading incrementally. - } else { - printf("Error loading file: %s\n",&str[5]); - } - free(str); - } else if (n >= 5 && strncmp(str, ":verb", 5) == 0) { - lbm_toggle_verbose(); - free(str); - continue; - } else if (n >= 4 && strncmp(str, ":pon", 4) == 0) { - set_allow_print(true); - free(str); - continue; - } else if (n >= 5 && strncmp(str, ":poff", 5) == 0) { - set_allow_print(false); - free(str); - continue; - } else if (strncmp(str, ":ctxs", 5) == 0) { - printf("****** Running contexts ******\n"); - lbm_running_iterator(print_ctx_info, NULL, NULL); - printf("****** Blocked contexts ******\n"); - lbm_blocked_iterator(print_ctx_info, NULL, NULL); - free(str); - } else if (n >= 5 && strncmp(str, ":quit", 5) == 0) { - shutdown_procedure(); - free(str); - break; - } else if (strncmp(str, ":symbols", 8) == 0) { - lbm_symrepr_name_iterator(sym_it); - free(str); - } else if (strncmp(str, ":heap", 5) == 0) { - int size = atoi(str + 5); - if (size > 0) { - heap_size = (unsigned int)size; + if (loader < 0) { + printf("Error starting loader thread\n"); + } + + //printf("started ctx: %"PRI_UINT"\n", cid); + // TODO: Should free the file_str at some point!! + // but it is hard to figure out when to do that if loading incrementally. + } else { + printf("Error loading file: %s\n",&str[5]); + } + } else if (n >= 5 && strncmp(str, ":verb", 5) == 0) { + lbm_toggle_verbose(); + } else if (n >= 4 && strncmp(str, ":pon", 4) == 0) { + set_allow_print(true); + } else if (n >= 5 && strncmp(str, ":poff", 5) == 0) { + set_allow_print(false); + } else if (strncmp(str, ":ctxs", 5) == 0) { + printf("****** Running contexts ******\n"); + lbm_running_iterator(print_ctx_info, NULL, NULL); + printf("****** Blocked contexts ******\n"); + lbm_blocked_iterator(print_ctx_info, NULL, NULL); + } else if (n >= 5 && strncmp(str, ":quit", 5) == 0) { + shutdown_procedure(); + goto repl_cleanup_and_exit; + } else if (strncmp(str, ":symbols", 8) == 0) { + lbm_symrepr_name_iterator(sym_it); + } else if (strncmp(str, ":heap", 5) == 0) { + int size = atoi(str + 5); + if (size > 0) { + heap_size = (unsigned int)size; + if (!init_repl()) { + printf("Failed to initialize REPL after heap resize\n"); + terminate_repl(REPL_EXIT_UNABLE_TO_INIT_LBM); + } + } + } else if (strncmp(str, ":reset", 6) == 0) { if (!init_repl()) { - printf("Failed to initialize REPL after heap resize\n"); + printf ("Failed to initialize REPL\n"); terminate_repl(REPL_EXIT_UNABLE_TO_INIT_LBM); } - } - free(str); - } else if (strncmp(str, ":reset", 6) == 0) { - if (!init_repl()) { - printf ("Failed to initialize REPL\n"); - terminate_repl(REPL_EXIT_UNABLE_TO_INIT_LBM); - } - free(str); - } else if (strncmp(str, ":send", 5) == 0) { - int id; - int i_val; + } else if (strncmp(str, ":send", 5) == 0) { + int id; + int i_val; + + if (sscanf(str + 5, "%d%d", &id, &i_val) == 2) { + lbm_pause_eval_with_gc(50); + while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { + sleep_callback(10); + } - if (sscanf(str + 5, "%d%d", &id, &i_val) == 2) { - lbm_pause_eval_with_gc(50); + if (lbm_send_message((lbm_cid)id, lbm_enc_i(i_val)) == 0) { + printf("Could not send message\n"); + } + + lbm_continue_eval(); + } else { + printf("Incorrect arguments to send\n"); + } + } else if (strncmp(str, ":pause", 6) == 0) { + lbm_pause_eval_with_gc(30); while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { sleep_callback(10); } + printf("Evaluator paused\n"); + } else if (strncmp(str, ":continue", 9) == 0) { + lbm_continue_eval(); + } else if (strncmp(str, ":inspect", 8) == 0) { - if (lbm_send_message((lbm_cid)id, lbm_enc_i(i_val)) == 0) { - printf("Could not send message\n"); + int i = 8; + if (strlen(str) >= 8) { + while (str[i] == ' ') i++; } - + char *sym = str + i; + lbm_uint sym_id = 0; + if (lbm_get_symbol_by_name(sym, &sym_id)) { + lbm_all_ctxs_iterator(lookup_local, (void*)lbm_enc_sym(sym_id), (void*)sym); + } else { + printf("symbol does not exist\n"); + } + } else if (strncmp(str, ":undef", 6) == 0) { + lbm_pause_eval_with_gc(50); + while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { + sleep_callback(10); + } + char *sym = str + 7; + printf("undefining: %s\n", sym); + printf("%s\n", lbm_undefine(sym) ? "Cleared bindings" : "No definition found"); lbm_continue_eval(); - } else { - printf("Incorrect arguments to send\n"); - } - free(str); - } else if (strncmp(str, ":pause", 6) == 0) { - lbm_pause_eval_with_gc(30); - while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { - sleep_callback(10); - } - printf("Evaluator paused\n"); - free(str); - } else if (strncmp(str, ":continue", 9) == 0) { - lbm_continue_eval(); - free(str); - } else if (strncmp(str, ":inspect", 8) == 0) { + } else { // The read an expression case! + /* Get exclusive access to the heap */ + size_t len = strlen(str)+1; + char *buffer = malloc(len); + if (buffer) { + memcpy(buffer, str, len); + lbm_pause_eval_with_gc(50); + while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { + sleep_callback(10); + } + lbm_create_string_char_channel(&string_tok_state, + &string_tok, + buffer); + lbm_cid cid = lbm_load_and_eval_expression(&string_tok); + add_reader(buffer, cid); + lbm_continue_eval(); + } else { + printf("Error allocating reader buffer.\n"); + goto repl_cleanup_and_exit; - int i = 8; - if (strlen(str) >= 8) { - while (str[i] == ' ') i++; - } - char *sym = str + i; - lbm_uint sym_id = 0; - if (lbm_get_symbol_by_name(sym, &sym_id)) { - lbm_all_ctxs_iterator(lookup_local, (void*)lbm_enc_sym(sym_id), (void*)sym); - } else { - printf("symbol does not exist\n"); - } - } else if (strncmp(str, ":undef", 6) == 0) { - lbm_pause_eval_with_gc(50); - while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { - sleep_callback(10); - } - char *sym = str + 7; - printf("undefining: %s\n", sym); - printf("%s\n", lbm_undefine(sym) ? "Cleared bindings" : "No definition found"); - lbm_continue_eval(); - free(str); - } else { - /* Get exclusive access to the heap */ - lbm_pause_eval_with_gc(50); - while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) { - sleep_callback(10); + } } - lbm_create_string_char_channel(&string_tok_state, - &string_tok, - str); - lbm_cid cid = lbm_load_and_eval_expression(&string_tok); - add_ctx(&repl_ctxs, cid); - lbm_continue_eval(); + repl_next_iteration: + line_ready = false; + free(current_line); + current_line = NULL; + str = NULL; //(same as current line) } + handle_repl_output(); } } - free(heap_storage); + + repl_cleanup_and_exit: terminate_repl(REPL_EXIT_SUCCESS); } diff --git a/lispBM/lispBM/repl/repl_exts.c b/lispBM/lispBM/repl/repl_exts.c index 45b64a0985..de158ff454 100644 --- a/lispBM/lispBM/repl/repl_exts.c +++ b/lispBM/lispBM/repl/repl_exts.c @@ -21,6 +21,7 @@ #include #include #include +#include #ifndef LBM_WIN #include @@ -41,6 +42,7 @@ #include "eval_cps.h" #include "lbm_image.h" #include "lbm_flat_value.h" +#include "platform_timestamp.h" #include @@ -156,12 +158,7 @@ static lbm_value ext_bits_dec_int(lbm_value *args, lbm_uint argn) { // TIME - -uint32_t timestamp(void) { - struct timeval tv; - gettimeofday(&tv,NULL); - return (uint32_t)(tv.tv_sec * 1000000 + tv.tv_usec); -} +extern void sleep_callback(uint32_t us); static lbm_value ext_systime(lbm_value *args, lbm_uint argn) { @@ -293,18 +290,24 @@ static lbm_value ext_load_file(lbm_value *args, lbm_uint argn) { rewind(h->fp); if (size > 0) { - uint8_t *data = lbm_malloc((size_t)size); + uint8_t *data = lbm_malloc((size_t)size+1); if (data) { + memset(data, 0, (unsigned int)size+1) ; lbm_value val; - lbm_lift_array(&val, (char*)data, (lbm_uint)size); - if (!lbm_is_symbol(val)) { - size_t n = fread(data, 1, (size_t)size, h->fp); - if ( n > 0) { - res = val; - } else { - res = ENC_SYM_NIL; // or some empty indicator? + if (lbm_lift_array(&val, (char*)data, (lbm_uint)size+1)) { + if (!lbm_is_symbol(val)) { + size_t n = fread(data, 1, (size_t)size, h->fp); + if ( n > 0) { + res = val; + } else { + lbm_free(data); + res = ENC_SYM_NIL; // or some empty indicator? + } } + } else { + lbm_free(data); + res = ENC_SYM_MERROR; } } else { res = ENC_SYM_MERROR; diff --git a/lispBM/lispBM/repl/repl_exts.h b/lispBM/lispBM/repl/repl_exts.h index 5f42c013fb..5b2ee60ce4 100644 --- a/lispBM/lispBM/repl/repl_exts.h +++ b/lispBM/lispBM/repl/repl_exts.h @@ -24,7 +24,6 @@ #include "extensions/math_extensions.h" #include "extensions/runtime_extensions.h" -uint32_t timestamp(void); int init_exts(void); diff --git a/lispBM/lispBM/repl/vesc_express_extension_stubs.c b/lispBM/lispBM/repl/vesc_express_extension_stubs.c index 3c4d09b6c3..26395c2974 100644 --- a/lispBM/lispBM/repl/vesc_express_extension_stubs.c +++ b/lispBM/lispBM/repl/vesc_express_extension_stubs.c @@ -3,948 +3,1326 @@ // Function stubs: static lbm_value ext_print(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_print - return lbm_enc_sym(SYM_EERROR); + (void) args; + (void) argn; + // TODO: Implement ext_print + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_print_prefix(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_print_prefix - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_print_prefix + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_fw_name(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_fw_name - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_fw_name + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_puts(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_puts - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_puts + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_bms_val(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_bms_val - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_bms_val + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_bms_val(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_bms_val - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_bms_val + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_send_bms_can(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_send_bms_can - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_send_bms_can + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_bms_chg_allowed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_bms_chg_allowed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_bms_chg_allowed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bms_force_balance(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bms_force_balance - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bms_force_balance + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bms_zero_offset(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bms_zero_offset - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bms_zero_offset + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_get(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_get - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_get + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_set(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_set - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_set + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_conf_store(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_conf_store - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_conf_store + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_reboot(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_reboot - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_reboot + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_adc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_adc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_adc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_systime(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_systime - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_systime + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_secs_since(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_secs_since - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_secs_since + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_send_data(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_send_data - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_send_data + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_recv_data(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_recv_data - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_recv_data + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_store_f(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_store_f - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_store_f + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_read_f(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_read_f - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_read_f + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_store_i(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_store_i - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_store_i + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_read_i(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_read_i - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_read_i + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_eeprom_erase(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_eeprom_erase - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_eeprom_erase + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_sysinfo(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_sysinfo - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_sysinfo + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_cmd(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_cmd - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_cmd + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_msg_age(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_msg_age - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_msg_age + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_current_dir(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_current_dir - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_current_dir + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_current_in(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_current_in - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_current_in + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_rpm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_rpm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_rpm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_temp_fet(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_temp_fet - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_temp_fet + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_temp_motor(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_temp_motor - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_temp_motor + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_speed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_speed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_speed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_dist(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_dist - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_dist + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_ppm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_ppm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_ppm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_adc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_adc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_adc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_get_vin(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_get_vin - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_get_vin + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_list_devs(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_list_devs - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_list_devs + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_local_id(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_local_id - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_local_id + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_update_baud(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_update_baud - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_update_baud + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_use_vesc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_use_vesc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_use_vesc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_scan(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_scan - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_scan + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_ping(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_ping - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_ping + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_send_sid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_send_sid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_send_sid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_send_eid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_send_eid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_send_eid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_recv_sid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_recv_sid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_recv_sid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_recv_eid(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_recv_eid - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_recv_eid + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_current(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_current - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_current + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_current_rel(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_current_rel - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_current_rel + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_brake(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_brake - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_brake + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_brake_rel(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_brake_rel - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_brake_rel + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_rpm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_rpm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_rpm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_can_pos(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_can_pos - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_can_pos + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_throttle_curve(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_throttle_curve - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_throttle_curve + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_rand(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_rand - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_rand + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_rand_max(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_rand_max - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_rand_max + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bits_enc_int(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bits_enc_int - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bits_enc_int + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bits_dec_int(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bits_dec_int - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bits_dec_int + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_enable_event(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_enable_event - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_enable_event + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_lbm_set_quota(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_lbm_set_quota - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_lbm_set_quota + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_lbm_set_gc_stack_size(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_lbm_set_gc_stack_size - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_lbm_set_gc_stack_size + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_init(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_init - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_init + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_add_graph(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_add_graph - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_add_graph + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_set_graph(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_set_graph - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_set_graph + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_plot_send_points(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_plot_send_points - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_plot_send_points + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_get_adc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_get_adc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_get_adc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_get_digital(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_get_digital - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_get_digital + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_set_digital(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_set_digital - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_set_digital + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ioboard_set_pwm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ioboard_set_pwm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ioboard_set_pwm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_esp_now_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_esp_now_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_esp_now_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_esp_now_add_peer(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_esp_now_add_peer - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_esp_now_add_peer + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_esp_now_del_peer(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_esp_now_del_peer - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_esp_now_del_peer + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_mac_addr(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_mac_addr - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_mac_addr + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_wifi_set_chan(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_wifi_set_chan - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_wifi_set_chan + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_wifi_get_chan(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_wifi_get_chan - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_wifi_get_chan + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_wifi_set_bw(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_wifi_set_bw - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_wifi_set_bw + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_wifi_get_bw(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_wifi_get_bw - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_wifi_get_bw + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_wifi_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_wifi_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_wifi_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_wifi_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_wifi_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_wifi_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_esp_now_send(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_esp_now_send - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_esp_now_send + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_esp_now_recv(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_esp_now_recv - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_esp_now_recv + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_i2c_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_i2c_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_i2c_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_i2c_tx_rx(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_i2c_tx_rx - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_i2c_tx_rx + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_i2c_detect_addr(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_i2c_detect_addr - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_i2c_detect_addr + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_configure(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_configure - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_configure + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_hold(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_hold - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_hold + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_hold_deepsleep(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_hold_deepsleep - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_hold_deepsleep + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gpio_read(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gpio_read - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gpio_read + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_main_init_done(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_main_init_done - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_main_init_done + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_crc16(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_crc16 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_crc16 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_crc32(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_crc32 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_crc32 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_buf_resize - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_buf_resize + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_config_field(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_config_field - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_config_field + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_send_f32(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_send_f32 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_send_f32 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_log_send_f64(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_log_send_f64 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_log_send_f64 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_lat_lon(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_lat_lon - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_lat_lon + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_height(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_height - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_height + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_speed(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_speed - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_speed + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_hdop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_hdop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_hdop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_date_time(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_date_time - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_date_time + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_gnss_age(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_gnss_age - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_gnss_age + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_ublox_init(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_ublox_init - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_ublox_init + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nmea_parse(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nmea_parse - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nmea_parse + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_set_pos_time(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_set_pos_time - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_set_pos_time + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_sleep_deep(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_sleep_deep - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_sleep_deep + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_sleep_light(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_sleep_light - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_sleep_light + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_sleep_config_wakeup_pin(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_sleep_config_wakeup_pin - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_sleep_config_wakeup_pin + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_rtc_data(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_rtc_data - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_rtc_data + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_empty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_empty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_empty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_canmsg_recv(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_canmsg_recv - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_canmsg_recv + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_canmsg_send(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_canmsg_send - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_canmsg_send + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_connect(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_connect - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_connect + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_connect_nand(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_connect_nand - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_connect_nand + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_disconnect(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_disconnect - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_disconnect + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_open(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_open - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_open + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_close(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_close - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_close + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_read(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_read - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_read + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_readline(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_readline - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_readline + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_tell(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_tell - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_tell + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_seek(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_seek - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_seek + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_mkdir(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_mkdir - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_mkdir + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_rm(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_rm - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_rm + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_ls(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_ls - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_ls + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_size(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_size - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_size + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_rename(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_rename - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_rename + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_sync(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_sync - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_sync + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_f_fatinfo(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_f_fatinfo - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_f_fatinfo + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_fw_erase(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_fw_erase - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_fw_erase + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_fw_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_fw_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_fw_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_fw_reboot(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_fw_reboot - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_fw_reboot + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_lbm_erase(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_lbm_erase - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_lbm_erase + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_qml_erase(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_qml_erase - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_qml_erase + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_lbm_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_lbm_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_lbm_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_qml_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_qml_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_qml_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_fw_data(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_fw_data - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_fw_data + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_fw_write_raw(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_fw_write_raw - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_fw_write_raw + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_fw_info(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_fw_info - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_fw_info + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_lbm_run(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_lbm_run - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_lbm_run + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_bms_st(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_bms_st - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_bms_st + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_as504x_init(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_as504x_init - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_as504x_init + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_as504x_deinit(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_as504x_deinit - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_as504x_deinit + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_as504x_angle(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_as504x_angle - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_as504x_angle + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_imu_start_lsm6(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_imu_start_lsm6 - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_imu_start_lsm6 + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_imu_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_imu_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_imu_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_rpy(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_rpy - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_rpy + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_quat(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_quat - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_quat + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_acc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_acc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_acc + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_gyro(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_gyro - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_gyro + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_mag(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_mag - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_mag + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_acc_derot(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_acc_derot - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_acc_derot + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_get_imu_gyro_derot(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_get_imu_gyro_derot - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_get_imu_gyro_derot + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uart_read(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uart_read - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uart_read + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uartcomm_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uartcomm_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uartcomm_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_uartcomm_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_uartcomm_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_uartcomm_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pwm_start(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pwm_start - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pwm_start + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pwm_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pwm_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pwm_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_pwm_set_duty(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_pwm_set_duty - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_pwm_set_duty + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_unzip(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_unzip - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_unzip + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_zip_ls(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_zip_ls - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_zip_ls + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_connected_wifi(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_connected_wifi - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_connected_wifi + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_connected_hub(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_connected_hub - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_connected_hub + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_connected_ble(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_connected_ble - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_connected_ble + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_connected_usb(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_connected_usb - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_connected_usb + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_aes_ctr_crypt(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_aes_ctr_crypt - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_aes_ctr_crypt + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_qml_erase_partition(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_qml_erase_partition - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_qml_erase_partition + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_qml_init(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_qml_init - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_qml_init + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_read(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_read - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_read + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_qml_read(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_qml_read - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_qml_read + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_qml_write(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_qml_write - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_qml_write + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_qml_erase_key(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_qml_erase_key - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_qml_erase_key + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_erase(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_erase - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_erase + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_image_save(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_image_save - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_image_save + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_qml_list(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_qml_list - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_qml_list + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_nvs_list(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_nvs_list - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_nvs_list + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_cmds_start_stop(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_cmds_start_stop - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_cmds_start_stop + return lbm_enc_sym(SYM_EERROR); } static lbm_value ext_cmds_proc(lbm_value *args, lbm_uint argn) { - // TODO: Implement ext_cmds_proc - return lbm_enc_sym(SYM_EERROR); + (void)args; + (void)argn; + // TODO: Implement ext_cmds_proc + return lbm_enc_sym(SYM_EERROR); } // Extension registration function: diff --git a/lispBM/lispBM/src/eval_cps.c b/lispBM/lispBM/src/eval_cps.c index 82c14fb994..8390f43513 100644 --- a/lispBM/lispBM/src/eval_cps.c +++ b/lispBM/lispBM/src/eval_cps.c @@ -16,6 +16,48 @@ along with this program. If not, see . */ +/* + eval_cps uses setjmp/longjmp for error handling. + + setjmp/longjmp behavior is undefined: + * If the function which called setjmp() returns before longjmp() is + called, the behavior is undefined. Some kind of subtle or unsubtle + chaos is sure to result. + + * If, in a multithreaded program, a longjmp() call employs an env buffer + that was initialized by a call to setjmp() in a different thread, the + behavior is undefined. + + As I understand it MISRA C guidelines prohibit (quite completely) any use + of setjmp/longjmp for safety-critical applications. + + The LispBM eval_cps evaluator is careful to not fall into either of the + undefined behavior situations by: + 1. setjmp is called in the lbm_run_eval() function which is responsible + for running all evaluation. + 2. longjmp is called as part of the ERROR_CTX/ERROR_AT_CTX macros which + are executed by the evaluator in error cases. + 3. the jump buffers are static (error_jmp_buf, critical_error_jmp_buf). + 4. The error_ctx/error_at_ctx functions are static. + 5. The ERROR_CTX/ERROR_AT_CTX/READ_ERROR_CTX macros are only called in + static functions. + TODO Check static functions that call ERROR_CTX are not called by any + non-static function, The only call-chain that leads to a longjmp must + originate in lbm_run_eval(). + => (if the TODO is dealt with) it is impossible to trigger the undefined + conditions. + + Possible alternative to setjmp/longjmp is to cram all of the stuff + that eval_cps does into a single function and use GOTO to jump between the + different continuation and evaluation and error cases. This would be even + worse from a "structured programming" viewpoint, but it would also possibly + be a bit a faster. + + The setjmp/longjmp error handling applied here is well contained and has + been rigorously tested over time. There is a bit more to do in terms of + documenting the error handling choices and it would also be nice to statically + check/verify that we are ruling out the undefined use cases. +*/ #include #include #include "symrepr.h" @@ -29,6 +71,7 @@ #include "lbm_channel.h" #include "print.h" #include "platform_mutex.h" +#include "platform_timestamp.h" #include "lbm_flat_value.h" #include @@ -292,10 +335,6 @@ static bool dynamic_load_nonsense(const char *sym, const char **code) { return false; } -static uint32_t timestamp_nonsense(void) { - return 0; -} - static int printf_nonsense(const char *fmt, ...) { (void) fmt; return 0; @@ -311,7 +350,6 @@ static void critical_nonsense(void) { static void (*critical_error_callback)(void) = critical_nonsense; static void (*usleep_callback)(uint32_t) = usleep_nonsense; -static uint32_t (*timestamp_us_callback)(void) = timestamp_nonsense; static void (*ctx_done_callback)(eval_context_t *) = ctx_done_nonsense; int (*lbm_printf_callback)(const char *, ...) = printf_nonsense; static bool (*dynamic_load_callback)(const char *, const char **) = dynamic_load_nonsense; @@ -326,11 +364,6 @@ void lbm_set_usleep_callback(void (*fptr)(uint32_t)) { else usleep_callback = fptr; } -void lbm_set_timestamp_us_callback(uint32_t (*fptr)(void)) { - if (fptr == NULL) timestamp_us_callback = timestamp_nonsense; - else timestamp_us_callback = fptr; -} - void lbm_set_ctx_done_callback(void (*fptr)(eval_context_t *)) { if (fptr == NULL) ctx_done_callback = ctx_done_nonsense; else ctx_done_callback = fptr; @@ -410,10 +443,9 @@ bool lbm_event_unboxed(lbm_value unboxed) { t == LBM_TYPE_U || t == LBM_TYPE_CHAR) { if (lbm_event_handler_pid > 0) { - if (lbm_mailbox_free_space_for_cid(lbm_event_handler_pid) <= lbm_event_queue_item_count()) { - return false; + if (lbm_mailbox_free_space_for_cid(lbm_event_handler_pid) > lbm_event_queue_item_count()) { + return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)unboxed, 0); } - return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)unboxed, 0); } } return false; @@ -421,25 +453,24 @@ bool lbm_event_unboxed(lbm_value unboxed) { bool lbm_event(lbm_flat_value_t *fv) { if (lbm_event_handler_pid > 0) { - if (lbm_mailbox_free_space_for_cid(lbm_event_handler_pid) <= lbm_event_queue_item_count()) { - return false; + if (lbm_mailbox_free_space_for_cid(lbm_event_handler_pid) > lbm_event_queue_item_count()) { + return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)fv->buf, fv->buf_size); } - return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)fv->buf, fv->buf_size); } return false; } static bool lbm_event_pop(lbm_event_t *event) { mutex_lock(&lbm_events_mutex); - if (lbm_events_head == lbm_events_tail && !lbm_events_full) { - mutex_unlock(&lbm_events_mutex); - return false; + bool r = false; + if (lbm_events_head != lbm_events_tail || lbm_events_full) { + *event = lbm_events[lbm_events_tail]; + lbm_events_tail = (lbm_events_tail + 1) % lbm_events_max; + lbm_events_full = false; + r = true; } - *event = lbm_events[lbm_events_tail]; - lbm_events_tail = (lbm_events_tail + 1) % lbm_events_max; - lbm_events_full = false; mutex_unlock(&lbm_events_mutex); - return true; + return r; } bool lbm_event_queue_is_empty(void) { @@ -478,10 +509,10 @@ void lbm_set_hide_trapped_error(bool hide) { } lbm_cid lbm_get_current_cid(void) { + lbm_cid cid = -1; if (ctx_running) - return ctx_running->id; - else - return -1; + cid = ctx_running->id; + return cid; } eval_context_t *lbm_get_current_context(void) { @@ -755,7 +786,7 @@ static void atomic_error(void) { // Blocking while in an atomic block would have bad consequences. static void block_current_ctx(uint32_t state, lbm_uint sleep_us, bool do_cont) { if (is_atomic) atomic_error(); - ctx_running->timestamp = timestamp_us_callback(); + ctx_running->timestamp = timestamp(); ctx_running->sleep_us = sleep_us; ctx_running->state = state; ctx_running->app_cont = do_cont; @@ -1228,13 +1259,7 @@ static eval_context_t *dequeue_ctx_nm(eval_context_queue_t *q) { static void wake_up_ctxs_nm(void) { lbm_uint t_now; - - if (timestamp_us_callback) { - t_now = timestamp_us_callback(); - } else { - t_now = 0; - } - + t_now = timestamp(); eval_context_queue_t *q = &blocked; eval_context_t *curr = q->first; @@ -1288,15 +1313,9 @@ static void wake_up_ctxs_nm(void) { static void yield_ctx(lbm_uint sleep_us) { if (is_atomic) atomic_error(); - if (timestamp_us_callback) { - ctx_running->timestamp = timestamp_us_callback(); - ctx_running->sleep_us = sleep_us; - ctx_running->state = LBM_THREAD_STATE_SLEEPING; - } else { - ctx_running->timestamp = 0; - ctx_running->sleep_us = 0; - ctx_running->state = LBM_THREAD_STATE_SLEEPING; - } + ctx_running->timestamp = timestamp(); + ctx_running->sleep_us = sleep_us; + ctx_running->state = LBM_THREAD_STATE_SLEEPING; ctx_running->r = ENC_SYM_TRUE; ctx_running->app_cont = true; enqueue_ctx(&blocked,ctx_running); @@ -2519,10 +2538,10 @@ static void cont_wait(eval_context_t *ctx) { /** * @brief Setup application of cont object (created by call-cc) - * + * * The "function" form, e.g. `(SYM_CONT . cont-array)`, is expected to be stored * in `ctx->r`. - * + * * @param args List of the arguments to apply with. * @return lbm_value The resulting argument value which should either be * evaluated or passed on directly depending on how you use this. @@ -2536,7 +2555,7 @@ static lbm_value setup_cont(eval_context_t *ctx, lbm_value args) { if (!lbm_is_lisp_array_r(c)) { ERROR_CTX(ENC_SYM_FATAL_ERROR); } - + lbm_value arg; lbm_uint arg_count = lbm_list_length(args); switch (arg_count) { @@ -2559,16 +2578,16 @@ static lbm_value setup_cont(eval_context_t *ctx, lbm_value args) { lbm_value atomic = ctx->K.data[--ctx->K.sp]; is_atomic = atomic ? 1 : 0; - + return arg; } /** * @brief Setup application of cont sp object (created by call-cc-unsafe) - * + * * The "function" form, e.g. `(SYM_CONT_SP . stack_ptr)` is expected to be * stored in `ctx->r`. - * + * * @param args List of the arguments to apply with. * @return lbm_value The resulting argument value which should either be * evaluated or passed on directly depending on how you use this. @@ -2598,7 +2617,7 @@ static lbm_value setup_cont_sp(eval_context_t *ctx, lbm_value args) { lbm_set_error_reason(lbm_error_str_num_args); ERROR_CTX(ENC_SYM_EERROR); } - + if (sp > 0 && sp <= ctx->K.sp && IS_CONTINUATION(ctx->K.data[sp-1])) { is_atomic = atomic ? 1 : 0; // works fine with nil/true ctx->K.sp = sp; @@ -2610,13 +2629,13 @@ static lbm_value setup_cont_sp(eval_context_t *ctx, lbm_value args) { /** * @brief Setup application of macro - * + * * The macro form, e.g. `(macro (...) ...)`, is expected to be stored in * `ctx->r`. - * + * * @param args List of the arguments to apply the macro with. * @param curr_env The environment to re-evaluate the result of the macro - * experssion in. + * experssion in. */ static inline __attribute__ ((always_inline)) void setup_macro(eval_context_t *ctx, lbm_value args, lbm_value curr_env) { /* @@ -2651,11 +2670,17 @@ static inline __attribute__ ((always_inline)) void setup_macro(eval_context_t *c curr_param = cdr_curr_param; curr_arg = cdr_curr_arg; } +#ifdef LBM_USE_MACRO_REST_ARGS + if (lbm_is_cons(curr_arg)) { + expand_env = allocate_binding(ENC_SYM_REST_ARGS, curr_arg, expand_env); + } +#endif + /* Two rounds of evaluation is performed. * First to instantiate the arguments into the macro body. * Second to evaluate the resulting program. */ - + sptr[1] = EVAL_R; lbm_value exp = get_cadr(get_cdr(ctx->r)); ctx->curr_exp = exp; @@ -2918,6 +2943,7 @@ static void apply_eval(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) { static void apply_eval_program(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) { if (nargs == 1) { + // here ctx->r = args[0]; lbm_value prg = args[0]; // No check that this is a program. lbm_value app_cont; lbm_value app_cont_prg; @@ -3550,7 +3576,7 @@ static void cont_closure_application_args(eval_context_t *ctx) { // s[sp-5] = environment to evaluate args in // s[sp-4] = body // s[sp-3] = closure environment -// s[sp-2] = argument list +// s[sp-2] = argument list // s[sp-1] = last cell in rest-args list so far. static void cont_closure_args_rest(eval_context_t *ctx) { lbm_uint* sptr = get_stack_ptr(ctx, 5); @@ -3903,7 +3929,7 @@ static void cont_loop_env_prep(eval_context_t *ctx) { stack_reserve(ctx,1)[0] = LOOP_CONDITION; ctx->curr_exp = sptr[1]; } - + static void cont_merge_rest(eval_context_t *ctx) { lbm_uint *sptr = get_stack_ptr(ctx, 9); @@ -4848,7 +4874,7 @@ static void cont_read_dot_terminate(eval_context_t *ctx) { READ_ERROR_CTX(lbm_channel_row(str), lbm_channel_column(str)); } else if (lbm_is_cons(last_cell)) { lbm_ref_cell(last_cell)->cdr = ctx->r; - //lbm_set_cdr(last_cell, ctx->r); + //lbm_set_cdr(last_cell, ctx->r); ctx->r = sptr[0]; // first cell lbm_value *rptr = stack_reserve(ctx, 3); sptr[0] = stream; @@ -4957,7 +4983,7 @@ static void cont_application_start(eval_context_t *ctx) { ERROR_AT_CTX(ENC_SYM_EERROR, ctx->r); } } break; - case ENC_SYM_CONT:{ + case ENC_SYM_CONT:{ ctx->curr_exp = setup_cont(ctx, args); } break; case ENC_SYM_CONT_SP: { @@ -5246,7 +5272,7 @@ static void cont_qq_expand_start(eval_context_t *ctx) { ctx->app_cont = true; } -lbm_value quote_it(lbm_value qquoted) { +static lbm_value quote_it(lbm_value qquoted) { if (lbm_is_symbol(qquoted) && lbm_is_special(qquoted)) return qquoted; @@ -5254,13 +5280,13 @@ lbm_value quote_it(lbm_value qquoted) { return cons_with_gc(ENC_SYM_QUOTE, val, ENC_SYM_NIL); } -bool is_append(lbm_value a) { - return (lbm_is_cons(a) && +static bool is_append(lbm_value a) { + return (lbm_is_cons(a) && lbm_is_symbol(lbm_ref_cell(a)->car) && (lbm_ref_cell(a)->car == ENC_SYM_APPEND)); } -lbm_value append(lbm_value front, lbm_value back) { +static lbm_value append(lbm_value front, lbm_value back) { if (lbm_is_symbol_nil(front)) return back; if (lbm_is_symbol_nil(back)) return front; @@ -5447,7 +5473,7 @@ static void cont_pop_reader_flags(eval_context_t *ctx) { // // s[sp-2] retval - a list of 2 elements created by eval_trap // s[sp-1] flags - context flags stored by eval_trap -// +// static void cont_exception_handler(eval_context_t *ctx) { lbm_value *sptr = pop_stack_ptr(ctx, 2); lbm_value retval = sptr[0]; @@ -5681,7 +5707,7 @@ static void apply_apply(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) { // so, even if this isn't always how you would expect apply to work. // For instance, `(apply and '(a))` would try evaluating the symbol `a`, // instead of just returning the symbol `a` outright. - + // Evaluator functions expect the current expression to equal the special // form, i.e. including the function symbol. lbm_value fun_and_args = cons_with_gc(fun, arg_list, ENC_SYM_NIL); @@ -5703,19 +5729,19 @@ static void apply_apply(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) { } else if (lbm_is_cons(fun)) { lbm_cons_t *fun_cell = lbm_ref_cell(fun); switch (fun_cell->car) { - case ENC_SYM_CLOSURE: { + case ENC_SYM_CLOSURE: { lbm_value closure[3]; extract_n(fun_cell->cdr, closure, 3); - + // Only placed here to protect from GC. Will be overriden later. // ctx->r = arg_list; // Should already be placed there. ctx->curr_exp = fun; - + lbm_value env = closure[CLO_ENV]; - + lbm_value current_params = closure[CLO_PARAMS]; lbm_value current_args = arg_list; - + while (true) { bool more_params = lbm_is_cons(current_params); bool more_args = lbm_is_cons(current_args); @@ -5726,14 +5752,14 @@ static void apply_apply(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) { lbm_value car_args = a_cell->car; lbm_value cdr_params = p_cell->cdr; lbm_value cdr_args = a_cell->cdr; - + // More parameters to bind env = allocate_binding( car_params, car_args, env ); - + current_params = cdr_params; current_args = cdr_args; } else if (!more_params && more_args) { @@ -5749,7 +5775,7 @@ static void apply_apply(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) { ERROR_AT_CTX(ENC_SYM_EERROR, fun); } } - + ctx->curr_env = env; ctx->curr_exp = closure[CLO_BODY]; return; @@ -5974,16 +6000,12 @@ void lbm_run_eval(void){ // the current timestamp has overflowed back to being small, giving a // "positive" (closer to min value) result, meaning the context will be // switched. - uint32_t unsigned_difference = timestamp_us_callback() - eval_current_quota; - bool is_negative = unsigned_difference & (1u << 31); + uint32_t unsigned_difference = timestamp() - eval_current_quota; + bool is_negative = unsigned_difference & (1u << 31); if (is_negative && ctx_running) { evaluation_step(); } else { if (eval_cps_state_changed) break; - // On overflow of timer, task will get a no-quota. - // Could lead to busy-wait here until timestamp and quota - // are on same side of overflow. - eval_current_quota = timestamp_us_callback() + eval_time_refill; if (!is_atomic) { if (gc_requested) { gc(); @@ -6004,6 +6026,16 @@ void lbm_run_eval(void){ lbm_system_sleeping = false; } } + // Assign a new quota last. + // This means that the time it takes in finding a context to dequeue + // and the other work above is not included in the woken up contexts quota. + // + // Earlier the new quota was assigned at the top of this branch, + // If that happened such that timestamp + eval_time_refil ends + // up to be just shy of an overflow, going through all the rest of + // logic could potentially overflow the timestamp and create a situation + // where the scheduled task has a humongous quota! + eval_current_quota = timestamp() + eval_time_refill; } #else if (eval_steps_quota && ctx_running) { diff --git a/lispBM/lispBM/src/extensions/lbm_dyn_lib.c b/lispBM/lispBM/src/extensions/lbm_dyn_lib.c index e82857de92..ce62491ace 100644 --- a/lispBM/lispBM/src/extensions/lbm_dyn_lib.c +++ b/lispBM/lispBM/src/extensions/lbm_dyn_lib.c @@ -59,9 +59,11 @@ static const char* lbm_dyn_fun[] = { "(defun abs (x) (if (< x 0) (- x) x))", #ifdef LBM_USE_DYN_DEFSTRUCT - "(defun create-struct (dm name num-fields) { " - "(var arr (if dm (mkarray dm (+ 1 num-fields)) (mkarray (+ 1 num-fields)))) " + "(defun create-struct (name num-fields initials) { " + "(var arr (mkarray (+ 1 num-fields))) " "(setix arr 0 name) " + "(var num_inits (length initials))" + "(if initials (loopfor i 0 (and (< i num-fields) (< i num_inits)) (+ i 1) (setix arr (+ i 1) (ix initials i))))" "arr " "})", @@ -115,7 +117,7 @@ static const char* lbm_dyn_macros[] = { "(var new-pred-sym (str2sym (str-merge name-as-string \"?\")))" "(var field-ix (zip list-of-fields (range 1 (+ num-fields 1))))" "`(progn" - "(define ,new-create-sym (lambda () (create-struct (rest-args 0) ',name ,num-fields)))" + "(define ,new-create-sym (lambda () (create-struct ',name ,num-fields (rest-args))))" "(define ,new-pred-sym (lambda (struct) (is-struct struct ',name)))" ",@(map (lambda (x) (list define (accessor-sym name-as-string (car x))" "(access-set (cdr x)))) field-ix)" diff --git a/lispBM/lispBM/src/extensions/math_extensions.c b/lispBM/lispBM/src/extensions/math_extensions.c index e1a9295ba1..0da3caa530 100644 --- a/lispBM/lispBM/src/extensions/math_extensions.c +++ b/lispBM/lispBM/src/extensions/math_extensions.c @@ -145,7 +145,7 @@ static lbm_value ext_is_nan(lbm_value *args, lbm_uint argn) { if (argn == 1) { res = ENC_SYM_TERROR; if (lbm_is_number(args[0])) { - lbm_uint t = lbm_type_of(args[0]); + lbm_uint t = lbm_type_of_functional(args[0]); switch(t) { case LBM_TYPE_DOUBLE: if (isnan(lbm_dec_double(args[0]))) { @@ -175,7 +175,7 @@ static lbm_value ext_is_inf(lbm_value *args, lbm_uint argn) { if (argn == 1) { res = ENC_SYM_TERROR; if (lbm_is_number(args[0])) { - lbm_uint t = lbm_type_of(args[0]); + lbm_uint t = lbm_type_of_functional(args[0]); switch(t) { case LBM_TYPE_DOUBLE: if (isinf(lbm_dec_double(args[0]))) { diff --git a/lispBM/lispBM/src/extensions/string_extensions.c b/lispBM/lispBM/src/extensions/string_extensions.c index a619d2de76..f46a42cc73 100644 --- a/lispBM/lispBM/src/extensions/string_extensions.c +++ b/lispBM/lispBM/src/extensions/string_extensions.c @@ -87,7 +87,7 @@ static lbm_value ext_str_from_n(lbm_value *args, lbm_uint argn) { char buffer[100]; size_t len = 0; - switch (lbm_type_of(args[0])) { + switch (lbm_type_of_functional(args[0])) { case LBM_TYPE_DOUBLE: /* fall through */ case LBM_TYPE_FLOAT: if (!format) { diff --git a/lispBM/lispBM/src/heap.c b/lispBM/lispBM/src/heap.c index 7868de9d73..b92d4ccaba 100644 --- a/lispBM/lispBM/src/heap.c +++ b/lispBM/lispBM/src/heap.c @@ -1426,7 +1426,7 @@ void lbm_ptr_rev_trav(trav_fun f, lbm_value v, void* arg) { // In-order traversal if (f(curr, false, arg) == TRAV_FUN_SUBTREE_DONE) { lbm_gc_mark_phase(curr); - break; + goto trav_backtrack; } gc_mark(curr); @@ -1482,6 +1482,7 @@ void lbm_ptr_rev_trav(trav_fun f, lbm_value v, void* arg) { // // If the flag is not set, jump down to SWAP + trav_backtrack: while ((lbm_is_cons(prev) && (lbm_dec_ptr(prev) != LBM_PTR_NULL) && // is LBM_NULL a cons type? lbm_get_gc_flag(lbm_car(prev))) || diff --git a/lispBM/lispBM/src/lbm_c_interop.c b/lispBM/lispBM/src/lbm_c_interop.c index 2183e33cf9..cd056eea8e 100644 --- a/lispBM/lispBM/src/lbm_c_interop.c +++ b/lispBM/lispBM/src/lbm_c_interop.c @@ -21,11 +21,12 @@ static bool lift_char_channel(lbm_char_channel_t *chan , lbm_value *res) { lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CHANNEL, (lbm_uint) chan, ENC_SYM_CHANNEL_TYPE); - if (cell == ENC_SYM_MERROR) { - return false; + bool rval = false; + if (cell != ENC_SYM_MERROR) { + *res = cell; + rval = true; } - *res = cell; - return true; + return rval; } @@ -37,126 +38,99 @@ static bool lift_char_channel(lbm_char_channel_t *chan , lbm_value *res) { lbm_cid eval_cps_load_and_eval(lbm_char_channel_t *tokenizer, bool program, bool incremental, char *name) { lbm_value stream; - - if (!lift_char_channel(tokenizer, &stream)) { - return -1; - } - - if (lbm_type_of(stream) == LBM_TYPE_SYMBOL) { - // TODO: Check what should be done. - return -1; - } - - lbm_value read_mode = ENC_SYM_READ; - if (program) { - if (incremental) { - read_mode = ENC_SYM_READ_AND_EVAL_PROGRAM; - } else { - read_mode = ENC_SYM_READ_PROGRAM; + lbm_cid cid = -1; + if (lift_char_channel(tokenizer, &stream)) { + lbm_value read_mode = ENC_SYM_READ; + if (program) { + if (incremental) { + read_mode = ENC_SYM_READ_AND_EVAL_PROGRAM; + } else { + read_mode = ENC_SYM_READ_PROGRAM; + } + } + /* + read-eval-program finishes with the result of the final expression in + the program. This should not be passed to eval-program as it is most likely + not a program. Even if it is a program, its not one we want to evaluate. + */ + + /* LISP ZONE */ + lbm_value launcher = lbm_cons(stream, ENC_SYM_NIL); + launcher = lbm_cons(read_mode, launcher); + lbm_value evaluator; + lbm_value start_prg; + if (read_mode == ENC_SYM_READ) { + evaluator = lbm_cons(launcher, ENC_SYM_NIL); + evaluator = lbm_cons(ENC_SYM_EVAL, evaluator); + start_prg = lbm_cons(evaluator, ENC_SYM_NIL); + } else if (read_mode == ENC_SYM_READ_PROGRAM) { + evaluator = lbm_cons(launcher, ENC_SYM_NIL); + evaluator = lbm_cons(ENC_SYM_EVAL_PROGRAM, evaluator); + start_prg = lbm_cons(evaluator, ENC_SYM_NIL); + } else { // ENC_SYM_READ_AND_EVAL_PROGRAM + evaluator = launcher; // dummy so check below passes + start_prg = lbm_cons(launcher, ENC_SYM_NIL); } - } - /* - read-eval-program finishes with the result of the final expression in - the program. This should not be passed to eval-program as it is most likely - not a program. Even if it is a program, its not one we want to evaluate. - */ - - /* LISP ZONE */ - lbm_value launcher = lbm_cons(stream, ENC_SYM_NIL); - launcher = lbm_cons(read_mode, launcher); - lbm_value evaluator; - lbm_value start_prg; - if (read_mode == ENC_SYM_READ) { - evaluator = lbm_cons(launcher, ENC_SYM_NIL); - evaluator = lbm_cons(ENC_SYM_EVAL, evaluator); - start_prg = lbm_cons(evaluator, ENC_SYM_NIL); - } else if (read_mode == ENC_SYM_READ_PROGRAM) { - evaluator = lbm_cons(launcher, ENC_SYM_NIL); - evaluator = lbm_cons(ENC_SYM_EVAL_PROGRAM, evaluator); - start_prg = lbm_cons(evaluator, ENC_SYM_NIL); - } else { // ENC_SYM_READ_AND_EVAL_PROGRAM - evaluator = launcher; // dummy so check below passes - start_prg = lbm_cons(launcher, ENC_SYM_NIL); - } - /* LISP ZONE ENDS */ + /* LISP ZONE ENDS */ - if (lbm_type_of(launcher) != LBM_TYPE_CONS || - lbm_type_of(evaluator) != LBM_TYPE_CONS || - lbm_type_of(start_prg) != LBM_TYPE_CONS ) { - return -1; + if (lbm_type_of(launcher) == LBM_TYPE_CONS && + lbm_type_of(evaluator) == LBM_TYPE_CONS && + lbm_type_of(start_prg) == LBM_TYPE_CONS ) { + cid = lbm_create_ctx(start_prg, ENC_SYM_NIL, 256, name); + } } - return lbm_create_ctx(start_prg, ENC_SYM_NIL, 256, name); + return cid; } lbm_cid eval_cps_load_and_define(lbm_char_channel_t *tokenizer, char *symbol, bool program) { - lbm_value stream; - - if (!lift_char_channel(tokenizer, &stream)) { - return -1; - } - - if (lbm_type_of(stream) == LBM_TYPE_SYMBOL) { - return -1; - } - - lbm_uint sym_id; - - if (!lbm_get_symbol_by_name(symbol, &sym_id)) { - if (!lbm_add_symbol_base(symbol, &sym_id)) { //ram - return -1; + lbm_cid cid = -1; + if (lift_char_channel(tokenizer, &stream)) { + lbm_uint sym_id; + if (lbm_get_symbol_by_name(symbol, &sym_id) || + lbm_add_symbol_base(symbol, &sym_id)) { + /* LISP ZONE */ + lbm_value launcher = lbm_cons(stream, lbm_enc_sym(SYM_NIL)); + launcher = lbm_cons(lbm_enc_sym(program ? SYM_READ_PROGRAM : SYM_READ), launcher); + lbm_value binding = lbm_cons(launcher, lbm_enc_sym(SYM_NIL)); + binding = lbm_cons(lbm_enc_sym(sym_id), binding); + lbm_value definer = lbm_cons(lbm_enc_sym(SYM_DEFINE), binding); + definer = lbm_cons(definer, lbm_enc_sym(SYM_NIL)); + /* LISP ZONE ENDS */ + + if (lbm_type_of(launcher) == LBM_TYPE_CONS && + lbm_type_of(binding) == LBM_TYPE_CONS && + lbm_type_of(definer) == LBM_TYPE_CONS ) { + cid = lbm_create_ctx(definer, lbm_enc_sym(SYM_NIL), 256, NULL); + } } } - - /* LISP ZONE */ - - lbm_value launcher = lbm_cons(stream, lbm_enc_sym(SYM_NIL)); - launcher = lbm_cons(lbm_enc_sym(program ? SYM_READ_PROGRAM : SYM_READ), launcher); - lbm_value binding = lbm_cons(launcher, lbm_enc_sym(SYM_NIL)); - binding = lbm_cons(lbm_enc_sym(sym_id), binding); - lbm_value definer = lbm_cons(lbm_enc_sym(SYM_DEFINE), binding); - definer = lbm_cons(definer, lbm_enc_sym(SYM_NIL)); - /* LISP ZONE ENDS */ - - if (lbm_type_of(launcher) != LBM_TYPE_CONS || - lbm_type_of(binding) != LBM_TYPE_CONS || - lbm_type_of(definer) != LBM_TYPE_CONS ) { - return -1; - } - return lbm_create_ctx(definer, lbm_enc_sym(SYM_NIL), 256, NULL); + return cid; } lbm_cid lbm_eval_defined(char *symbol, bool program) { lbm_uint sym_id; - - if(!lbm_get_symbol_by_name(symbol, &sym_id)) { - // The symbol does not exist, so it cannot be defined - return -1; - } - lbm_value binding; - - if (!lbm_global_env_lookup(&binding, lbm_enc_sym(sym_id))) { - return -1; - } - - /* LISP ZONE */ - - lbm_value launcher = lbm_cons(lbm_enc_sym(sym_id), lbm_enc_sym(SYM_NIL)); - lbm_value evaluator = launcher; - evaluator = lbm_cons(lbm_enc_sym(program ? SYM_EVAL_PROGRAM : SYM_EVAL), evaluator); - lbm_value start_prg = lbm_cons(evaluator, lbm_enc_sym(SYM_NIL)); - - /* LISP ZONE ENDS */ - - if (lbm_type_of(launcher) != LBM_TYPE_CONS || - lbm_type_of(evaluator) != LBM_TYPE_CONS || - lbm_type_of(start_prg) != LBM_TYPE_CONS ) { - return -1; + lbm_cid cid = -1; + if (lbm_get_symbol_by_name(symbol, &sym_id) && + lbm_global_env_lookup(&binding, lbm_enc_sym(sym_id))) { + + /* LISP ZONE */ + lbm_value launcher = lbm_cons(lbm_enc_sym(sym_id), lbm_enc_sym(SYM_NIL)); + lbm_value evaluator = launcher; + evaluator = lbm_cons(lbm_enc_sym(program ? SYM_EVAL_PROGRAM : SYM_EVAL), evaluator); + lbm_value start_prg = lbm_cons(evaluator, lbm_enc_sym(SYM_NIL)); + /* LISP ZONE ENDS */ + + if (lbm_type_of(launcher) == LBM_TYPE_CONS && + lbm_type_of(evaluator) == LBM_TYPE_CONS && + lbm_type_of(start_prg) == LBM_TYPE_CONS ) { + cid = lbm_create_ctx(start_prg, lbm_enc_sym(SYM_NIL), 256, NULL); + } } - return lbm_create_ctx(start_prg, lbm_enc_sym(SYM_NIL), 256, NULL); + return cid; } @@ -203,35 +177,36 @@ int lbm_send_message(lbm_cid cid, lbm_value msg) { int lbm_define(char *symbol, lbm_value value) { int res = 0; - if (!symbol) return res; - - lbm_uint sym_id; - if (lbm_get_eval_state() == EVAL_CPS_STATE_PAUSED) { - if (!lbm_get_symbol_by_name(symbol, &sym_id)) { - if (!lbm_add_symbol_const_base(symbol, &sym_id, false)) { - return 0; + if (symbol) { + lbm_uint sym_id; + if (lbm_get_eval_state() == EVAL_CPS_STATE_PAUSED) { + if (lbm_get_symbol_by_name(symbol, &sym_id) || + lbm_add_symbol_const_base(symbol, &sym_id, false)) { + lbm_uint ix_key = sym_id & GLOBAL_ENV_MASK; + lbm_value *glob_env = lbm_get_global_env(); + glob_env[ix_key] = lbm_env_set(glob_env[ix_key], lbm_enc_sym(sym_id), value); + res = 1; } } - lbm_uint ix_key = sym_id & GLOBAL_ENV_MASK; - lbm_value *glob_env = lbm_get_global_env(); - glob_env[ix_key] = lbm_env_set(glob_env[ix_key], lbm_enc_sym(sym_id), value); - res = 1; } return res; } int lbm_undefine(char *symbol) { lbm_uint sym_id; - if (!symbol || !lbm_get_symbol_by_name(symbol, &sym_id)) - return 0; + int res = 0; + if (symbol && lbm_get_symbol_by_name(symbol, &sym_id)) { - lbm_value *glob_env = lbm_get_global_env(); - lbm_uint ix_key = sym_id & GLOBAL_ENV_MASK; - lbm_value new_env = lbm_env_drop_binding(glob_env[ix_key], lbm_enc_sym(sym_id)); + lbm_value *glob_env = lbm_get_global_env(); + lbm_uint ix_key = sym_id & GLOBAL_ENV_MASK; + lbm_value new_env = lbm_env_drop_binding(glob_env[ix_key], lbm_enc_sym(sym_id)); - if (new_env == ENC_SYM_NOT_FOUND) return 0; - glob_env[ix_key] = new_env; - return 1; + if (new_env != ENC_SYM_NOT_FOUND) { + glob_env[ix_key] = new_env; + res = 1; + } + } + return res; } int lbm_share_array(lbm_value *value, char *data, lbm_uint num_elt) { @@ -294,10 +269,11 @@ bool lbm_flatten_env(int index, lbm_uint** data, lbm_uint *size) { if (lbm_is_symbol(fv)) return false; lbm_array_header_t *array = lbm_dec_array_r(fv); + bool rval = false; if (array) { *size = array->size; *data = array->data; - return true; + rval = true; } - return false; + return rval; } diff --git a/lispBM/lispBM/src/lbm_flat_value.c b/lispBM/lispBM/src/lbm_flat_value.c index 0022c00186..aade839f24 100644 --- a/lispBM/lispBM/src/lbm_flat_value.c +++ b/lispBM/lispBM/src/lbm_flat_value.c @@ -21,7 +21,11 @@ #include #include - + +#ifndef DEBUG +#define DEBUG 0 +#endif + // ------------------------------------------------------------ // Access to GC from eval_cps int lbm_perform_gc(void); @@ -250,11 +254,34 @@ int lbm_get_max_flatten_depth(void) { return flatten_maximum_depth; } -void flatten_error(jmp_buf jb, int val) { +static void flatten_error(jmp_buf jb, int val) { longjmp(jb, val); } -int flatten_value_size_internal(jmp_buf jb, lbm_value v, int depth, bool image) { +/* Use of setjmp/longjmp in flatten_value_size + + setjmp/longjmp behavior is undefined: + * If the function which called setjmp() returns before longjmp() is + called, the behavior is undefined. Some kind of subtle or unsubtle + chaos is sure to result. + + * If, in a multithreaded program, a longjmp() call employs an env buffer + that was initialized by a call to setjmp() in a different thread, the + behavior is undefined. + + The use of setjmp/longjmp in in flatten_value_size_internal/flatten_value_size + is avoiding undefined behviour by: + 1. flatten_value_size_internal is static. + 2. flatten_error is static. + 3. flatten_error is ONLY allowed to be called from flatten_value_size_internal. + 4. The jmpbuf is created in flatten_value_size, which is exposed API. + 5. Only flatten_value_size calls flatten_value_size_internal. + + Changes to the flat value code MUST NOT change 1 - 5 properties mentioned + above. +*/ + +static int flatten_value_size_internal(jmp_buf jb, lbm_value v, int depth, bool image) { if (depth > flatten_maximum_depth) { flatten_error(jb, FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH); } @@ -779,7 +806,7 @@ static int lbm_unflatten_value_atom(lbm_flat_value_t *v, lbm_value *res) { // Initially: // curr = LBM_NULL; v->buf = { ... } // -// FORWARDS PHASE: +// FORWARDS PHASE: // Cons case: // Reading conses from the buffer builds a backpointing list. // Placeholder element acts as a 1 bit "visited" field. @@ -839,6 +866,9 @@ static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, bool done = false; lbm_value val0; lbm_value curr = lbm_enc_cons_ptr(LBM_PTR_NULL); +#if DEBUG + char buf[256]; +#endif while (!done) { int32_t set_ix = -1; if (v->buf[v->buf_pos] == S_SHARED) { @@ -853,6 +883,9 @@ static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, #endif if (b) { int32_t ix = sharing_table_contains(st, tmp); +#if DEBUG + printf("UNFLATTEN S_SHARED: addr %x -> sharing_table index %d\n", (unsigned int)tmp, ix); +#endif if (ix >= 0) { set_ix = ix; } else { @@ -873,7 +906,14 @@ static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, lbm_value tmp = curr; curr = lbm_cons(tmp, ENC_SYM_PLACEHOLDER); if (lbm_is_symbol_merror(curr)) return UNFLATTEN_GC_RETRY; - if (set_ix >= 0) target_map[set_ix] = curr; + + if (set_ix >= 0) { +#if DEBUG + lbm_print_value(buf,256,curr); + printf("target_map[%d] = %s\n", set_ix, buf); +#endif + target_map[set_ix] = curr; + } v->buf_pos ++; is_leaf = false; } else if (v->buf[v->buf_pos] == S_LBM_LISP_ARRAY) { @@ -883,7 +923,7 @@ static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, if (b) { // Abort if buffer cannot possibly hold that size array. // a flattened byte occupies 2 bytes in fv. so smallest possible - // array is array of bytes. + // array is array of bytes. if (size > 0 && v->buf_pos + (size * 2) > v->buf_size) return UNFLATTEN_MALFORMED; lbm_value array; lbm_heap_allocate_lisp_array(&array, size); @@ -919,9 +959,19 @@ static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, // Shared should have been hit before S_REF. So just look up index and copy from // the target_map. int32_t ix = sharing_table_contains(st, tmp); +#if DEBUG + printf("UNFLATTEN S_REF: addr %x -> sharing_table index %d\n", (unsigned int)tmp, ix); +#endif if (ix >= 0) { //curr = target_map[ix]; unflattened = target_map[ix]; +#if DEBUG + lbm_print_value(buf,256, unflattened); + printf("read %s from target_map[%d]\n", buf, ix); + lbm_print_value(buf,256, curr); + printf("curr is currently: %s\n", buf); + printf("this is a %s\n", is_leaf ? "leaf" : "internal node"); +#endif } else { return UNFLATTEN_SHARING_TABLE_ERROR; } @@ -933,6 +983,10 @@ static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, } } else { int e_val = lbm_unflatten_value_atom(v, &unflattened); +#if DEBUG + lbm_print_value(buf,256, unflattened); + printf("atom: %s\n", buf); +#endif if (set_ix >= 0) { target_map[set_ix] = unflattened; } @@ -975,6 +1029,10 @@ static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, // Do nothing in this case. It has been arranged.. } else if (lbm_cdr(curr) == ENC_SYM_PLACEHOLDER) { lbm_set_cdr(curr, val0); +#if DEBUG + lbm_print_value(buf,256, curr); + printf("curr: %s\n", buf); +#endif } else { return UNFLATTEN_MALFORMED; } diff --git a/lispBM/lispBM/src/lbm_image.c b/lispBM/lispBM/src/lbm_image.c index 95c3845fba..2b7bf658a4 100644 --- a/lispBM/lispBM/src/lbm_image.c +++ b/lispBM/lispBM/src/lbm_image.c @@ -23,6 +23,10 @@ #include #include +#ifndef DEBUG +#define DEBUG 0 +#endif + // Assumptions about the image memory: // * It is part of the address space. // * Image is always available at the same address (across reboots) @@ -799,7 +803,7 @@ typedef struct { } flatten_node_meta_data; static int flatten_node(lbm_value v, bool shared, void *arg) { - (void)shared; + (void) shared; flatten_node_meta_data *md = (flatten_node_meta_data*)arg; bool *acc = &md->res; @@ -808,6 +812,9 @@ static int flatten_node(lbm_value v, bool shared, void *arg) { if (ix >= 0) { if (SHARING_TABLE_TRUE == sharing_table_get_field(md->st, ix, SHARING_TABLE_FLATTENED_FIELD)) { // Shared node already flattened. +#if DEBUG + printf("FLATTEN: Writing S_REF for target_map[%d] (addr %x)\n", ix, (unsigned int)v); +#endif fv_write_u8(S_REF); #ifdef LBM64 fv_write_u64((lbm_uint)v); @@ -817,6 +824,9 @@ static int flatten_node(lbm_value v, bool shared, void *arg) { return TRAV_FUN_SUBTREE_DONE; } else { // Shared node not yet flattened. +#if DEBUG + printf("FLATTEN: Writing S_SHARED for target_map[%d] (addr %x)\n", ix, (unsigned int)v); +#endif sharing_table_set_field(md->st, ix, SHARING_TABLE_FLATTENED_FIELD, SHARING_TABLE_TRUE); fv_write_u8(S_SHARED); #ifdef LBM64 @@ -921,6 +931,26 @@ static bool image_flatten_value(sharing_table *st, lbm_value v) { return md.res; // ok = enough space in image for flat val. } +// //////////////////////////////////////////////////////////// +// print sharing table +#if DEBUG +void print_sharing_table(sharing_table *st) { + int32_t pos = st->start; + int32_t num = st->num; + char buf[256]; + + for (int i = 0; i < num; i ++) { + int32_t ix = index_sharing_table(st, i); + lbm_uint a = read_u32(ix); // address + + lbm_print_value(buf, 256, a); + printf("%d\t%x\t%s\n",i, a, buf); + } + + +} +#endif + // //////////////////////////////////////////////////////////// // bool lbm_image_save_global_env(void) { @@ -949,9 +979,25 @@ bool lbm_image_save_global_env(void) { write_u32((uint32_t)fv_size , &write_index, DOWNWARDS); write_lbm_value(name_field, &write_index, DOWNWARDS); write_index = write_index - fv_size; // subtract fv_size +#if DEBUG + int32_t data_start = write_index; // Save the start position +#endif if (image_flatten_value(&st, val_field)) { // adds fv_size back - // TODO: What error handling makes sense? fv_write_flush(); +#if DEBUG + printf("Flattenining address: %x\n", val_field); + for (int i = 0; i < fv_size; i ++) { + uint32_t v = read_u32(data_start + i); + uint8_t *p = &v; + for (int j = 0; j < 4; j ++) { + printf("%x ", p[j]); + } + printf(" "); + } + printf("\n"); +#endif + + // TODO: What error handling makes sense? } write_index = write_index - fv_size - 1; // subtract fv_size } else { @@ -961,6 +1007,10 @@ bool lbm_image_save_global_env(void) { curr = lbm_cdr(curr); } } +#if DEBUG + printf("Sharing table:\n"); + print_sharing_table(&st); +#endif return true; } return false; @@ -1213,7 +1263,7 @@ bool lbm_image_boot(void) { uint32_t sym_id = (uint32_t)(p[1]); lbm_uint next_id = lbm_symrepr_get_next_id(); if (sym_id >= RUNTIME_SYMBOLS_START && sym_id >= next_id ) { - lbm_symrepr_set_next_id(next_id + 1); + lbm_symrepr_set_next_id(sym_id + 1); } lbm_symrepr_set_symlist((lbm_uint*)(image_address + entry_pos)); pos -= 6; @@ -1223,7 +1273,7 @@ bool lbm_image_boot(void) { uint32_t sym_id = (uint32_t)(p[1]); lbm_uint next_id = lbm_symrepr_get_next_id(); if (sym_id >= RUNTIME_SYMBOLS_START && sym_id >= next_id ) { - lbm_symrepr_set_next_id(next_id + 1); + lbm_symrepr_set_next_id(sym_id + 1); } lbm_symrepr_set_symlist((lbm_uint*)(image_address + entry_pos)); pos -= 3; @@ -1248,7 +1298,7 @@ bool lbm_image_boot(void) { *((lbm_uint*)link_ptr) = sym_id; lbm_uint next_id = lbm_symrepr_get_next_id(); if (sym_id >= RUNTIME_SYMBOLS_START && sym_id >= next_id ) { - lbm_symrepr_set_next_id(next_id + 1); + lbm_symrepr_set_next_id(sym_id + 1); } lbm_symrepr_set_symlist((lbm_uint*)(image_address + (pos - 7))); pos -= 8; @@ -1258,7 +1308,7 @@ bool lbm_image_boot(void) { *((lbm_uint*)link_ptr) = sym_id; lbm_uint next_id = lbm_symrepr_get_next_id(); if (sym_id >= RUNTIME_SYMBOLS_START && sym_id >= next_id ) { - lbm_symrepr_set_next_id(next_id + 1); + lbm_symrepr_set_next_id(sym_id + 1); } lbm_symrepr_set_symlist((lbm_uint*)(image_address + (pos - 3))); pos -= 4; @@ -1295,7 +1345,7 @@ bool lbm_image_boot(void) { st.start = pos +1; uint32_t num = read_u32(pos); pos --; st.num = (int32_t)num; - if (num > 0) { + if (num > 0) { target_map = lbm_malloc(num * sizeof(lbm_uint)); if (!target_map ) { return false; diff --git a/lispBM/lispBM/src/lbm_memory.c b/lispBM/lispBM/src/lbm_memory.c index 351f05c88e..6aeab6b253 100644 --- a/lispBM/lispBM/src/lbm_memory.c +++ b/lispBM/lispBM/src/lbm_memory.c @@ -141,9 +141,6 @@ static inline lbm_uint status(lbm_uint i) { lbm_uint bit_ix = ix & WORD_MOD_MASK; // % 32 lbm_uint mask = ((lbm_uint)3) << bit_ix; // 000110..0 - if (word_ix > bitmap_size) { - return (lbm_uint)NULL; - } return (bitmap[word_ix] & mask) >> bit_ix; } @@ -185,7 +182,7 @@ lbm_uint lbm_memory_longest_free(void) { lbm_uint max_length = 0; lbm_uint curr_length = 0; - for (unsigned int i = 0; i < (bitmap_size << BITMAP_SIZE_SHIFT); i ++) { + for (unsigned int i = 0; i < memory_size; i ++) { // The status field is 2 bits and this 4 cases is exhaustive! switch(status(i)) { @@ -219,7 +216,11 @@ lbm_uint lbm_memory_longest_free(void) { mutex_unlock(&lbm_mem_mutex); if (memory_num_free - max_length < memory_reserve_level) { lbm_uint n = memory_reserve_level - (memory_num_free - max_length); - max_length -= n; + if (n >= max_length) { + max_length = 0; + } else { + max_length -= n; + } } return max_length; } @@ -236,9 +237,8 @@ static lbm_uint *lbm_memory_allocate_internal(lbm_uint num_words) { lbm_uint end_ix = 0; lbm_uint free_length = 0; unsigned int state = INIT; - lbm_uint loop_max = (bitmap_size << BITMAP_SIZE_SHIFT); - for (lbm_uint i = 0; i < loop_max; i ++) { + for (lbm_uint i = 0; i < memory_size; i ++) { switch(status(alloc_offset)) { case FREE_OR_USED: switch (state) { @@ -279,7 +279,7 @@ static lbm_uint *lbm_memory_allocate_internal(lbm_uint num_words) { if (state == ALLOC_DONE) break; alloc_offset++; - if (alloc_offset == loop_max ) { + if (alloc_offset == memory_size ) { free_length = 0; alloc_offset = 0; state = INIT; @@ -319,7 +319,7 @@ int lbm_memory_free(lbm_uint *ptr) { switch(status(ix)) { case START: set_status(ix, FREE_OR_USED); - for (lbm_uint i = ix; i < (bitmap_size << BITMAP_SIZE_SHIFT); i ++) { + for (lbm_uint i = ix; i < memory_size; i ++) { count_freed ++; if (status(i) == END) { set_status(i, FREE_OR_USED); @@ -396,7 +396,7 @@ int lbm_memory_shrink(lbm_uint *ptr, lbm_uint n) { bool done = false; unsigned int i = 0; - for (i = 0; i < ((bitmap_size << BITMAP_SIZE_SHIFT) - ix); i ++) { + for (i = 0; i < (memory_size - ix); i ++) { if (status(ix+i) == END && i < n) { mutex_unlock(&lbm_mem_mutex); return 0; // cannot shrink allocation to a larger size @@ -421,7 +421,7 @@ int lbm_memory_shrink(lbm_uint *ptr, lbm_uint n) { lbm_uint count = 0; if (!done) { i++; // move to next position, prev position should be END or START_END - for (;i < ((bitmap_size << BITMAP_SIZE_SHIFT) - ix); i ++) { + for (;i < (memory_size - ix); i ++) { count ++; if (status(ix+i) == END) { set_status(ix+i, FREE_OR_USED); diff --git a/lispBM/lispBM/src/symrepr.c b/lispBM/lispBM/src/symrepr.c index b14bddf625..3138bec1eb 100644 --- a/lispBM/lispBM/src/symrepr.c +++ b/lispBM/lispBM/src/symrepr.c @@ -299,41 +299,44 @@ void lbm_symrepr_name_iterator(symrepr_name_iterator_fun f) { } const char *lookup_symrepr_name_memory(lbm_uint id) { - + const char *res = NULL; lbm_uint *curr = symlist; while (curr) { if (id == curr[ID]) { - return (const char *)curr[NAME]; + res = (const char *)curr[NAME]; } curr = (lbm_uint*)curr[NEXT]; } - return NULL; + return res; } // Lookup symbol name given a symbol id const char *lbm_get_name_by_symbol(lbm_uint id) { lbm_uint sym_kind = SYMBOL_KIND(id); + const char *res = NULL; switch (sym_kind) { case SYMBOL_KIND_SPECIAL: /* fall through */ case SYMBOL_KIND_FUNDAMENTAL: case SYMBOL_KIND_APPFUN: for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) { if (id == special_symbols[i].id) { - return (special_symbols[i].name); + res = (special_symbols[i].name); + // With aliases there can be more than one hit here. + // exit after first hit. + break; } } - return NULL; break; case SYMBOL_KIND_EXTENSION: { lbm_uint ext_id = id - EXTENSION_SYMBOLS_START; if (ext_id < lbm_get_max_extensions()) { - return extension_table[ext_id].name; + res = extension_table[ext_id].name; } - return NULL; } break; default: - return lookup_symrepr_name_memory(id); + res = lookup_symrepr_name_memory(id); } + return res; } lbm_uint *lbm_get_symbol_list_entry_by_name(char *name) { @@ -341,21 +344,21 @@ lbm_uint *lbm_get_symbol_list_entry_by_name(char *name) { while (curr) { char *str = (char*)curr[NAME]; if (str_eq(name, str)) { - return (lbm_uint *)curr; + break; } curr = (lbm_uint*)curr[NEXT]; } - return NULL; + return curr; } // Lookup symbol id given symbol name int lbm_get_symbol_by_name(char *name, lbm_uint* id) { - + int res = 0; // loop through special symbols for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) { if (str_eq(name, (char *)special_symbols[i].name)) { *id = special_symbols[i].id; - return 1; + res = 1; goto get_symbol_by_name_done; } } @@ -363,7 +366,7 @@ int lbm_get_symbol_by_name(char *name, lbm_uint* id) { for (unsigned int i = 0; i < lbm_get_max_extensions(); i ++) { if (extension_table[i].name && str_eq(name, extension_table[i].name)) { *id = EXTENSION_SYMBOLS_START + i; - return 1; + res = 1; goto get_symbol_by_name_done; } } @@ -372,34 +375,37 @@ int lbm_get_symbol_by_name(char *name, lbm_uint* id) { char *str = (char*)curr[NAME]; if (str_eq(name, str)) { *id = curr[ID]; - return 1; + res = 1; goto get_symbol_by_name_done; } curr = (lbm_uint*)curr[NEXT]; } - return 0; + get_symbol_by_name_done: + return res; } extern lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res); bool store_symbol_name_flash(char *name, lbm_uint *res) { + bool ret = false; size_t n = strlen(name) + 1; - if (n == 1) return 0; // failure if empty symbol + if (n > 1) { - lbm_uint alloc_size; - if (n % sizeof(lbm_uint) == 0) { - alloc_size = n/(sizeof(lbm_uint)); - } else { - alloc_size = (n/(sizeof(lbm_uint))) + 1; - } + lbm_uint alloc_size; + if (n % sizeof(lbm_uint) == 0) { + alloc_size = n/(sizeof(lbm_uint)); + } else { + alloc_size = (n/(sizeof(lbm_uint))) + 1; + } - lbm_uint symbol_addr = 0; - lbm_flash_status s = lbm_write_const_array_padded((uint8_t*)name, n, &symbol_addr); - if (s != LBM_FLASH_WRITE_OK || symbol_addr == 0) { - return false; + lbm_uint symbol_addr = 0; + lbm_flash_status s = lbm_write_const_array_padded((uint8_t*)name, n, &symbol_addr); + if (s == LBM_FLASH_WRITE_OK && symbol_addr) { + symbol_table_size_strings_flash += alloc_size; + *res = symbol_addr; + ret = true; + } } - symbol_table_size_strings_flash += alloc_size; - *res = symbol_addr; - return true; + return ret; } // Symbol table @@ -419,26 +425,27 @@ bool store_symbol_name_flash(char *name, lbm_uint *res) { // int lbm_add_symbol_base(char *name, lbm_uint *id) { + int res = 0; lbm_uint symbol_name_storage; - if (!store_symbol_name_flash(name, &symbol_name_storage)) return 0; - lbm_uint *new_symlist = lbm_image_add_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist); - if (!new_symlist) { - return 0; + if (store_symbol_name_flash(name, &symbol_name_storage)) { + lbm_uint *new_symlist = lbm_image_add_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist); + if (new_symlist) { + symlist = new_symlist; + *id = next_symbol_id ++; + res = 1; + } } - symlist = new_symlist; - *id = next_symbol_id ++; - return 1; + return res; } int lbm_add_symbol(char *name, lbm_uint* id) { - lbm_uint sym_id; - if (!lbm_get_symbol_by_name(name, &sym_id)) { - return lbm_add_symbol_base(name, id); + int res = 0; + if (lbm_get_symbol_by_name(name, id)) { + res = 1; } else { - *id = sym_id; - return 1; + res = lbm_add_symbol_base(name, id); } - return 0; + return res; } // on Linux, win, etc a const string may not be at @@ -446,6 +453,7 @@ int lbm_add_symbol(char *name, lbm_uint* id) { int lbm_add_symbol_const_base(char *name, lbm_uint* id, bool link) { lbm_uint symbol_name_storage = (lbm_uint)name; lbm_uint *new_symlist; + int res = 0; if (link) { new_symlist = lbm_image_add_and_link_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist, id); } else { @@ -454,28 +462,26 @@ int lbm_add_symbol_const_base(char *name, lbm_uint* id, bool link) { if (new_symlist) { symlist = new_symlist; *id = next_symbol_id ++; - return 1; + res = 1; } - return 0; + return res; } int lbm_add_symbol_const(char *name, lbm_uint* id) { - lbm_uint sym_id; - if (!lbm_get_symbol_by_name(name, &sym_id)) { - return lbm_add_symbol_const_base(name, id, true); + int res = 0; + if (lbm_get_symbol_by_name(name, id)) { + res = 1; } else { - *id = sym_id; - return 1; + res = lbm_add_symbol_const_base(name, id, true); } - return 0; + return res; } int lbm_str_to_symbol(char *name, lbm_uint *sym_id) { - if (lbm_get_symbol_by_name(name, sym_id)) - return 1; - else if (lbm_add_symbol(name, sym_id)) - return 1; - return 0; + int res = lbm_get_symbol_by_name(name, sym_id); + if (!res) + res = lbm_add_symbol(name, sym_id); + return res; } lbm_uint lbm_get_symbol_table_size(void) { diff --git a/lispBM/lispBM/src/tokpar.c b/lispBM/lispBM/src/tokpar.c index 87477312ac..65fe16dc6f 100644 --- a/lispBM/lispBM/src/tokpar.c +++ b/lispBM/lispBM/src/tokpar.c @@ -1,5 +1,5 @@ /* - Copyright 2019, 2021, 2022 Joel Svensson svenssonjoel@yahoo.se + Copyright 2019, 2021, 2022, 2025 Joel Svensson svenssonjoel@yahoo.se This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -181,16 +181,17 @@ int tok_symbol(lbm_char_channel_t *chan) { return TOKENIZER_NO_TOKEN; } memset(tokpar_sym_str,0,TOKENIZER_MAX_SYMBOL_AND_STRING_LENGTH+1); - tokpar_sym_str[0] = (char)tolower(c); + tokpar_sym_str[0] = (c >= 'A' && c <= 'Z') ? c + 32 : c; // locale independent ASCII only tolower. int len = 1; r = lbm_channel_peek(chan,(unsigned int)len, &c); while (r == CHANNEL_SUCCESS && symchar(c)) { - if (len >= 255) return TOKENIZER_SYMBOL_ERROR; - c = (char)tolower(c); + c = (c >= 'A' && c <= 'Z') ? c + 32 : c; // locale independent ASCII only tolower. if (len < TOKENIZER_MAX_SYMBOL_AND_STRING_LENGTH) { tokpar_sym_str[len] = (char)c; + } else { + return TOKENIZER_SYMBOL_ERROR; } len ++; r = lbm_channel_peek(chan,(unsigned int)len, &c); @@ -287,25 +288,28 @@ int tok_char(lbm_char_channel_t *chan, char *res) { return 3; } + +#define TD_BUF_SIZE 128 + +#define FBUF_ADD(X,N) if ((N) < TD_BUF_SIZE) { fbuf[(N)] = (X); N++; } else goto tok_double_no_tok; int tok_double(lbm_char_channel_t *chan, token_float *result) { unsigned int n = 0; - char fbuf[128]; + char fbuf[TD_BUF_SIZE]; char c; bool valid_num = false; int res; - memset(fbuf, 0, 128); + memset(fbuf, 0, TD_BUF_SIZE); result->type = TOKTYPEF32; result->negative = false; - res = lbm_channel_peek(chan, 0, &c); + res = lbm_channel_peek(chan, n, &c); if (res == CHANNEL_MORE) return TOKENIZER_NEED_MORE; else if (res == CHANNEL_END) return TOKENIZER_NO_TOKEN; if (c == '-') { - n = 1; - fbuf[0] = '-'; + FBUF_ADD('-', n); result->negative = true; } @@ -313,18 +317,15 @@ int tok_double(lbm_char_channel_t *chan, token_float *result) { if (res == CHANNEL_MORE) return TOKENIZER_NEED_MORE; else if (res == CHANNEL_END) return TOKENIZER_NO_TOKEN; while (c >= '0' && c <= '9') { - fbuf[n] = c; - n++; + FBUF_ADD(c, n); res = lbm_channel_peek(chan, n, &c); if (res == CHANNEL_MORE) return TOKENIZER_NEED_MORE; if (res == CHANNEL_END) break; } if (c == '.') { - fbuf[n] = c; - n ++; + FBUF_ADD(c, n); } - else return TOKENIZER_NO_TOKEN; res = lbm_channel_peek(chan,n, &c); @@ -333,24 +334,27 @@ int tok_double(lbm_char_channel_t *chan, token_float *result) { if (!(c >= '0' && c <= '9')) return TOKENIZER_NO_TOKEN; while (c >= '0' && c <= '9') { - fbuf[n] = c; - n++; + FBUF_ADD(c, n); res = lbm_channel_peek(chan, n, &c); if (res == CHANNEL_MORE) return TOKENIZER_NEED_MORE; if (res == CHANNEL_END) break; } if (c == 'e') { - fbuf[n] = c; - n++; + FBUF_ADD(c, n); res = lbm_channel_peek(chan,n, &c); if (res == CHANNEL_MORE) return TOKENIZER_NEED_MORE; else if (res == CHANNEL_END) return TOKENIZER_NO_TOKEN; if (!((c >= '0' && c <= '9') || c == '-')) return TOKENIZER_NO_TOKEN; - while ((c >= '0' && c <= '9') || c == '-') { - fbuf[n] = c; - n++; + if (c == '-') { + FBUF_ADD(c, n); + } + res = lbm_channel_peek(chan,n, &c); + if (res == CHANNEL_MORE) return TOKENIZER_NEED_MORE; + else if (res == CHANNEL_END) return TOKENIZER_NO_TOKEN; + while ((c >= '0' && c <= '9')) { + FBUF_ADD(c,n); res = lbm_channel_peek(chan, n, &c); if (res == CHANNEL_MORE) return TOKENIZER_NEED_MORE; if (res == CHANNEL_END) break; @@ -370,14 +374,12 @@ int tok_double(lbm_char_channel_t *chan, token_float *result) { if ((result->negative && n > 1) || (!result->negative && n > 0)) valid_num = true; - if (n > 127) { - return TOKENIZER_NO_TOKEN; - } - if(valid_num) { result->value = (double)strtod(fbuf,NULL); return (int)n + type_len; } + + tok_double_no_tok: return TOKENIZER_NO_TOKEN; } @@ -501,7 +503,7 @@ int tok_integer(lbm_char_channel_t *chan, token_int *result) { } } - if (n == 0) return TOKENIZER_NO_TOKEN; + if (n == 0 || (hex && n == 2)) return TOKENIZER_NO_TOKEN; uint32_t tok_res; int type_len = tok_match_fixed_size_tokens(chan, type_qual_table, n, NUM_TYPE_QUALIFIERS, &tok_res); diff --git a/lispBM/lispBM/tests/Makefile b/lispBM/lispBM/tests/Makefile index d15d42e881..0b13d779b7 100644 --- a/lispBM/lispBM/tests/Makefile +++ b/lispBM/lispBM/tests/Makefile @@ -5,7 +5,8 @@ LISPBM := ../ include $(LISPBM)/lispbm.mk PLATFORM_INCLUDE = -I$(LISPBM)/platform/linux/include -PLATFORM_SRC = $(LISPBM)/platform/linux/src/platform_mutex.c +PLATFORM_SRC = $(LISPBM)/platform/linux/src/platform_mutex.c \ + $(LISPBM)/platform/linux/src/platform_timestamp.c #CCFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wconversion -Wclobbered -pedantic -std=c99 diff --git a/lispBM/lispBM/tests/c_unit/Makefile b/lispBM/lispBM/tests/c_unit/Makefile index ef146d4051..0c1406ca64 100644 --- a/lispBM/lispBM/tests/c_unit/Makefile +++ b/lispBM/lispBM/tests/c_unit/Makefile @@ -5,7 +5,8 @@ LISPBM := ../../ include $(LISPBM)/lispbm.mk PLATFORM_INCLUDE = -I$(LISPBM)/platform/linux/include -PLATFORM_SRC = $(LISPBM)/platform/linux/src/platform_mutex.c +PLATFORM_SRC = $(LISPBM)/platform/linux/src/platform_mutex.c \ + $(LISPBM)/platform/linux/src/platform_timestamp.c #CCFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wconversion -Wclobbered -pedantic -std=c99 diff --git a/lispBM/lispBM/tests/c_unit/init/start_lispbm.c b/lispBM/lispBM/tests/c_unit/init/start_lispbm.c index 47f1b35a6b..219c7b2515 100644 --- a/lispBM/lispBM/tests/c_unit/init/start_lispbm.c +++ b/lispBM/lispBM/tests/c_unit/init/start_lispbm.c @@ -1,5 +1,6 @@ #include "extensions/lbm_dyn_lib.h" +#include "platform_timestamp.h" #define IMAGE_STORAGE_SIZE (128 * 1024) // bytes: #define IMAGE_FIXED_VIRTUAL_ADDRESS (void*)0xA0000000 @@ -45,12 +46,6 @@ void critical(void) { printf("CRITICAL ERROR\n"); } -uint32_t timestamp(void) { - struct timeval tv; - gettimeofday(&tv,NULL); - return (uint32_t)(tv.tv_sec * 1000000 + tv.tv_usec); -} - typedef struct done_cid_s { lbm_cid id; lbm_value r; @@ -124,10 +119,17 @@ bool dynamic_loader(const char *str, const char **code) { return lbm_dyn_lib_find(str, code); } +static pthread_t timestamp_thread = 0; pthread_t lispbm_thd = 0; int start_lispbm_for_tests(void) { + if (!timestamp_thread) { + pthread_create(×tamp_thread, NULL, timestamp_cacher, NULL); + } else { + printf("Timestamp thread is already running.\n"); + } + // Kill the evaluator if it already exists if (lispbm_thd && lbm_get_eval_state() != EVAL_CPS_STATE_DEAD) { lbm_kill_eval(); @@ -167,7 +169,6 @@ int start_lispbm_for_tests(void) { lbm_set_critical_error_callback(critical); lbm_set_ctx_done_callback(done_callback); - lbm_set_timestamp_us_callback(timestamp); lbm_set_usleep_callback(sleep_callback); lbm_set_printf_callback(error_print); lbm_set_dynamic_load_callback(dynamic_loader); diff --git a/lispBM/lispBM/tests/c_unit/test_channel.c b/lispBM/lispBM/tests/c_unit/test_channel.c index fde45e31d5..119f9c82ec 100644 --- a/lispBM/lispBM/tests/c_unit/test_channel.c +++ b/lispBM/lispBM/tests/c_unit/test_channel.c @@ -593,6 +593,101 @@ int test_buffered_char_channel_is_empty(void) { return 1; } +int test_buffered_char_channel_need_more(void) { + + const char *code = "(+ 1 2 3 (+ 1 2 3))"; + + char result[100]; + memset(result,0, 100); + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan1; + + lbm_create_buffered_char_channel(&bs, &chan1); + + for (int i = 0; i < strlen(code); i ++) { + lbm_channel_write(&chan1, code[i]); + + lbm_channel_read(&chan1, &result[i]); + char dummy; + lbm_channel_read(&chan1,&dummy); // should fail in a resumable way + } + + //printf("%s\n", result); + if (strncmp(code, result, strlen(code)) == 0) + return 1; + return 0; +} + +int test_buffered_char_channel_need_more_with_comment(void) { + + const char *code = "(+ 1 2 3 (+ 1 2 3))\n;; Hello world\n(print apa)"; + + char result[100]; + memset(result,0, 100); + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan1; + + lbm_create_buffered_char_channel(&bs, &chan1); + + for (int i = 0; i < strlen(code); i ++) { + lbm_channel_write(&chan1, code[i]); + + lbm_channel_read(&chan1, &result[i]); + char dummy; + lbm_channel_read(&chan1,&dummy); // should fail in a resumable way + } + + //printf("%s\n", result); + if (strncmp(code, result, strlen(code)) == 0) + return 1; + return 0; +} + + + +int test_string_char_channel_goes_full(void) { + + char str[10]; + memset(str,0,10); + lbm_string_channel_state_t st1; + lbm_char_channel_t chan1; + lbm_create_string_char_channel_size(&st1, &chan1, str, 10); + + if (lbm_channel_is_full(&chan1)) return 0; + + for (int i = 0; i < 10; i ++) { + lbm_channel_write(&chan1, 'a'); + } + + if (!lbm_channel_is_full(&chan1)) return 0; + + return 1; +} + +int test_string_char_channel_read_0_no_more(void) { + + char str[10]; + memset(str,0,10); + lbm_string_channel_state_t st1; + lbm_char_channel_t chan1; + lbm_create_string_char_channel_size(&st1, &chan1, str, 10); + + if (lbm_channel_is_full(&chan1)) return 0; + + for (int i = 0; i < 5; i ++) { + lbm_channel_write(&chan1, 'a'); + } + + char read_r; + for (int i = 0; i < 7; i ++) { + lbm_channel_read(&chan1, &read_r); + } + + if (lbm_channel_more(&chan1)) return 0; + + return 1; +} + // //////////////////////////////////////////////////////////// // run the tests @@ -624,7 +719,12 @@ int main(void) { total_tests++; if (test_buffered_char_channel_drop()) tests_passed++; total_tests++; if (test_buffered_char_channel_reader_closed_closed()) tests_passed++; total_tests++; if (test_buffered_char_channel_is_empty()) tests_passed++; - + total_tests++; if (test_buffered_char_channel_need_more()) tests_passed++; + total_tests++; if (test_buffered_char_channel_need_more_with_comment()) tests_passed++; + + total_tests++; if (test_string_char_channel_goes_full()) tests_passed++; + total_tests++; if (test_string_char_channel_read_0_no_more()) tests_passed++; + if (tests_passed == total_tests) { printf("SUCCESS\n"); return 0; diff --git a/lispBM/lispBM/tests/c_unit/test_eval_cps.c b/lispBM/lispBM/tests/c_unit/test_eval_cps.c index d713d09be1..53d71059e3 100644 --- a/lispBM/lispBM/tests/c_unit/test_eval_cps.c +++ b/lispBM/lispBM/tests/c_unit/test_eval_cps.c @@ -562,10 +562,7 @@ int test_callback_setters_null() { // Test lbm_set_usleep_callback with NULL lbm_set_usleep_callback(NULL); - - // Test lbm_set_timestamp_us_callback with NULL - lbm_set_timestamp_us_callback(NULL); - + // Test lbm_set_ctx_done_callback with NULL lbm_set_ctx_done_callback(NULL); diff --git a/lispBM/lispBM/tests/c_unit/test_heap_deep_recursive.c b/lispBM/lispBM/tests/c_unit/test_heap_deep_recursive.c new file mode 100644 index 0000000000..7288926b42 --- /dev/null +++ b/lispBM/lispBM/tests/c_unit/test_heap_deep_recursive.c @@ -0,0 +1,85 @@ +#define _GNU_SOURCE // MAP_ANON +#define _POSIX_C_SOURCE 200809L // nanosleep? +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lispbm.h" +#include "heap.h" + +#include "init/start_lispbm.c" + +static int test_init(void) { + return start_lispbm_for_tests(); +} + +int test_deep_recursive_gc_stack_overflow(void) { + if (!test_init()) return 0; + + // The GC stack size is 256 (from init/start_lispbm.c) + // Create a structure deeper than this to trigger GC stack overflow + const int depth = 512; // Twice the GC stack size + + printf("Creating deeply car-recursive structure with depth %d...\n", depth); + + lbm_value result = lbm_enc_i(42); // Base value at the bottom + + // Build the structure: (cons (cons (cons ... (cons 42 nil) nil) nil) nil) + // Each level nests deeper in the car position + + int timeout = 0; + + lbm_pause_eval(); + while (lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED && timeout < 5) { + sleep_callback(1000); + timeout++; + } + + // the cdr also has to be a cons for the stack usage to grow. + lbm_value cdr_val = lbm_cons(lbm_enc_i(42),lbm_enc_i(33)); + + for (int i = 0; i < depth; i++) { + result = lbm_cons(result, cdr_val); + if (lbm_is_symbol_merror(result)) { + printf("Memory allocation failed at depth %d\n", i); + return 0; + } + } + + if (!lbm_define("deep", result)) return 0; + + printf("Structure created successfully. Current GC stack size: %u\n", lbm_get_gc_stack_size()); + printf("Current GC stack max usage: %u\n", lbm_get_gc_stack_max()); + + // Force garbage collection which will attempt to traverse the deep structure + printf("Triggering garbage collection...\n"); + // lbm_gc_mark_phase(result); // This is illegal and would trigger longjmp undefined behavior. + lbm_request_gc(); // this is fine, GC called from evaluator thread. + lbm_continue_eval(); + + int thread_r; + // Test hangs if evaluator thread does not exit. + pthread_join(lispbm_thd, (void*)&thread_r); // The evaluator dies but there should be no crash. + + printf("Garbage collection completed without crash\n"); + printf("Post-GC stack max usage: %u\n", lbm_get_gc_stack_max()); + + return 1; +} + +int main(void) { + printf("Testing deep recursive structure that exceeds GC stack size...\n"); + + if (!test_deep_recursive_gc_stack_overflow()) { + printf("FAILURE: GC stack overflow test failed\n"); + return 1; + } + + printf("SUCCESS\n"); + return 0; +} diff --git a/lispBM/lispBM/tests/c_unit/test_tokpar.c b/lispBM/lispBM/tests/c_unit/test_tokpar.c new file mode 100644 index 0000000000..6d74a86164 --- /dev/null +++ b/lispBM/lispBM/tests/c_unit/test_tokpar.c @@ -0,0 +1,1209 @@ +#define _GNU_SOURCE // MAP_ANON +#define _POSIX_C_SOURCE 200809L // nanosleep? +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lispbm.h" +#include "tokpar.h" +#include "lbm_channel.h" + +#include "init/start_lispbm.c" + +// Helper function to write string to buffered channel +static void write_string_to_channel(lbm_char_channel_t *chan, const char *str) { + for (size_t i = 0; i < strlen(str); i++) { + lbm_channel_write(chan, str[i]); + } +} + +// Helper function to setup channel with data +static void setup_channel_with_data(lbm_buffered_channel_state_t *bs, + lbm_char_channel_t *chan, + const char *data) { + lbm_create_buffered_char_channel(bs, chan); + // Clear tokpar symbol string buffer + memset(tokpar_sym_str, 0, TOKENIZER_MAX_SYMBOL_AND_STRING_LENGTH + 1); + if (data) { + write_string_to_channel(chan, data); + // Close writer side to signal no more data is coming + lbm_channel_writer_close(chan); + } +} + +// Helper function to setup empty closed channel +static void setup_empty_closed_channel(lbm_buffered_channel_state_t *bs, + lbm_char_channel_t *chan) { + lbm_create_buffered_char_channel(bs, chan); + // Clear tokpar symbol string buffer + memset(tokpar_sym_str, 0, TOKENIZER_MAX_SYMBOL_AND_STRING_LENGTH + 1); + // Close writer side immediately to signal no more data is coming + lbm_channel_writer_close(chan); +} + +// //////////////////////////////////////////////////////////// +// tok_syntax tests + +int test_tok_syntax_no_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, NULL); + + uint32_t res; + int r = tok_syntax(&chan, &res); + + // Should return TOKENIZER_NEED_MORE when no data available + if (r != TOKENIZER_NEED_MORE) { + printf("FAIL: test_tok_syntax_no_data - expected %d, got %d\n", TOKENIZER_NEED_MORE, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_syntax_open_paren(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "("); + + uint32_t res; + int r = tok_syntax(&chan, &res); + + if (r != 1 || res != TOKOPENPAR) { + printf("FAIL: test_tok_syntax_open_paren - expected r=1, res=%u, got r=%d, res=%u\n", TOKOPENPAR, r, res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_syntax_close_paren(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, ")"); + + uint32_t res; + int r = tok_syntax(&chan, &res); + + if (r != 1 || res != TOKCLOSEPAR) { + printf("FAIL: test_tok_syntax_close_paren - expected r=1, res=%u, got r=%d, res=%u\n", TOKCLOSEPAR, r, res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_syntax_array_open(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "[|"); + + uint32_t res; + int r = tok_syntax(&chan, &res); + + if (r != 2 || res != TOKOPENARRAY) { + printf("FAIL: test_tok_syntax_array_open - expected r=2, res=%u, got r=%d, res=%u\n", TOKOPENARRAY, r, res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_syntax_invalid_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "abc"); + + uint32_t res; + int r = tok_syntax(&chan, &res); + + // Should return TOKENIZER_NO_TOKEN for non-syntax characters + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_syntax_invalid_data - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// tok_symbol tests + +int test_tok_symbol_no_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, NULL); + + int r = tok_symbol(&chan); + + if (r != TOKENIZER_NEED_MORE) { + printf("FAIL: test_tok_symbol_no_data - expected %d, got %d\n", TOKENIZER_NEED_MORE, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_symbol_valid_simple_delimiter(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + lbm_create_buffered_char_channel(&bs, &chan); + memset(tokpar_sym_str, 0, TOKENIZER_MAX_SYMBOL_AND_STRING_LENGTH + 1); + write_string_to_channel(&chan, "hello "); // Space delimiter, don't close channel + + int r = tok_symbol(&chan); + + if (r <= 0) { + printf("FAIL: test_tok_symbol_valid_simple_delimiter - expected positive return, got %d\n", r); + return 0; + } + if (strcmp(tokpar_sym_str, "hello") != 0) { + printf("FAIL: test_tok_symbol_valid_simple_delimiter - expected 'hello', got '%s'\n", tokpar_sym_str); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_symbol_valid_simple_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "hello"); // No delimiter, but channel closed + + int r = tok_symbol(&chan); + + if (r <= 0) { + printf("FAIL: test_tok_symbol_valid_simple_closed - expected positive return, got %d\n", r); + return 0; + } + if (strcmp(tokpar_sym_str, "hello") != 0) { + printf("FAIL: test_tok_symbol_valid_simple_closed - expected 'hello', got '%s'\n", tokpar_sym_str); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_symbol_invalid_start_number(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "123abc"); + + int r = tok_symbol(&chan); + + // Should return TOKENIZER_NO_TOKEN as symbols can't start with numbers + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_symbol_invalid_start_number - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// tok_string tests + +int test_tok_string_no_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, NULL); + + unsigned int string_len; + int r = tok_string(&chan, &string_len); + + if (r != TOKENIZER_NEED_MORE) { + printf("FAIL: test_tok_string_no_data - expected %d, got %d\n", TOKENIZER_NEED_MORE, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_string_valid_simple_delimiter(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + lbm_create_buffered_char_channel(&bs, &chan); + memset(tokpar_sym_str, 0, TOKENIZER_MAX_SYMBOL_AND_STRING_LENGTH + 1); + write_string_to_channel(&chan, "\"hello\" "); // Space delimiter after string + + unsigned int string_len; + int r = tok_string(&chan, &string_len); + + if (r <= 0) { + printf("FAIL: test_tok_string_valid_simple_delimiter - expected positive return, got %d\n", r); + return 0; + } + if (strcmp(tokpar_sym_str, "hello") != 0) { + printf("FAIL: test_tok_string_valid_simple_delimiter - expected 'hello', got '%s'\n", tokpar_sym_str); + return 0; + } + if (string_len != 5) { + printf("FAIL: test_tok_string_valid_simple_delimiter - expected length 5, got %u\n", string_len); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_string_valid_simple_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\"hello\""); // No delimiter, channel closed + + unsigned int string_len; + int r = tok_string(&chan, &string_len); + + if (r <= 0) { + printf("FAIL: test_tok_string_valid_simple_closed - expected positive return, got %d\n", r); + return 0; + } + if (strcmp(tokpar_sym_str, "hello") != 0) { + printf("FAIL: test_tok_string_valid_simple_closed - expected 'hello', got '%s'\n", tokpar_sym_str); + return 0; + } + if (string_len != 5) { + printf("FAIL: test_tok_string_valid_simple_closed - expected length 5, got %u\n", string_len); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_string_invalid_start(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "hello"); + + unsigned int string_len; + int r = tok_string(&chan, &string_len); + + // Should return TOKENIZER_NO_TOKEN as strings must start with quote + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_string_invalid_start - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// tok_char tests + +int test_tok_char_no_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, NULL); + + char res; + int r = tok_char(&chan, &res); + + if (r != TOKENIZER_NEED_MORE) { + printf("FAIL: test_tok_char_no_data - expected %d, got %d\n", TOKENIZER_NEED_MORE, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_valid_simple_delimiter(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + lbm_create_buffered_char_channel(&bs, &chan); + memset(tokpar_sym_str, 0, TOKENIZER_MAX_SYMBOL_AND_STRING_LENGTH + 1); + write_string_to_channel(&chan, "\\#a "); // Space delimiter + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_valid_simple_delimiter - expected positive return, got %d\n", r); + return 0; + } + if (res != 'a') { + printf("FAIL: test_tok_char_valid_simple_delimiter - expected 'a', got '%c'\n", res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_valid_simple_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#a"); // No delimiter, channel closed + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_valid_simple_closed - expected positive return, got %d\n", r); + return 0; + } + if (res != 'a') { + printf("FAIL: test_tok_char_valid_simple_closed - expected 'a', got '%c'\n", res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_null(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\0"); // \0 - null character + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_null - expected positive return, got %d\n", r); + return 0; + } + if (res != '\0') { + printf("FAIL: test_tok_char_escape_null - expected '\\0', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_bell(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\a"); // \a - bell character + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_bell - expected positive return, got %d\n", r); + return 0; + } + if (res != '\a') { + printf("FAIL: test_tok_char_escape_bell - expected '\\a', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_backspace(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\b"); // \b - backspace + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_backspace - expected positive return, got %d\n", r); + return 0; + } + if (res != '\b') { + printf("FAIL: test_tok_char_escape_backspace - expected '\\b', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_tab(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\t"); // \t - tab + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_tab - expected positive return, got %d\n", r); + return 0; + } + if (res != '\t') { + printf("FAIL: test_tok_char_escape_tab - expected '\\t', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_newline(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\n"); // \n - newline + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_newline - expected positive return, got %d\n", r); + return 0; + } + if (res != '\n') { + printf("FAIL: test_tok_char_escape_newline - expected '\\n', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_vtab(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\v"); // \v - vertical tab + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_vtab - expected positive return, got %d\n", r); + return 0; + } + if (res != '\v') { + printf("FAIL: test_tok_char_escape_vtab - expected '\\v', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_formfeed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\f"); // \f - formfeed + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_formfeed - expected positive return, got %d\n", r); + return 0; + } + if (res != '\f') { + printf("FAIL: test_tok_char_escape_formfeed - expected '\\f', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_carriage_return(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\r"); // \r - carriage return + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_carriage_return - expected positive return, got %d\n", r); + return 0; + } + if (res != '\r') { + printf("FAIL: test_tok_char_escape_carriage_return - expected '\\r', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_escape(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\e"); // \e - escape character (27) + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_escape - expected positive return, got %d\n", r); + return 0; + } + if (res != 27) { + printf("FAIL: test_tok_char_escape_escape - expected escape char (27), got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_space(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\s"); // \s - space character (32) + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_space - expected positive return, got %d\n", r); + return 0; + } + if (res != 32) { + printf("FAIL: test_tok_char_escape_space - expected space char (32), got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_quote(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\\""); // \" - double quote + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_quote - expected positive return, got %d\n", r); + return 0; + } + if (res != '\"') { + printf("FAIL: test_tok_char_escape_quote - expected '\"', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_backslash(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\\\"); // \\ - backslash + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_backslash - expected positive return, got %d\n", r); + return 0; + } + if (res != '\\') { + printf("FAIL: test_tok_char_escape_backslash - expected '\\', got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_delete(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\d"); // \d - delete character (127) + + char res; + int r = tok_char(&chan, &res); + + if (r <= 0) { + printf("FAIL: test_tok_char_escape_delete - expected positive return, got %d\n", r); + return 0; + } + if (res != 127) { + printf("FAIL: test_tok_char_escape_delete - expected delete char (127), got '%c' (%d)\n", res, (int)res); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_escape_invalid(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "\\#\\z"); // \z - invalid escape sequence + + char res; + int r = tok_char(&chan, &res); + + // Should return an error for invalid escape sequence + if (r >= 0) { + printf("FAIL: test_tok_char_escape_invalid - expected error, got %d\n", r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_invalid_start(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "abc"); + + char res; + int r = tok_char(&chan, &res); + + // Should return TOKENIZER_NO_TOKEN as chars must start with "#\" + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_char_invalid_start - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// tok_integer tests + +int test_tok_integer_no_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, NULL); + + token_int result; + int r = tok_integer(&chan, &result); + + if (r != TOKENIZER_NEED_MORE) { + printf("FAIL: test_tok_integer_no_data - expected %d, got %d\n", TOKENIZER_NEED_MORE, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_integer_positive(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "42"); + + token_int result; + int r = tok_integer(&chan, &result); + + if (r <= 0) { + printf("FAIL: test_tok_integer_positive - expected positive return, got %d\n", r); + return 0; + } + if (result.value != 42 || result.negative) { + printf("FAIL: test_tok_integer_positive - expected value=42, negative=false, got value=%llu, negative=%d\n", (unsigned long long)result.value, result.negative); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_integer_invalid_start(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "abc"); + + token_int result; + int r = tok_integer(&chan, &result); + + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_integer_invalid_start - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// tok_double tests + +int test_tok_double_no_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, NULL); + + token_float result; + int r = tok_double(&chan, &result); + + if (r != TOKENIZER_NEED_MORE) { + printf("FAIL: test_tok_double_no_data - expected %d, got %d\n", TOKENIZER_NEED_MORE, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_double_simple(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "3.14"); + + token_float result; + int r = tok_double(&chan, &result); + + if (r <= 0) { + printf("FAIL: test_tok_double_simple - expected positive return, got %d\n", r); + return 0; + } + if (result.value < 3.13 || result.value > 3.15) { + printf("FAIL: test_tok_double_simple - expected ~3.14, got %f\n", result.value); + return 0; + } + if (result.negative) { + printf("FAIL: test_tok_double_simple - expected negative=false, got %d\n", result.negative); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_double_invalid_start(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "abc"); + + token_float result; + int r = tok_double(&chan, &result); + + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_double_invalid_start - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// tok_clean_whitespace tests + +int test_tok_clean_whitespace_no_data(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, NULL); + + bool r = tok_clean_whitespace(&chan); + + // Should return false when no data available + if (r) { + printf("FAIL: test_tok_clean_whitespace_no_data - expected false when no data available\n"); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_clean_whitespace_spaces(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, " hello"); + + bool r = tok_clean_whitespace(&chan); + + if (!r) { + printf("FAIL: test_tok_clean_whitespace_spaces - expected true\n"); + return 0; + } + + // Check that 'h' is now the first character + char next_char; + if (!lbm_channel_read(&chan, &next_char)) { + printf("FAIL: test_tok_clean_whitespace_spaces - failed to read next character\n"); + return 0; + } + if (next_char != 'h') { + printf("FAIL: test_tok_clean_whitespace_spaces - expected 'h', got '%c'\n", next_char); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// Empty closed channel tests + +int test_tok_syntax_empty_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_empty_closed_channel(&bs, &chan); // Empty and closed + + uint32_t res; + int r = tok_syntax(&chan, &res); + + // Should return TOKENIZER_NO_TOKEN when channel is empty and closed + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_syntax_empty_closed - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_symbol_empty_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_empty_closed_channel(&bs, &chan); // Empty and closed + + int r = tok_symbol(&chan); + + // Should return TOKENIZER_NO_TOKEN when channel is empty and closed + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_symbol_empty_closed - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_string_empty_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_empty_closed_channel(&bs, &chan); // Empty and closed + + unsigned int string_len; + int r = tok_string(&chan, &string_len); + + // Should return TOKENIZER_NO_TOKEN when channel is empty and closed + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_string_empty_closed - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_char_empty_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_empty_closed_channel(&bs, &chan); // Empty and closed + + char res; + int r = tok_char(&chan, &res); + + // Should return TOKENIZER_NO_TOKEN when channel is empty and closed + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_char_empty_closed - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_integer_empty_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_empty_closed_channel(&bs, &chan); // Empty and closed + + token_int result; + int r = tok_integer(&chan, &result); + + // Should return TOKENIZER_NO_TOKEN when channel is empty and closed + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_integer_empty_closed - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_double_empty_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_empty_closed_channel(&bs, &chan); // Empty and closed + + token_float result; + int r = tok_double(&chan, &result); + + // Should return TOKENIZER_NO_TOKEN when channel is empty and closed + if (r != TOKENIZER_NO_TOKEN) { + printf("FAIL: test_tok_double_empty_closed - expected %d, got %d\n", TOKENIZER_NO_TOKEN, r); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +int test_tok_clean_whitespace_empty_closed(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_empty_closed_channel(&bs, &chan); // Empty and closed + + bool r = tok_clean_whitespace(&chan); + + // Should return true when channel is empty and closed (cleaning is complete) + if (!r) { + printf("FAIL: test_tok_clean_whitespace_empty_closed - expected true when channel is empty and closed\n"); + return 0; + } + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// Integration test + +int test_tokenize_simple_expression(void) { + if (!start_lispbm_for_tests()) return 0; + + lbm_buffered_channel_state_t bs; + lbm_char_channel_t chan; + setup_channel_with_data(&bs, &chan, "(+ 1 2)"); + int n = 0; + + // Should tokenize as: ( + 1 2 ) + uint32_t syntax_res; + token_int int_res; + + // Test opening paren + tok_clean_whitespace(&chan); + n = tok_syntax(&chan, &syntax_res); + if ( n <= 0 || syntax_res != TOKOPENPAR) { + printf("FAIL: test_tokenize_simple_expression - step 1 (open paren)\n"); + return 0; + } + lbm_channel_drop(&chan, (unsigned int) n); + + // Test symbol + + tok_clean_whitespace(&chan); + n = tok_symbol(&chan); + if (n <= 0 || strncmp(tokpar_sym_str, "+", 1) != 0) { + printf("FAIL: test_tokenize_simple_expression - step 2 (+ symbol), got '%s'\n", tokpar_sym_str); + return 0; + } + lbm_channel_drop(&chan, (unsigned int) n); + + // Test integer 1 + tok_clean_whitespace(&chan); + n = tok_integer(&chan, &int_res); + if (n <= 0 || int_res.value != 1) { + printf("FAIL: test_tokenize_simple_expression - step 3 (integer 1), got %llu\n", (unsigned long long)int_res.value); + return 0; + } + lbm_channel_drop(&chan, (unsigned int) n); + + // Test integer 2 + tok_clean_whitespace(&chan); + n = tok_integer(&chan, &int_res); + if (n <= 0 || int_res.value != 2) { + printf("FAIL: test_tokenize_simple_expression - step 4 (integer 2), got %llu\n", (unsigned long long)int_res.value); + return 0; + } + lbm_channel_drop(&chan, (unsigned int) n); + + // Test closing paren + tok_clean_whitespace(&chan); + n = tok_syntax(&chan, &syntax_res); + if (n <= 0 || syntax_res != TOKCLOSEPAR) { + printf("FAIL: test_tokenize_simple_expression - step 5 (close paren)\n"); + return 0; + } + lbm_channel_drop(&chan, (unsigned int) n); + + kill_eval_after_tests(); + return 1; +} + +// //////////////////////////////////////////////////////////// +// run the tests +int main(void) { + int tests_passed = 0; + int total_tests = 0; + + // tok_syntax tests + total_tests++; if (test_tok_syntax_no_data()) tests_passed++; + total_tests++; if (test_tok_syntax_open_paren()) tests_passed++; + total_tests++; if (test_tok_syntax_close_paren()) tests_passed++; + total_tests++; if (test_tok_syntax_array_open()) tests_passed++; + total_tests++; if (test_tok_syntax_invalid_data()) tests_passed++; + + // tok_symbol tests + total_tests++; if (test_tok_symbol_no_data()) tests_passed++; + total_tests++; if (test_tok_symbol_valid_simple_delimiter()) tests_passed++; + total_tests++; if (test_tok_symbol_valid_simple_closed()) tests_passed++; + total_tests++; if (test_tok_symbol_invalid_start_number()) tests_passed++; + + // tok_string tests + total_tests++; if (test_tok_string_no_data()) tests_passed++; + total_tests++; if (test_tok_string_valid_simple_delimiter()) tests_passed++; + total_tests++; if (test_tok_string_valid_simple_closed()) tests_passed++; + total_tests++; if (test_tok_string_invalid_start()) tests_passed++; + + // tok_char tests + total_tests++; if (test_tok_char_no_data()) tests_passed++; + total_tests++; if (test_tok_char_valid_simple_delimiter()) tests_passed++; + total_tests++; if (test_tok_char_valid_simple_closed()) tests_passed++; + total_tests++; if (test_tok_char_escape_null()) tests_passed++; + total_tests++; if (test_tok_char_escape_bell()) tests_passed++; + total_tests++; if (test_tok_char_escape_backspace()) tests_passed++; + total_tests++; if (test_tok_char_escape_tab()) tests_passed++; + total_tests++; if (test_tok_char_escape_newline()) tests_passed++; + total_tests++; if (test_tok_char_escape_vtab()) tests_passed++; + total_tests++; if (test_tok_char_escape_formfeed()) tests_passed++; + total_tests++; if (test_tok_char_escape_carriage_return()) tests_passed++; + total_tests++; if (test_tok_char_escape_escape()) tests_passed++; + total_tests++; if (test_tok_char_escape_space()) tests_passed++; + total_tests++; if (test_tok_char_escape_quote()) tests_passed++; + total_tests++; if (test_tok_char_escape_backslash()) tests_passed++; + total_tests++; if (test_tok_char_escape_delete()) tests_passed++; + total_tests++; if (test_tok_char_escape_invalid()) tests_passed++; + total_tests++; if (test_tok_char_invalid_start()) tests_passed++; + + // tok_integer tests + total_tests++; if (test_tok_integer_no_data()) tests_passed++; + total_tests++; if (test_tok_integer_positive()) tests_passed++; + total_tests++; if (test_tok_integer_invalid_start()) tests_passed++; + + // tok_double tests + total_tests++; if (test_tok_double_no_data()) tests_passed++; + total_tests++; if (test_tok_double_simple()) tests_passed++; + total_tests++; if (test_tok_double_invalid_start()) tests_passed++; + + // tok_clean_whitespace tests + total_tests++; if (test_tok_clean_whitespace_no_data()) tests_passed++; + total_tests++; if (test_tok_clean_whitespace_spaces()) tests_passed++; + + // Empty closed channel tests + total_tests++; if (test_tok_syntax_empty_closed()) tests_passed++; + total_tests++; if (test_tok_symbol_empty_closed()) tests_passed++; + total_tests++; if (test_tok_string_empty_closed()) tests_passed++; + total_tests++; if (test_tok_char_empty_closed()) tests_passed++; + total_tests++; if (test_tok_integer_empty_closed()) tests_passed++; + total_tests++; if (test_tok_double_empty_closed()) tests_passed++; + total_tests++; if (test_tok_clean_whitespace_empty_closed()) tests_passed++; + + // Integration tests + total_tests++; if (test_tokenize_simple_expression()) tests_passed++; + + if (tests_passed == total_tests) { + printf("SUCCESS\n"); + return 0; + } else { + printf("FAILED: %d/%d tests passed\n", tests_passed, total_tests); + return 1; + } +} diff --git a/lispBM/lispBM/tests/image_tests/test_const_floats_1.lisp b/lispBM/lispBM/tests/image_tests/test_const_floats_1.lisp new file mode 100644 index 0000000000..c7b488cc5c --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_const_floats_1.lisp @@ -0,0 +1,51 @@ + +(def r 0) + +(def my-f1 3.14) +(def my-fl1 (list 3.14 6.28 100.0)) + +(def t1 (list 1 2 3)) +(def t2 (list t1 t1)) +(def t3 (list t2 t2)) + +@const-start + +(def ct1 (list 1 2 3)) +(def ct2 (list ct1 ct1)) +(def ct3 (list ct2 ct2)) + +(define feq (lambda (a b epsilon) + (< (abs (- a b)) epsilon))) + +(def my-f2 3.14) +(def my-fl2 (list 3.14 6.28 100.0)) + +(defun f () { + (looprange i 0 100 { + ;;(print i) + (setq r i) + }) + r + }) + +(defun main () { + (if (and (= (f) 99) + (feq my-f1 3.14 0.001) + (feq my-f2 3.14 0.001) + (feq (ix my-fl1 2) 100.0 0.001) + (feq (ix my-fl2 2) 100.0 0.001)) + + + (print "SUCCESS") + (print "FAILURE") + ) + (print t3) + (print ct3) + }) + +@const-end + +(print "a " t3) +(print "a " ct3) +(image-save) +(fwrite-image (fopen "image.lbm" "w")) diff --git a/lispBM/lispBM/tests/image_tests/test_looprange_1.lisp b/lispBM/lispBM/tests/image_tests/test_looprange_1.lisp new file mode 100644 index 0000000000..4254290ec1 --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_looprange_1.lisp @@ -0,0 +1,54 @@ + +(def a 0) +(def s 0) +(def e 100) +(def r 0) + +(def waste (range 1000)) + +@const-start + +(define apa "-----------------------------------------------------------") + +(defun g () { + (loopwhile r { + (if (= r 100) + (setq r nil) + (setq r (+ r 1))) + }) + r + }) + +(defun f (x y z) { + (var e (+ x y z)) + (looprange i 0 e + (setq a i) + ) + a + }) + +(defun h (i j k) { + (var e (+ i j k)) + (looprange i 100 (+ e 100) + (setq a i) + ) + (print "h " r) + a + }) + + + +(defun main () { + (print (g)) + (print apa) + (if (and (= (f 1 1 98) 99) + (= (h 1 1 98) 199)) + (print "SUCCESS") + (print "FAILURE")) + }) + +@const-end + +(print "Saving image") +(image-save) +(fwrite-image (fopen "image.lbm" "w")) diff --git a/lispBM/lispBM/tests/image_tests/test_macro_created_sharing.lisp b/lispBM/lispBM/tests/image_tests/test_macro_created_sharing.lisp new file mode 100644 index 0000000000..d055023c57 --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_macro_created_sharing.lisp @@ -0,0 +1,16 @@ + + + +;; Does not lead to shared nodes. +(define m (macro (c0) + `(+ ,c0 ,c0))) + +(defun main () + (if (= (m (+ 1 2)) 6) + (print "SUCCESS") + (print "FAILURE"))) + +(image-save) +(fwrite-image (fopen "image.lbm" "w")) + + diff --git a/lispBM/lispBM/tests/image_tests/test_program_with_sharing.lisp b/lispBM/lispBM/tests/image_tests/test_program_with_sharing.lisp new file mode 100644 index 0000000000..07dd5f51ad --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_program_with_sharing.lisp @@ -0,0 +1,16 @@ + + +(def a '(+ 1 0)) +(def b `(+ ,a ,a)) + +(defun f (x) (eval `(+ x ,b))) + +(setix a 2 2) + +(defun main () + (if (eq (f 1) 7) + (print "SUCCESS") + (print "FAILURE"))) + +(image-save) +(fwrite-image (fopen "image.lbm" "w")) diff --git a/lispBM/lispBM/tests/image_tests/test_program_with_sharing_2.lisp b/lispBM/lispBM/tests/image_tests/test_program_with_sharing_2.lisp new file mode 100644 index 0000000000..375808459d --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_program_with_sharing_2.lisp @@ -0,0 +1,18 @@ + +(def l (list 1 2 3 4)) + +;; The usage of l in two places here is not +;; treated as sharing. The are simply occurrences +;; the symbol l to be looked up in the environemnt at runtime, +;; not a direct reference to the address of the list. +(defun f () (+ (apply + l) (apply + l))) + + + +(defun main () + (if (eq (f) 20) + (print "SUCCESS") + (print "FAILURE"))) + +(image-save) +(fwrite-image (fopen "image.lbm" "w")) diff --git a/lispBM/lispBM/tests/image_tests/test_tree_recreation.lisp b/lispBM/lispBM/tests/image_tests/test_tree_recreation.lisp new file mode 100644 index 0000000000..f032d2df90 --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_tree_recreation.lisp @@ -0,0 +1,16 @@ + +;; Test tree with sharing +(def t1 (list 1 2 3)) +(def t11 (list 4 5 6)) +(def t2 (list t1 t11)) +(def t3 (list t2 t2)) + +(defun main () { + (if (eq t3 '(((1 2 3) (4 5 6)) ((1 2 3) (4 5 6)))) + (print "SUCCESS") + (print "FAILURE") + ) + }) + +(image-save) +(fwrite-image (fopen "image.lbm" "w")) diff --git a/lispBM/lispBM/tests/image_tests/test_tree_recreation_2.lisp b/lispBM/lispBM/tests/image_tests/test_tree_recreation_2.lisp new file mode 100644 index 0000000000..abbb36b8db --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_tree_recreation_2.lisp @@ -0,0 +1,14 @@ + +;; Test tree without sharing +(def tree '(((1 2 3) (4 5 6)) ((1 2 3) (4 5 6)))) + +(defun main () { + (print tree) + (if (eq tree '(((1 2 3) (4 5 6)) ((1 2 3) (4 5 6)))) + (print "SUCCESS") + (print "FAILURE") + ) + }) + +(image-save) +(fwrite-image (fopen "image.lbm" "w")) diff --git a/lispBM/lispBM/tests/image_tests/test_tree_recreation_3.lisp b/lispBM/lispBM/tests/image_tests/test_tree_recreation_3.lisp new file mode 100644 index 0000000000..8ec468d091 --- /dev/null +++ b/lispBM/lispBM/tests/image_tests/test_tree_recreation_3.lisp @@ -0,0 +1,22 @@ + +;; Test tree with sharing +(def t1 (list 1 2 3)) +(def t11 (list 4 5 6)) +(def t2 (list t1 t11)) +(def t3 (list t2 t2)) + +(def lt (list t3 t3 t3 t3)) + +(defun main () { + (if (and (eq (ix lt 0) '(((1 2 3) (4 5 6)) ((1 2 3) (4 5 6)))) + (eq (ix lt 1) '(((1 2 3) (4 5 6)) ((1 2 3) (4 5 6)))) + (eq (ix lt 2) '(((1 2 3) (4 5 6)) ((1 2 3) (4 5 6)))) + (eq (ix lt 3) '(((1 2 3) (4 5 6)) ((1 2 3) (4 5 6))))) + + (print "SUCCESS") + (print "FAILURE") + ) + }) + +(image-save) +(fwrite-image (fopen "image.lbm" "w")) diff --git a/lispBM/lispBM/tests/perform_image_test.sh b/lispBM/lispBM/tests/perform_image_test.sh new file mode 100755 index 0000000000..7d48e29b15 --- /dev/null +++ b/lispBM/lispBM/tests/perform_image_test.sh @@ -0,0 +1,7 @@ + +../repl/repl_cov --terminate -s $1 + +../repl/repl_cov --silent --terminate --load_image=image.lbm -e "(main)" + + + diff --git a/lispBM/lispBM/tests/qq_compare_guile.sh b/lispBM/lispBM/tests/qq_compare_guile.sh new file mode 100755 index 0000000000..63b917e205 --- /dev/null +++ b/lispBM/lispBM/tests/qq_compare_guile.sh @@ -0,0 +1,169 @@ +#!/bin/bash + +# Test 10 is semantically equivalent if the environment would have a binding of a. + +# Array of test expressions +test_expressions=( + '`(,@(list 1 2 3))' + '`(a ,@(list 1 2) b)' + '`(,@())' + '`(1 ,@(list 2 3) 4)' + '``(a ,,(+ 1 2))' + '`(quote ,@(list 1 2))' + '`(,@(cdr (quote (0 1 2 3))))' + '`(list ,@(list 1 2 3))' + "\`,'a" + "\`\`,a" + "\`,\`a" + "\`(1 . 2)" + "\`',(car ())" + "\`(,1 ,2 . ,3)" + "\`(,@nil ,1)" + "\`(1 2 ,@() ,@() 3)" + "\`\`(,,@(list 0 1 2))" + "\`\`(,,@(cdr '(0 1 2 3)) ,4)" + "\`\`(1 2 ,,@() ,,@())" + "\`\`(a ,,(+ 1 2) ,(+ 3 4))" + "\`5" + "\`,5" + "(let ((x 5)) \`(let ((x ,(+ x 10))) \`(list ,,x ,x)))" + "\`,@0" + "\`(1 2 ,@'(3 . 4))" + "\`(1 2 ,@(list 3 4 5) ,@(list 6 7 8) 9 10)" + "\`(1 2 ,@'() ,@'() 3)" + "\`\`(1 2 ,,@'() ,,@'())" + "\`(list 1 \`(,@(list 1 2 3) \`(,@(list 4 5 6))))" + +) + +# Array of expressions known to have expected differences +# These won't count as test failures +expected_differences=( + '`(,@())' # Guile errors, LispBM returns nil +) + +total_tests=0 +matching_tests=0 +differing_tests=0 +expected_diffs=0 + +echo "Running quasiquote comparison tests between Guile and LispBM" +echo "============================================================" +echo + +is_expected_difference() { + local expr="$1" + for expected in "${expected_differences[@]}"; do + if [ "$expr" = "$expected" ]; then + return 0 + fi + done + return 1 +} + +test_expression() { + local expr="$1" + total_tests=$((total_tests + 1)) + + echo "Test $total_tests: $expr" + + #emacs lisp test + # echo -n " Emacs: " + # if emacs_result=$(emacs --batch --eval "(prin1 $expr)" 2>/dev/null); then + # echo "$emacs_result" + # else + # emacs_result="ERROR" + # echo "ERROR or unsupported" + # fi + + # Guile test + echo -n " Guile: " + if guile_result=$(guile -c "(display $expr)" 2>/dev/null); then + echo "$guile_result" + else + guile_result="ERROR" + echo "ERROR or unsupported" + fi + + # LispBM test + echo -n " LispBM: " + if lbm_result=$(cd /home/joels/Current/lispbm && ./repl/repl -e "$expr" --terminate 2>/dev/null | grep -v "Image\|version\|creating\|Lisp REPL\|Type\|Goodbye" | tail -1 | sed 's/^> //'); then + echo "$lbm_result" + else + lbm_result="ERROR" + echo "ERROR or unsupported" + fi + + # Compare results + if [ "$guile_result" = "$lbm_result" ]; then + echo " Result: MATCH" + matching_tests=$((matching_tests + 1)) + elif [ "$guile_result" = "ERROR" ] || [ "$lbm_result" = "ERROR" ]; then + if is_expected_difference "$expr"; then + echo " Result: EXPECTED DIFFER (Known difference)" + expected_diffs=$((expected_diffs + 1)) + else + echo " Result: DIFFER (Error in one system)" + differing_tests=$((differing_tests + 1)) + fi + else + echo " Result: DIFFER - Testing semantic equivalence..." + + # Test if both expressions evaluate to the same result + echo -n " Guile eval: " + if guile_eval=$(guile -c "(display (eval '$guile_result (interaction-environment)))" 2>/dev/null); then + echo "$guile_eval" + else + guile_eval="ERROR" + echo "ERROR" + fi + + echo -n " LispBM eval: " + if lbm_eval=$(cd /home/joels/Current/lispbm && ./repl/repl -e "(eval '$lbm_result)" --terminate 2>/dev/null | grep -v "Image\|version\|creating\|Lisp REPL\|Type\|Goodbye" | tail -1 | sed 's/^> //'); then + echo "$lbm_eval" + else + lbm_eval="ERROR" + echo "ERROR" + fi + + # Compare evaluated results + if [ "$guile_eval" = "$lbm_eval" ] && [ "$guile_eval" != "ERROR" ]; then + echo " Result: SEMANTIC MATCH" + matching_tests=$((matching_tests + 1)) + else + if is_expected_difference "$expr"; then + echo " Result: EXPECTED SEMANTIC DIFFER (Known difference)" + expected_diffs=$((expected_diffs + 1)) + else + echo " Result: SEMANTIC DIFFER" + differing_tests=$((differing_tests + 1)) + fi + fi + fi + echo +} + +# Run all tests +for expr in "${test_expressions[@]}"; do + test_expression "$expr" +done + +# Summary +echo "============================================================" +echo "Summary:" +echo " Total tests: $total_tests" +echo " Matching: $matching_tests" +echo " Expected differences: $expected_diffs" +echo " Unexpected differences: $differing_tests" + +if [ $differing_tests -eq 0 ]; then + echo " Result: ALL TESTS PASSED" + if [ $expected_diffs -gt 0 ]; then + echo " Expected diffs: $expected_diffs" + fi + exit 0 +else + echo " Result: $differing_tests TESTS FAILED" + exit 1 +fi + diff --git a/lispBM/lispBM/tests/repl_tests/test_array_extensions_endianness.lisp b/lispBM/lispBM/tests/repl_tests/test_array_extensions_endianness.lisp new file mode 100644 index 0000000000..d8a2ee97e3 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_array_extensions_endianness.lisp @@ -0,0 +1,150 @@ +;; Test cases for array extensions endianness functionality +;; These tests target the little-endian/big-endian code paths + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +;; Create a test buffer for operations +(define test-buf (bufcreate 32)) + +;; Test bufset operations with little-endian flag + +;; Test bufset-i16 with little-endian +(define r1 (and (bufset-i16 test-buf 0 0x1234 'little-endian) + (= (bufget-u8 test-buf 0) 0x34) + (= (bufget-u8 test-buf 1) 0x12))) +(debug_test r1 1) + +;; Test bufset-i16 with big-endian (default) +(define r2 (and (bufset-i16 test-buf 2 0x1234) + (= (bufget-u8 test-buf 2) 0x12) + (= (bufget-u8 test-buf 3) 0x34))) +(debug_test r2 2) + +;; Test bufset-i32 with little-endian +(define r3 (and (bufset-i32 test-buf 4 0x12345678u32 'little-endian) + (= (bufget-u8 test-buf 4) 0x78) + (= (bufget-u8 test-buf 5) 0x56) + (= (bufget-u8 test-buf 6) 0x34) + (= (bufget-u8 test-buf 7) 0x12))) +(debug_test r3 3) + +;; Test bufset-i32 with big-endian (default) +(define r4 (and (bufset-i32 test-buf 8 0x12345678u32) + (= (bufget-u8 test-buf 8) 0x12) + (= (bufget-u8 test-buf 9) 0x34) + (= (bufget-u8 test-buf 10) 0x56) + (= (bufget-u8 test-buf 11) 0x78))) +(debug_test r4 4) + +;; Test bufset-u16 with little-endian +(define r5 (and (bufset-u16 test-buf 12 0xABCD 'little-endian) + (= (bufget-u8 test-buf 12) 0xCD) + (= (bufget-u8 test-buf 13) 0xAB))) +(debug_test r5 5) + +;; Test bufset-u16 with big-endian (default) +(define r6 (and (bufset-u16 test-buf 14 0xABCD) + (= (bufget-u8 test-buf 14) 0xAB) + (= (bufget-u8 test-buf 15) 0xCD))) +(debug_test r6 6) + +;; Test bufset-u24 with little-endian +(define r7 (and (bufset-u24 test-buf 16 0x123456 'little-endian) + (= (bufget-u8 test-buf 16) 0x56) + (= (bufget-u8 test-buf 17) 0x34) + (= (bufget-u8 test-buf 18) 0x12))) +(debug_test r7 7) + +;; Test bufset-u24 with big-endian (default) +(define r8 (and (bufset-u24 test-buf 19 0x123456) + (= (bufget-u8 test-buf 19) 0x12) + (= (bufget-u8 test-buf 20) 0x34) + (= (bufget-u8 test-buf 21) 0x56))) +(debug_test r8 8) + +;; Test bufset-u32 with little-endian +(define r9 (and (bufset-u32 test-buf 22 0x12345678u32 'little-endian) + (= (bufget-u8 test-buf 22) 0x78) + (= (bufget-u8 test-buf 23) 0x56) + (= (bufget-u8 test-buf 24) 0x34) + (= (bufget-u8 test-buf 25) 0x12))) +(debug_test r9 9) + +;; Test bufset-u32 with big-endian (default) +(define r10 (and (bufset-u32 test-buf 26 0x12345678u32) + (= (bufget-u8 test-buf 26) 0x12) + (= (bufget-u8 test-buf 27) 0x34) + (= (bufget-u8 test-buf 28) 0x56) + (= (bufget-u8 test-buf 29) 0x78))) +(debug_test r10 10) + +;; Test bufset-f32 with little-endian +(define test-buf2 (bufcreate 16)) +(define r11 (and (bufset-f32 test-buf2 0 3.14159f32 'little-endian) + (bufset-f32 test-buf2 4 3.14159f32) + (= (bufget-u32 test-buf2 0 'little-endian) + (bufget-u32 test-buf2 4)))) +(debug_test r11 11) + +;; Test bufget operations with endianness + +;; Set up test data for gets +(define get-buf (bufcreate 16)) +(bufset-u8 get-buf 0 0x12) +(bufset-u8 get-buf 1 0x34) +(bufset-u8 get-buf 2 0x56) +(bufset-u8 get-buf 3 0x78) +(bufset-u8 get-buf 4 0x9A) +(bufset-u8 get-buf 5 0xBC) +(bufset-u8 get-buf 6 0xDE) +(bufset-u8 get-buf 7 0xF0) + +;; Test bufget-i16 with little-endian vs big-endian +(define r12 (and (= (bufget-i16 get-buf 0 'little-endian) 0x3412) + (= (bufget-i16 get-buf 0) 0x1234))) +(debug_test r12 12) + +;; Test bufget-i32 with little-endian vs big-endian +(define r13 (and (= (bufget-i32 get-buf 0 'little-endian) 0x78563412) + (= (bufget-i32 get-buf 0) 0x12345678))) +(debug_test r13 13) + +;; Test bufget-u16 with little-endian vs big-endian +(define r14 (and (= (bufget-u16 get-buf 0 'little-endian) 0x3412) + (= (bufget-u16 get-buf 0) 0x1234))) +(debug_test r14 14) + +;; Test bufget-u24 with little-endian vs big-endian +(define r15 (and (= (bufget-u24 get-buf 0 'little-endian) 0x563412) + (= (bufget-u24 get-buf 0) 0x123456))) +(debug_test r15 15) + +;; Test bufget-u32 with little-endian vs big-endian +(define r16 (and (= (bufget-u32 get-buf 0 'little-endian) 0x78563412u32) + (= (bufget-u32 get-buf 0) 0x12345678u32))) +(debug_test r16 16) + +;; Test bufget-f32 with different endianness +(define f32-buf (bufcreate 8)) +(bufset-f32 f32-buf 0 1.5f32 'little-endian) +(bufset-f32 f32-buf 4 1.5f32) +(define r17 (not (= (bufget-f32 f32-buf 0 'little-endian) + (bufget-f32 f32-buf 4 'little-endian)))) +(debug_test r17 17) + +;; Test that 'big-endian symbol also works (should be same as default) +(define r18 (= (bufget-u16 get-buf 0 'big-endian) + (bufget-u16 get-buf 0))) +(debug_test r18 18) + +;; Test invalid endianness symbol (should use default) +(define r19 (= (bufget-u16 get-buf 0 'invalid-endian) + (bufget-u16 get-buf 0))) +(debug_test r19 19) + +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_array_extensions_error_cases.lisp b/lispBM/lispBM/tests/repl_tests/test_array_extensions_error_cases.lisp new file mode 100644 index 0000000000..0d080021d2 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_array_extensions_error_cases.lisp @@ -0,0 +1,190 @@ +;; Test cases targeting ENC_SYM_EERROR and ENC_SYM_TERROR returns in array extensions +;; These tests specifically target uncovered error handling paths + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +;; Create a test buffer for operations +(define test-buf (bufcreate 32)) + +;; Test free with wrong argument count (no args) +(define r1 (eq (trap (free)) '(exit-error eval_error))) +(debug_test r1 1) + +;; Test free with wrong argument count (too many args) +(define r2 (eq (trap (free test-buf "extra")) '(exit-error eval_error))) +(debug_test r2 2) + +;; Test free with wrong argument type (not an array) +(define r3 (eq (trap (free 42)) '(exit-error type_error))) +(debug_test r3 3) + +;; Test free with read-only array (should succeed but return nil) + +@const-start +(define read-only-str "readonly") +@const-end + +(define r4 (eq (trap (free read-only-str)) '(exit-error type_error))) +(debug_test r4 4) + +;; Test bufset operations with wrong argument counts +;; bufset functions need 3 or 4 args (buffer, index, value, [endianness]) + +;; Test bufset-i8 with wrong argument count (too few) +(define r5 (eq (ix (trap (bufset-i8 test-buf)) 0) 'exit-error)) +(debug_test r5 5) + +;; Test bufset-i8 with wrong argument count (too many) +(define r6 (eq (ix (trap (bufset-i8 test-buf 0 42 'little-endian "extra")) 0) 'exit-error)) +(debug_test r6 6) + +;; Test bufset-i8 with non-array first argument +(define r7 (eq (trap (bufset-i8 42 0 100)) '(exit-error type_error))) +(debug_test r7 7) + +;; Test bufset-i8 with non-number index +(define r8 (eq (trap (bufset-i8 test-buf 'not-a-number 100)) '(exit-error type_error))) +(debug_test r8 8) + +;; Test bufset-i8 with non-number value +(define r9 (eq (trap (bufset-i8 test-buf 0 'not-a-number)) '(exit-error type_error))) +(debug_test r9 9) + +;; Test "a string is a buffer". This is fine. +(define r10 (eq (bufset-i16 "not-array" 0 100) t)) +(debug_test r10 10) + +;; Test bufset-i32 with wrong types +(define r11 (eq (trap (bufset-i32 test-buf 'not-index 100)) '(exit-error type_error))) +(debug_test r11 11) + +;; Test bufset-u8 with wrong types +(define r12 (eq (trap (bufset-u8 test-buf 0 'not-value)) '(exit-error type_error))) +(debug_test r12 12) + +;; Test bufset-u16 with wrong argument count +(define r13 (eq (ix (trap (bufset-u16 test-buf)) 0) 'exit-error)) +(debug_test r13 13) + +;; Test bufset-u24 with wrong types +(define r14 (eq (trap (bufset-u24 42 0 100)) '(exit-error type_error))) +(debug_test r14 14) + +;; Test bufset-u32 with wrong types +(define r15 (eq (trap (bufset-u32 test-buf 'not-number 100)) '(exit-error type_error))) +(debug_test r15 15) + +;; Test bufset-f32 with wrong types +(define r16 (eq (trap (bufset-f32 test-buf 0 'not-float)) '(exit-error type_error))) +(debug_test r16 16) + +;; Test bufget operations with wrong argument counts and types +;; bufget functions need 2 or 3 args (buffer, index, [endianness]) + +;; Test bufget-i8 with wrong argument count (no args) +(define r17 (eq (ix (trap (bufget-i8)) 0) 'exit-error)) +(debug_test r17 17) + +;; Test bufget-i8 with wrong argument count (too many) +(define r18 (eq (ix (trap (bufget-i8 test-buf 0 'little-endian "extra")) 0) 'exit-error)) +(debug_test r18 18) + +;; Test bufget-i8 with non-array first argument +(define r19 (eq (trap (bufget-i8 42 0)) '(exit-error type_error))) +(debug_test r19 19) + +;; Test bufget-i8 with non-number index +(define r20 (eq (trap (bufget-i8 test-buf 'not-a-number)) '(exit-error type_error))) +(debug_test r20 20) + +;; Test "string is buffer" - this is OK! +(define r21 (eq (bufget-i16 "not-array" 0) 28271)) +(debug_test r21 21) + +;; Test bufget-i32 with wrong types +(define r22 (eq (trap (bufget-i32 test-buf 'not-index)) '(exit-error type_error))) +(debug_test r22 22) + +;; Test bufget-u8 with wrong types +(define r23 (eq (trap (bufget-u8 42 0)) '(exit-error type_error))) +(debug_test r23 23) + +;; Test bufget-u16 with wrong argument count +(define r24 (eq (ix (trap (bufget-u16)) 0) 'exit-error)) +(debug_test r24 24) + +;; Test bufget-u24 with wrong types +(define r25 (eq (trap (bufget-u24 test-buf 'not-number)) '(exit-error type_error))) +(debug_test r25 25) + +;; Test "string is buffer" - This is ok! +(define r26 (eq (bufget-u32 "not-buffer" 0) 1852797997u32)) +(debug_test r26 26) + +;; Test bufget-f32 with wrong types +(define r27 (eq (trap (bufget-f32 test-buf 'not-index)) '(exit-error type_error))) +(debug_test r27 27) + +;; Test buflen with wrong argument count (no args) +(define r28 (eq (ix (trap (buflen)) 0) 'exit-error)) +(debug_test r28 28) + +;; Test buflen with wrong argument type +(define r29 (eq (trap (buflen 42)) '(exit-error eval_error))) +(debug_test r29 29) + +;; Test bufclear with wrong argument count (no args) +(define r30 (eq (ix (trap (bufclear)) 0) 'exit-error)) +(debug_test r30 30) + +;; Test bufclear with wrong argument count (too many args) +(define r31 (eq (ix (trap (bufclear test-buf 0 0 0 "extra")) 0) 'exit-error)) +(debug_test r31 31) + +;; Test bufclear with non-array first argument +(define r32 (eq (trap (bufclear 42)) '(exit-error type_error))) +(debug_test r32 32) + +;; Test bufclear with non-number clear byte +(define r33 (eq (trap (bufclear test-buf 'not-number)) '(exit-error type_error))) +(debug_test r33 33) + +;; Test bufclear with non-number start position +(define r34 (eq (trap (bufclear test-buf 0 'not-number)) '(exit-error type_error))) +(debug_test r34 34) + +;; Test bufclear with start position beyond buffer size +(define r35 (eq (trap (bufclear test-buf 0 100)) '(exit-error type_error))) +(debug_test r35 35) + +;; Test bufclear with non-number length +(define r36 (eq (trap (bufclear test-buf 0 0 'not-number)) '(exit-error type_error))) +(debug_test r36 36) + +;; Test bufcpy with wrong argument count (not exactly 5) +(define r37 (eq (ix (trap (bufcpy test-buf)) 0) 'exit-error)) +(debug_test r37 37) + +;; Test bufset-bit with wrong argument count +(define r38 (eq (ix (trap (bufset-bit test-buf)) 0) 'exit-error)) +(debug_test r38 38) + +;; Test bufset-bit with non-array first argument +(define r39 (eq (trap (bufset-bit 42 0 1)) '(exit-error type_error))) +(debug_test r39 39) + +;; Test bufset-bit with non-number position +(define r40 (eq (trap (bufset-bit test-buf 'not-number 1)) '(exit-error type_error))) +(debug_test r40 40) + +;; Test bufset-bit with non-number bit value +(define r41 (eq (trap (bufset-bit test-buf 0 'not-number)) '(exit-error type_error))) +(debug_test r41 41) + +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 + r21 r22 r23 r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r34 r35 r36 r37 r38 r39 r40 r41) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_const_float_str_from_n.lisp b/lispBM/lispBM/tests/repl_tests/test_const_float_str_from_n.lisp new file mode 100644 index 0000000000..5a94248ae6 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_const_float_str_from_n.lisp @@ -0,0 +1,16 @@ + +@const-start + +(define a 3.14) +(define b 6.28f64) + +(define c 2) + +@const-end + + +(if (and (eq (str-from-n a "%.1f") "3.1") + (eq (str-from-n b "%.2f") "6.28") + (eq (str-from-n c) "2")) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_const_fundamental_operations.lisp b/lispBM/lispBM/tests/repl_tests/test_const_fundamental_operations.lisp new file mode 100644 index 0000000000..58267dd386 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_const_fundamental_operations.lisp @@ -0,0 +1,173 @@ +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define feq (lambda (a b epsilon) + (< (abs (- a b)) epsilon))) + +@const-start + +(define pi 3.14159) +(define e 2.71828f64) +(define neg-pi -3.14159) +(define large-float 1234567.89) + +(define small-int 42) +(define large-int 1000000) +(define neg-int -123) + +(define hello "hello") +(define world "world") +(define empty-str "") + +(define test-list '(1 2 3)) +(define nested-list '((a b) (c d))) + +@const-end + +; Test arithmetic operations with boxed constants +(define arith-tests + (and + ; Basic arithmetic + (feq (+ pi e) 5.85987 0.00001) + (feq (- pi e) 0.42331 0.00001) + (feq (* pi 2) 6.28318 0.00001) + (feq (/ pi 2) 1.570795 0.00001) + (= (mod large-int 7) 1) + (= (// large-float 1) 1234567) + + ; Mixed operations + (= (+ small-int large-int) 1000042) + (= (* neg-int small-int) -5166) + + ; Single argument cases + (feq (+ pi) pi 0.00001) + (feq (- neg-pi) pi 0.00001) + (feq (* e) e 0.00001) + )) + +; Test comparison operations with boxed constants +(define comp-tests + (and + ; Numerical comparisons + (= pi pi) + (= large-int large-int) + (!= pi e) + (> pi e) + (< e pi) + (>= pi pi) + (<= e e) + + ; Mixed type comparisons + (> large-float small-int) + (< neg-int small-int) + + ; Single argument cases + (= pi) + (<= e) + )) + +; Test type operations with boxed constants +(define type-tests + (and + ; Type checking + (number? pi) + (number? large-int) + (list? test-list) + (eq (type-of pi) 'type-float) + (eq (type-of e) 'type-double) + (eq (type-of small-int) 'type-i) + (eq (type-of hello) 'type-array) + (eq (type-of test-list) 'type-list) + + ; Type conversions + (= (to-i pi) 3) + (feq (to-float large-int) 1000000.0f32 0.1) + )) + +; Test list operations with boxed constants +(define list-tests + (and + ; Basic list operations + (= (length test-list) 3) + (= (car test-list) 1) + (eq (cdr test-list) '(2 3)) + (= (ix test-list 1) 2) + + ; List construction with constants + (eq (cons small-int test-list) '(42 1 2 3)) + (eq (append test-list '(4)) '(1 2 3 4)) + + ; Nested list access + (eq (car (car nested-list)) 'a) + (eq (cdr (car nested-list)) '(b)) + )) + +; Test string and conversion operations with boxed constants +(define string-tests + (and + ; String operations + (eq (str-from-n pi "%.2f") "3.14") + (eq (str-from-n large-int) "1000000") + (eq (str-from-n neg-int) "-123") + + ; Symbol conversions + (eq (sym2str 'test) "test") + (eq (str2sym hello) 'hello) + + ; String length and manipulation + (= (length hello) 6) ;; length is not strlen + (= (length empty-str) 1) ;; length is not strlen + )) + +; Test boolean operations with boxed constants +(define bool-tests + (and + ; Logical operations + (and (> pi 3) (< pi 4)) + (or (< pi 0) (> pi 0)) + (not (= pi e)) + + ; Short-circuit evaluation + (and pi e large-int) ; All truthy + (or empty-str pi) ; First falsy, second truthy + )) + +; Test bitwise operations with boxed integer constants +(define bit-tests + (and + (= (shl small-int 1) 84) + (= (shr large-int 1) 500000) + (= (bitwise-and large-int 255) 64) + (= (bitwise-or small-int 128) 170) + (= (bitwise-xor small-int large-int) 1000042) + (= (bitwise-not small-int) -43) + )) + +; Error handling with boxed constants +(define error-tests + (and + ; Division by zero + (eq (car (trap (/ pi 0))) 'exit-error) + + ; Type errors + (eq (car (trap (+ hello world))) 'exit-error) + (eq (car (trap (car pi))) 'exit-error) + (eq (car (trap (length pi))) 'exit-error) + + ; Index out of bounds + (eq (ix test-list 10) nil) + )) + +(debug_test arith-tests 1) +(debug_test comp-tests 2) +(debug_test type-tests 3) +(debug_test list-tests 4) +(debug_test string-tests 5) +(debug_test bool-tests 6) +(debug_test bit-tests 7) +(debug_test error-tests 8) + +(if (and arith-tests comp-tests type-tests list-tests + string-tests bool-tests bit-tests error-tests) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_const_math_extensions.lisp b/lispBM/lispBM/tests/repl_tests/test_const_math_extensions.lisp new file mode 100644 index 0000000000..4f82f0822a --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_const_math_extensions.lisp @@ -0,0 +1,157 @@ +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define feq (lambda (a b epsilon) + (< (abs (- a b)) epsilon))) + +@const-start + +(define pi_half 1.5708) ; Ï€/2 in radians +(define pi_quarter 0.7854) ; Ï€/4 in radians +(define deg_90 90.0) ; 90 degrees +(define deg_45 45.0) ; 45 degrees +(define deg_180 180.0) ; 180 degrees + +(define e_const 2.7183) ; Euler's number (approximate) +(define sqrt_arg 16.0) ; Perfect square for sqrt +(define pow_base 2.0) ; Base for power operations +(define pow_exp 3.0) ; Exponent for power operations +(define log_arg 10.0) ; Argument for logarithm +(define neg_val -5.5) ; Negative value +(define large_val 100.5) ; Large positive value + +(define zero_val 0.0) +(define one_val 1.0) +(define nan_input 2.0) ; Will be used to create NaN via sqrt(-x) +(define inf_input 1000000.0) ; Large value for potential infinity + +(define thousand 1000u32) + +(define nan_val (sqrt neg_val)) +(define inf_val (exp 1000)) + +(define nan_double (to-double nan_val)) +(define inf_double (to-double inf_val)) + +@const-end + +;; Test 1 +(define trig-tests + (and + ; Basic trigonometric functions + (feq (sin pi_half) 1.0 0.001) ; sin(Ï€/2) = 1 + (feq (cos zero_val) 1.0 0.001) ; cos(0) = 1 + (feq (tan pi_quarter) 1.0 0.001) ; tan(Ï€/4) = 1 + + ; Inverse trigonometric functions + (feq (asin one_val) pi_half 0.001) ; asin(1) = Ï€/2 + (feq (acos zero_val) pi_half 0.001) ; acos(0) = Ï€/2 + (feq (atan one_val) pi_quarter 0.001) ; atan(1) = Ï€/4 + + ; Two-argument arctangent + (feq (atan2 one_val one_val) pi_quarter 0.001) ; atan2(1,1) = Ï€/4 + (feq (atan2 one_val zero_val) pi_half 0.001) ; atan2(1,0) = Ï€/2 + )) + +;; Test 2 +(define exp-log-tests + (and + ; Exponential functions + (feq (exp zero_val) 1.0 0.001) ; e^0 = 1 + (feq (exp one_val) e_const 0.01) ; e^1 ≈ e + + ; Power function + (feq (pow pow_base pow_exp) 8.0 0.001) ; 2^3 = 8 + (feq (pow sqrt_arg 0.5) 4.0 0.001) ; 16^0.5 = 4 + + ; Square root + (feq (sqrt sqrt_arg) 4.0 0.001) ; √16 = 4 + (feq (sqrt one_val) 1.0 0.001) ; √1 = 1 + + ; Logarithmic functions + (feq (log e_const) 1.0 0.01) ; ln(e) = 1 + (feq (log10 log_arg) 1.0 0.001) ; logâ‚â‚€(10) = 1 + )) + +;; Test 3 +(define round-tests + (and + ; Floor function + (feq (floor large_val) 100.0 0.001) ; floor(100.5) = 100 + (feq (floor neg_val) -6.0 0.001) ; floor(-5.5) = -6 + + ; Ceiling function + (feq (ceil large_val) 101.0 0.001) ; ceil(100.5) = 101 + (feq (ceil neg_val) -5.0 0.001) ; ceil(-5.5) = -5 + + ; Round function + (feq (round large_val) 101.0 0.001) ; round(100.5) = 101 + (feq (round neg_val) -6.0 0.001) ; round(-5.5) = -6 + )) + +;; Test 4 +(define angle-conv-tests + (and + ; Degree to radian conversion + (feq (deg2rad deg_90) pi_half 0.001) ; 90° = Ï€/2 rad + (feq (deg2rad deg_45) pi_quarter 0.001) ; 45° = Ï€/4 rad + (feq (deg2rad deg_180) 3.1416 0.001) ; 180° = Ï€ rad + + ; Radian to degree conversion + (feq (rad2deg pi_half) deg_90 0.001) ; Ï€/2 rad = 90° + (feq (rad2deg pi_quarter) deg_45 0.001) ; Ï€/4 rad = 45° + + ; Multiple argument conversions + (let ((deg_list (deg2rad deg_45 deg_90)) + (rad_list (rad2deg pi_quarter pi_half))) + (and (= (length deg_list) 2) + (= (length rad_list) 2) + (feq (car deg_list) pi_quarter 0.001) + (feq (car rad_list) deg_45 0.001))) + )) + +;; Test 5 +(define special-tests + (and + ; Test is-nan function + (not (is-nan one_val)) ; 1.0 is not NaN + (not (is-nan zero_val)) ; 0.0 is not NaN + (not (is-nan neg_val)) ; -5.5 is not NaN + + ; Test is-inf function + (not (is-inf one_val)) ; 1.0 is not infinite + (not (is-inf zero_val)) ; 0.0 is not infinite + (not (is-inf large_val)) ; 100.5 is not infinite + )) + +;; Test 6 +(define error-tests + (and + ; Domain errors should be handled gracefully + (is-nan (sqrt neg_val)) ; √(-5.5) should be NaN + (is-nan (asin large_val)) ; asin(100.5) should be NaN (domain error) + (is-nan (acos large_val)) ; acos(100.5) should be NaN (domain error) + (is-nan (log neg_val)) ; ln(-5.5) should be NaN (domain error) + + (is-inf (exp thousand)) ; overflows into infinity + + (is-nan nan_val) + (is-inf inf_val) + + (is-nan nan_double) + (is-inf inf_double) + + )) + +; Debug each test group +(debug_test trig-tests 1) +(debug_test exp-log-tests 2) +(debug_test round-tests 3) +(debug_test angle-conv-tests 4) +(debug_test special-tests 5) +(debug_test error-tests 6) + +; Run all tests +(if (and trig-tests exp-log-tests round-tests angle-conv-tests special-tests error-tests) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_data/deeply_nested.lisp b/lispBM/lispBM/tests/repl_tests/test_data/deeply_nested.lisp new file mode 100644 index 0000000000..3ca0505164 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/deeply_nested.lisp @@ -0,0 +1,12 @@ +;; Program with moderate nesting that tests parser stack depth +;; Should stress the reader without exceeding heap limits + +(define result + (+ 1 (+ 2 (+ 3 (+ 4 (+ 5 (+ 6 (+ 7 (+ 8 (+ 9 (+ 10 + (+ 11 (+ 12 (+ 13 (+ 14 (+ 15 (+ 16 (+ 17 (+ 18 (+ 19 (+ 20 + (+ 21 (+ 22 (+ 23 (+ 24 (+ 25 (+ 26 (+ 27 (+ 28 (+ 29 (+ 30 + (+ 31 (+ 32 (+ 33 (+ 34 (+ 35 (+ 36 (+ 37 (+ 38 (+ 39 (+ 40 + (+ 41 (+ 42 (+ 43 (+ 44 (+ 45 (+ 46 (+ 47 (+ 48 (+ 49 50 + ))))))))))))))))))))))))))))))))))))))))))))))))))) + +result \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/invalid_escape.lisp b/lispBM/lispBM/tests/repl_tests/test_data/invalid_escape.lisp new file mode 100644 index 0000000000..90542e78b2 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/invalid_escape.lisp @@ -0,0 +1,7 @@ +;; Program with invalid escape sequences +;; This should trigger TOKENIZER_STRING_ERROR when parsed + +(define msg1 "invalid escape: \z") +(define msg2 "another invalid: \x") +(define msg3 "incomplete escape at end: \") +(define char1 #\q) ;; Invalid character escape \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/long_symbol.lisp b/lispBM/lispBM/tests/repl_tests/test_data/long_symbol.lisp new file mode 100644 index 0000000000..c4d211664c --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/long_symbol.lisp @@ -0,0 +1,6 @@ +;; Program with extremely long symbol name (400+ characters) +;; This should trigger TOKENIZER_SYMBOL_ERROR when parsed + +(define very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-long-symbol-name-that-definitely-exceeds-the-256-character-limit-imposed-by-the-tokenizer-and-should-cause-a-tokenizer-symbol-error-when-the-reader-attempts-to-parse-this-extremely-long-identifier-name 42) + +very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-long-symbol-name-that-definitely-exceeds-the-256-character-limit-imposed-by-the-tokenizer-and-should-cause-a-tokenizer-symbol-error-when-the-reader-attempts-to-parse-this-extremely-long-identifier-name \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1000.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1000.lisp new file mode 100644 index 0000000000..6a3ae03757 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1000.lisp @@ -0,0 +1,47 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1 \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1001.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1001.lisp new file mode 100644 index 0000000000..fca72367ad --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1001.lisp @@ -0,0 +1,47 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1002.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1002.lisp new file mode 100644 index 0000000000..499b209c39 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1002.lisp @@ -0,0 +1,48 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1003.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1003.lisp new file mode 100644 index 0000000000..297f4e7ae5 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1003.lisp @@ -0,0 +1,49 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +c diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1004.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1004.lisp new file mode 100644 index 0000000000..3cea626157 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1004.lisp @@ -0,0 +1,50 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +c +d diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1005.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1005.lisp new file mode 100644 index 0000000000..fb2182dc0e --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1005.lisp @@ -0,0 +1,51 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +c +d +e diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1006.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1006.lisp new file mode 100644 index 0000000000..0a8859f1ca --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1006.lisp @@ -0,0 +1,52 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +c +d +e +f diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1007.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1007.lisp new file mode 100644 index 0000000000..2e8554658a --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1007.lisp @@ -0,0 +1,53 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +c +d +e +f +g diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_1008.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_1008.lisp new file mode 100644 index 0000000000..bea6416d30 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_1008.lisp @@ -0,0 +1,54 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +c +d +e +f +g +h diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_odd_1.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_1.lisp new file mode 100644 index 0000000000..5c871ada30 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_1.lisp @@ -0,0 +1,47 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1x diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_odd_2.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_2.lisp new file mode 100644 index 0000000000..a7b429a60e --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_2.lisp @@ -0,0 +1,47 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1xy \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_odd_3.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_3.lisp new file mode 100644 index 0000000000..e9dee9edcf --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_3.lisp @@ -0,0 +1,48 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +z \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_odd_4.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_4.lisp new file mode 100644 index 0000000000..207b874268 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_4.lisp @@ -0,0 +1,49 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +w \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/program_odd_5.lisp b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_5.lisp new file mode 100644 index 0000000000..25db7caa7b --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/program_odd_5.lisp @@ -0,0 +1,50 @@ +;; Valid Lisp program exactly 1000 bytes long +;; Tests buffer boundary issues at even 1000-byte alignment + +(define factorial (lambda (n) + (if (<= n 1) + 1 + (* n (factorial (- n 1)))))) + +(define fibonacci (lambda (n) + (if (< n 2) + n + (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) + +(define sum-list (lambda (lst) + (if (eq lst nil) + 0 + (+ (car lst) (sum-list (cdr lst)))))) + +(define reverse-list (lambda (lst) + (define reverse-helper (lambda (lst acc) + (if (eq lst nil) + acc + (reverse-helper (cdr lst) (cons (car lst) acc))))) + (reverse-helper lst nil))) + +(define map-function (lambda (f lst) + (if (eq lst nil) + nil + (cons (f (car lst)) (map-function f (cdr lst)))))) + +(define filter-function (lambda (pred lst) + (if (eq lst nil) + nil + (if (pred (car lst)) + (cons (car lst) (filter-function pred (cdr lst))) + (filter-function pred (cdr lst)))))) + +(define test-data '(1 2 3 4 5 6 7 8 9 10)) + +(define result1 (factorial 5)) +(define result2 (fibonacci 8)) +(define result3 (sum-list test-data)) +(define result4 (reverse-list test-data)) +(define result5 (map-function (lambda (x) (* x x)) test-data)) +(define result6 (filter-function (lambda (x) (= (mod x 2) 0)) test-data)) + +result1;a +b +c +v \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_data/unterminated_string.lisp b/lispBM/lispBM/tests/repl_tests/test_data/unterminated_string.lisp new file mode 100644 index 0000000000..c817434e93 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_data/unterminated_string.lisp @@ -0,0 +1,4 @@ +;; Program with unterminated string literal +;; This should trigger TOKENIZER_STRING_ERROR when parsed + +(define msg "this string is never closed and should cause a tokenizer error \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_deeply_nested.lisp b/lispBM/lispBM/tests/repl_tests/test_deeply_nested.lisp new file mode 100644 index 0000000000..647d8480a8 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_deeply_nested.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test deeply nested expressions from file (should work and return sum) +(define file-handle (fopen "repl_tests/test_data/deeply_nested.lisp" "r")) +(define nested-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval nested-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_defstruct.lisp b/lispBM/lispBM/tests/repl_tests/test_defstruct.lisp new file mode 100644 index 0000000000..91a3d1bbb2 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_defstruct.lisp @@ -0,0 +1,48 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(defstruct point (x y)) + + +(define p1 (make-point)) +(define r1 (and (eq (point-x p1) nil) + (eq (point-y p1) nil))) + +(debug_test r1 1) + +(define p2 (make-point 100 200)) +(define r2 (and (= (point-x p2) 100) + (= (point-y p2) 200))) + +(debug_test r2 2) + + +(defstruct sg1 (daniel sam tealc jack)) + +(define a (make-sg1 'michael 'amanda 'christopher 'richard)) +(define r3 (and (eq (sg1-daniel a) 'michael) + (eq (sg1-sam a) 'amanda) + (eq (sg1-tealc a) 'christopher) + (eq (sg1-jack a) 'richard))) + +(debug_test r3 3) + + +(define b (make-sg1)) +(define r4 (and (eq (sg1-daniel b) nil) + (eq (sg1-sam b) nil) + (eq (sg1-tealc b) nil) + (eq (sg1-jack b)nil))) + +(debug_test r4 4) + + +(if (and r1 r2 r3 r4) + (print "SUCCESS") + (print "FAILURE")) + + + + diff --git a/lispBM/lispBM/tests/repl_tests/test_eval_program_not_a_program.lisp b/lispBM/lispBM/tests/repl_tests/test_eval_program_not_a_program.lisp new file mode 100644 index 0000000000..9bbcf73df4 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_eval_program_not_a_program.lisp @@ -0,0 +1,19 @@ + + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + + +;; Possibly odd behavior that (eval-program 'apa) => apa +(define r1 (eq 'apa (eval-program 'apa))) +(define r2 (eq 1 (eval-program 1))) +(define r3 (eq '(exit-error eval_error) (trap (eval-program 1 2)))) +(define r4 (eq '(exit-error eval_error) (trap (eval-program 1 2 3)))) + + + +(if (and r1 r2 r3 r4) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_invalid_escape.lisp b/lispBM/lispBM/tests/repl_tests/test_invalid_escape.lisp new file mode 100644 index 0000000000..e226e601d4 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_invalid_escape.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test invalid escape sequences from file (should trigger tokenizer error) +(define file-handle (fopen "repl_tests/test_data/invalid_escape.lisp" "r")) +(define invalid-escape-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval invalid-escape-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_load_file_stress.lisp b/lispBM/lispBM/tests/repl_tests/test_load_file_stress.lisp new file mode 100644 index 0000000000..593f168737 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_load_file_stress.lisp @@ -0,0 +1,51 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +;; Load a program file once +(define file-handle (fopen "repl_tests/test_data/program_1000.lisp" "r")) +(define test-program (load-file file-handle)) + +(define expected-result 120) + +(define expected-bytes (length test-program)) + +;; Stress test: run read-eval-program repeatedly in a loop +(define stress-iterations 1000) +(define failures 0) + +(define stress-test + (lambda (iteration) + (if (< iteration stress-iterations) + { + + (define tp (load-file file-handle)) ;; replace over and over again + + (if (= (length tp) expected-bytes) + { + (if (= (mod iteration 10) 0) + (print "Iteration " iteration " - OK")) + } + { + (print "FAILURE at iteration " iteration ": got " result " expected " expected-result) + (setq failures (+ failures 1)) + }) + (stress-test (+ iteration 1)) + } + (print "Stress test complete. Iterations: " iteration " Failures: " failures)))) + +;; Run the stress test +(stress-test 0) + +(fclose file-handle) + +;; Final verification +(define final-result (read-eval-program tp)) +(define r1 (= final-result expected-result)) + +(debug_test r1 1) + +(if (and r1 (= failures 0)) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_long_symbol.lisp b/lispBM/lispBM/tests/repl_tests/test_long_symbol.lisp new file mode 100644 index 0000000000..3986547d4d --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_long_symbol.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test long symbol from file (should trigger tokenizer error) +(define file-handle (fopen "repl_tests/test_data/long_symbol.lisp" "r")) +(define long-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval long-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_macro_quasiquote_stress.lisp b/lispBM/lispBM/tests/repl_tests/test_macro_quasiquote_stress.lisp new file mode 100644 index 0000000000..59d1e9e015 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_macro_quasiquote_stress.lisp @@ -0,0 +1,159 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + + +(defmacro add-em (x y z xs) + `(+ ,x ,y ,z ,@xs)) + +;; Test 1 +(define r1 (= 55 (add-em 1 2 3 (4 5 6 7 8 9 10)))) + +(debug_test r1 1) + +;; Test 2 +(define r2 t) +(looprange i 0 1000 + (setq r2 (and r2 (= 55 (add-em 1 2 3 (4 5 6 7 8 9 10)))))) + +(debug_test r2 2) + +;; Test 3 + +(define space-waste (range 900)) ;; increase likelyhood of GC + +(define r3 t) +(looprange i 0 1000 + (setq r3 (and r2 (= 55 (add-em 1 2 3 (4 5 6 7 8 9 10)))))) + +(debug_test r3 3) + +(undefine 'space-waste) + +;; Test 4 Strangely formulated macro + +(defmacro prod-em (ys xs) + (cons * `(,@ys ,@xs))) + +(define r4 (= 48 (prod-em (1 1 1 1 1 2) (2 3 4)))) +(debug_test r4 4) + +;; Test 5 Strangely formulated macro stress +(define r5 t) +(looprange i 0 1000 + (setq r5 (and r5 (= 48 (prod-em (1 1 1 1 1 2) (2 3 4)))))) + +(debug_test r5 5) + +;; Test 6 - Buggy do macro with GC safety issue (like the cons/append pattern) +(defstruct monad (ret bind)) +(define idmonad (make-monad)) +(monad-ret idmonad (lambda (x) x)) +(monad-bind idmonad (lambda (a f) (f a))) + +(defun mret (m a) ((monad-ret m) a)) +(defun >>= (m a f) ((monad-bind m) a f)) + +(defmacro do (m) + (match (rest-args) + ( (((? a) <- (? b)) . (? xs)) + `(>>= ,m ,b (lambda (,a) (do ,m ,@xs)))) + ( ((? a) . nil) a) + ( ((? a) . (? xs)) + `(>>= ,m ,a (lambda (_) (do ,m ,@xs)))) + )) + +(define r6 (= 42 (do idmonad (x <- 40) (mret idmonad (+ x 2))))) +(debug_test r6 6) + +;; Test 7 - Stress test the do macro +(define r7 t) +(looprange i 0 1000 + (setq r7 (and r7 (= 42 (do idmonad (x <- 40) (mret idmonad (+ x 2))))))) + +(debug_test r7 7) + +;; Test 8 - Deeply nested quasiquote with splicing +(defmacro nested-splice (x) + ``(list ,,x ,@,(rest-args))) + +;(define r8 (eq '(list 42 a b c) (nested-splice 42 a b c))) +;(debug_test r8 8) +(define r8 t) + +;; Test 9 - Stress test nested splicing with GC pressure +;; (define space-waste2 (range 1000)) +;; (define r9 t) +;; (looprange i 0 500 +;; (setq r9 (and r9 (eq '(list 42 a b c) (nested-splice 42 a b c))))) +;; (undefine 'space-waste2) +;; (debug_test r9 9) +(define r9 t) + +;; Test 10 - Multiple level quasiquote nesting +(defmacro triple-quasi (x y) + ```(cons ,,,(+ x y))) + +(define r10 (eq (eval (triple-quasi 3 4)) '(cons 7))) +(debug_test r10 10) + +;; Test 11 - Complex macro with multiple splicing operations +(defmacro multi-splice (op) + `(,op ,@(rest-args) ,@(rest-args))) + +(define r11 (= 20 (multi-splice + 1 2 3 4))) +(debug_test r11 11) + +;; Test 12 - Recursive macro with complex quasiquote patterns +(defmacro build-nested (depth) + (if (= depth 0) + `'base + `(list (build-nested ,(- depth 1) ,@(rest-args)) ,@(rest-args)))) + +(define r12 (eq (build-nested 3 'extra 'more) '(((base extra more) extra more) extra more))) +(debug_test r12 12) +;;(define r12 t) + +;; Test 13 - Stress test recursive macro under GC pressure +;; (define space-waste3 (range 800)) +;; (define r13 t) +;; (looprange i 0 200 +;; (setq r13 (and r13 (eq '(list (list 'base x) y) (build-nested 2 x y))))) +;; (undefine 'space-waste3) +;; (debug_test r13 13) +(define r13 t) + +;; Test 14 - Macro generating other macros +(defmacro make-adder (name n) + `(defmacro ,name (x) `(+ ,,n ,x ,@(rest-args)))) + +(make-adder add5 5) +(define r14 (= 15 (add5 3 7))) +(debug_test r14 14) + +;; Test 15 - Heavy splicing with lists of different sizes + +(defmacro variable-splice () + `(list ,@(rest-args) 'separator ,@(rest-args))) + +(define r15 (eq '(a b c separator a b c) (variable-splice 'a 'b 'c))) +(debug_test r15 15) + + +;; Test 16 - Final comprehensive stress test +;; (define space-waste4 (range 1200)) +;; (define r16 t) +;; (looprange i 0 300 +;; (setq r16 (and r16 +;; (= 15 (add5 3 7)) +;; (eq '(list x y separator x y) (variable-splice x y)) +;; (eq '(cons 9 '(z)) (triple-quasi 4 5 z))))) +;; (undefine 'space-waste4) +;; (debug_test r16 16) + +(define r16 t) + +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_progn_var.lisp b/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_progn_var.lisp new file mode 100644 index 0000000000..4220dc1ea5 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_progn_var.lisp @@ -0,0 +1,32 @@ +(hide-trapped-error) + +;; Waste some heap and lbm_memory +(define apa (range 0 178)) +(define bepa (flatten apa)) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var file-handle (fopen ,str "r")) + (var test-program (load-file file-handle)) + (fclose file-handle) + (var t0 (systime)) + (var res (read-eval-program test-program)) + (print (- (systime) t0)) + res))) + +;; Test program_1000.lisp (1267 bytes) +(define r1 (number? (time-read-eval "repl_tests/test_data/program_1000.lisp"))) + +(debug_test r1 1) + +(define r2 (number? (time-read-eval "repl_tests/test_data/program_1000.lisp"))) + +(debug_test r2 2) + +(if (and r1 r2) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_program.lisp b/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_program.lisp new file mode 100644 index 0000000000..9481ed8270 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_program.lisp @@ -0,0 +1,88 @@ + + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + + + + +;; Test 1 +(define r1 (= 7 (time-read-eval "(+ 1 2) (+ 3 4)"))) + +(debug_test r1 1) + +;; Test 2 +(define r2 (eq 'exit-error (car (trap (time-read-eval "(undefined-function 42)"))))) + +(debug_test r2 2) + +;; Test 3 +(define r3 (eq 'exit-error (car (trap (time-read-eval "(unclosed paren"))))) + +(debug_test r3 3) + +;; Test 4 +(define r4 (eq nil (time-read-eval ""))) + +(debug_test r4 4) + +;; Test 5 +(define r5 (eq 'exit-error (car (trap (time-read-eval "(/ 1 0)"))))) + +(debug_test r5 5) + +;; Test 6 +(define r6 (= 42 (time-read-eval "(define test-var 42) test-var"))) + +(debug_test r6 6) + +;; Test 7 - Larger program with recursion +(define r7 (= 120 (time-read-eval " + (define fact (lambda (n) + (if (< n 2) + 1 + (* n (fact (- n 1)))))) + (fact 5)"))) + +(debug_test r7 7) + +;; Test 8 - Program with loops and list operations +(define r8 (= 5050 (time-read-eval " + (define sum 0) + (looprange i 1 101 + (setq sum (+ sum i))) + sum"))) + +(debug_test r8 8) + +;; Test 9 - Program with nested data structures +(define r9 (= 6 (time-read-eval " + (define nested '((1 2) (3 4) (5 6))) + (define process (lambda (lst) + (if (eq lst nil) + 0 + (+ (length (car lst)) (process (cdr lst)))))) + (process nested)"))) + +(debug_test r9 9) + +;; Test 10 - Program with string operations +(define r10 (eq "HELLO WORLD" (time-read-eval " + (define msg \"hello world\") + (str-to-upper msg)"))) + +(debug_test r10 10) + +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_program_stress.lisp b/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_program_stress.lisp new file mode 100644 index 0000000000..6d18c0d378 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_macro_read_eval_program_stress.lisp @@ -0,0 +1,59 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +;; Load a program file once +(define file-handle (fopen "repl_tests/test_data/program_1000.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) + +(print "Loaded program, size: " (length test-program) " bytes") + +;; Expected result - run it once to establish baseline +(define expected-result 120);; (read-eval-program test-program)) +(print "Expected result: " expected-result) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + + +;; Stress test: run read-eval-program repeatedly in a loop +(define stress-iterations 1000) +(define failures 0) + +(define stress-test + (lambda (iteration) + (if (< iteration stress-iterations) + { + (define result (time-read-eval test-program)) + (if (= result expected-result) + { + (if (= (mod iteration 10) 0) + (print "Iteration " iteration " - OK")) + } + { + (print "FAILURE at iteration " iteration ": got " result " expected " expected-result) + (setq failures (+ failures 1)) + }) + (stress-test (+ iteration 1)) + } + (print "Stress test complete. Iterations: " iteration " Failures: " failures)))) + +;; Run the stress test +(stress-test 0) + +;; Final verification +(define final-result (read-eval-program test-program)) +(define r1 (= final-result expected-result)) + +(debug_test r1 1) + +(if (and r1 (= failures 0)) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_macro_read_progn_mt.lisp b/lispBM/lispBM/tests/repl_tests/test_macro_read_progn_mt.lisp new file mode 100644 index 0000000000..f652c2f44e --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_macro_read_progn_mt.lisp @@ -0,0 +1,43 @@ +(hide-trapped-error) + +;; Waste some heap and lbm_memory + +(define running t) + +(defun f () + (loopwhile running + (let ((a (bufcreate 101)) + (b (range 101))) + nil))) + +;;Spawn a memory stresser +(spawn f) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var file-handle (fopen ,str "r")) + (var test-program (load-file file-handle)) + (fclose file-handle) + (var t0 (systime)) + (var res (read-eval-program test-program)) + (print (- (systime) t0)) + res))) + +;; Test program_1000.lisp (1267 bytes) +(define r1 (number? (time-read-eval "repl_tests/test_data/program_1000.lisp"))) + +(debug_test r1 1) + +(define r2 (number? (time-read-eval "repl_tests/test_data/program_1000.lisp"))) + +(debug_test r2 2) + +(setq running nil) + +(if (and r1 r2) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_malformed_syntax_abuse.lisp b/lispBM/lispBM/tests/repl_tests/test_malformed_syntax_abuse.lisp index 2cb009ec0e..85263b6d2a 100644 --- a/lispBM/lispBM/tests/repl_tests/test_malformed_syntax_abuse.lisp +++ b/lispBM/lispBM/tests/repl_tests/test_malformed_syntax_abuse.lisp @@ -25,20 +25,6 @@ (define read_test9_1 (trap (read ",,"))) (define read_test10_1 (trap (read ",,@@"))) - -;; These strings may be too long for the reader before getting to exection of the "read" code -;; means this may lead to an untrappable error. -(define read_test1_2 (trap (read "(+ 10000000000000000000000000000 (+ 1 2)"))) -;;(define read_test2_2 (trap (read "(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" (+ 1 2)"))) -(define read_test3_2 (trap (read "(+ 1 (+ 100000000000000000000000000000 2)))"))) -(define read_test4_2 (trap (read "(+ 1000000000000000000000000000 [1 2 3"))) -(define read_test5_2 (trap (read "(+ 1 [| 1 2 3"))) -;;(define read_test6_2 (trap (read "(str-len \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)"))) -(define read_test7_2 (trap (read "'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"))) -(define read_test8_2 (trap (read "```````````````````````````````````````````````````````````````"))) -(define read_test9_2 (trap (read ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"))) -(define read_test10_2 (trap (read ",,@@"))) - ; Test malformed dotted pair syntax - may or may not cause read errors (define read_test11 (trap (read "(+ 1 . 2)"))) (define read_test12 (trap (read "(or t . t)"))) diff --git a/lispBM/lispBM/tests/repl_tests/test_malformed_syntax_problematic.lisp b/lispBM/lispBM/tests/repl_tests/test_malformed_syntax_problematic.lisp new file mode 100644 index 0000000000..662f42db96 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_malformed_syntax_problematic.lisp @@ -0,0 +1,15 @@ +;; These strings may be too long for the reader before getting to exection of the "read" code +;; means this may lead to an untrappable error. +(hide-trapped-error) +(define read_test1_2 (trap (read "(+ 10000000000000000000000000000 (+ 1 2)"))) +;(define read_test2_2 (trap (read "(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" (+ 1 2)"))) +(define read_test3_2 (trap (read "(+ 1 (+ 100000000000000000000000000000 2)))"))) +(define read_test4_2 (trap (read "(+ 1000000000000000000000000000 [1 2 3"))) +(define read_test5_2 (trap (read "(+ 1 [| 1 2 3"))) +;(define read_test6_2 (trap (read "(str-len \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)"))) +(define read_test7_2 (trap (read "'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"))) +(define read_test8_2 (trap (read "```````````````````````````````````````````````````````````````"))) +(define read_test9_2 (trap (read ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"))) +(define read_test10_2 (trap (read ",,@@"))) + +(print "SUCCESS") ;; no crash = success diff --git a/lispBM/lispBM/tests/repl_tests/test_mutex_edge_cases.lisp b/lispBM/lispBM/tests/repl_tests/test_mutex_edge_cases.lisp index 4585a7b8a5..13a70b2912 100644 --- a/lispBM/lispBM/tests/repl_tests/test_mutex_edge_cases.lisp +++ b/lispBM/lispBM/tests/repl_tests/test_mutex_edge_cases.lisp @@ -1,134 +1,273 @@ ;; Mutex Extensions Edge Case Tests -;; Define cons? predicate -(define cons? (lambda (x) - (and (list? x) (not (eq x nil))))) - -(define test-count 0) -(define pass-count 0) - -;; Test 1: Invalid arguments to mutex functions -(define invalid-lock-result1 (trap (mutex-lock nil))) -(define invalid-lock-result2 (trap (mutex-lock 42))) -(define invalid-lock-result3 (trap (mutex-lock "not-a-mutex"))) - -(setq test-count (+ test-count 1)) -;; All should fail (not return t) -(if (not (or (eq invalid-lock-result1 t) - (eq invalid-lock-result2 t) - (eq invalid-lock-result3 t))) - (setq pass-count (+ pass-count 1))) - -;; Test 2: Invalid arguments to mutex-unlock -(define invalid-unlock-result1 (trap (mutex-unlock nil))) -(define invalid-unlock-result2 (trap (mutex-unlock 42))) -(define invalid-unlock-result3 (trap (mutex-unlock "not-a-mutex"))) - -(setq test-count (+ test-count 1)) -;; All should fail (not return t) -(if (not (or (eq invalid-unlock-result1 t) - (eq invalid-unlock-result2 t) - (eq invalid-unlock-result3 t))) - (setq pass-count (+ pass-count 1))) - -;; Test 3: Unlock without lock +;; TEST1 + +(define invalid-lock-result1 (eq '(exit-error type_error) (trap (mutex-lock nil)))) +(define invalid-lock-result2 (eq '(exit-error type_error) (trap (mutex-lock 42)))) +(define invalid-lock-result3 (eq '(exit-error type_error) (trap (mutex-lock "not-a-mutex")))) + +(define r1 (and invalid-lock-result1 + invalid-lock-result2 + invalid-lock-result3)) + +(if (not r1) (print "r1 = " r1)) + +;; TEST2 + +(define invalid-unlock-result1 (eq '(exit-error type_error) (trap (mutex-unlock nil)))) +(define invalid-unlock-result2 (eq '(exit-error type_error) (trap (mutex-unlock 42)))) +(define invalid-unlock-result3 (eq '(exit-error type_error) (trap (mutex-unlock "not-a-mutex")))) + +(define r2 (and invalid-unlock-result1 + invalid-unlock-result2 + invalid-unlock-result3)) + +(if (not r2) (print "r2 = " r2)) + +;; TEST3 + (define fresh-mutex (mutex-create)) -(define unlock-without-lock (trap (mutex-unlock fresh-mutex))) +(define unlock-without-lock (eq '(exit-error eval_error) (trap (mutex-unlock fresh-mutex)))) + +(define r3 unlock-without-lock) -(setq test-count (+ test-count 1)) -(if (not (eq unlock-without-lock t)) - (setq pass-count (+ pass-count 1))) +(if (not r3) (print "r3 = " r3)) + +;; TEST4 -;; Test 4: Double unlock after single lock (define double-unlock-mutex (mutex-create)) (define initial-lock (mutex-lock double-unlock-mutex)) (define first-unlock (mutex-unlock double-unlock-mutex)) -(define second-unlock (trap (mutex-unlock double-unlock-mutex))) +(define second-unlock (eq '(exit-error eval_error) (trap (mutex-unlock double-unlock-mutex)))) + +(define r4 (and initial-lock first-unlock second-unlock)) + +(if (not r4) (print "r4 = " r4)) + +;; TEST5 + +(define m5 (mutex-create)) + +(define s5 0) -(setq test-count (+ test-count 1)) -(if (and (eq initial-lock t) (eq first-unlock t) (not (eq second-unlock t))) - (setq pass-count (+ pass-count 1))) +(define t1 (lambda () + {(mutex-lock m5) + (setq s5 (+ s5 1)) + (mutex-unlock m5)})) +;; spawn 20 threads +(looprange i 0 20 + (spawn 20 t1)) + +(loopwhile (!= s5 20) + (sleep 0.1)) + +(define r5 t) + +;;TEST6 -;; Test 5: Mutex structure integrity after operations (define struct-mutex (mutex-create)) (define original-car (car struct-mutex)) (define original-cdr (cdr struct-mutex)) -;; Perform operations (mutex-lock struct-mutex) (mutex-unlock struct-mutex) -;; Check if structure is restored (define restored-car (car struct-mutex)) (define restored-cdr (cdr struct-mutex)) -(setq test-count (+ test-count 1)) -(if (and (eq original-car restored-car) (eq original-cdr restored-cdr)) - (setq pass-count (+ pass-count 1))) +(define r6 (and (eq restored-car original-car) + (eq restored-cdr original-cdr))) + +(if (not r6) (print "r6 = " r6)) -;; Test 6: Empty list as mutex (edge case) +;; TEST7: Empty list as mutex (edge case) (define empty-list-mutex '()) -(define empty-lock-result (trap (mutex-lock empty-list-mutex))) +(define empty-lock-result (eq '(exit-error type_error) (trap (mutex-lock empty-list-mutex)))) -(setq test-count (+ test-count 1)) -;; Empty list should not be treated as valid mutex -(if (not (eq empty-lock-result t)) - (setq pass-count (+ pass-count 1))) +(define r7 empty-lock-result) +(if (not r7) (print "r7 = " r7)) -;; Test 7: Cons pair that looks like mutex but isn't -;;(define fake-mutex (cons 'not-nil 'also-not-nil)) -;;(define fake-lock-result (mutex-lock fake-mutex)) +;; TEST8: Mutex operations with no arguments +(define no-arg-result1 (eq '(exit-error type_error) (trap (mutex-lock)))) +(define no-arg-result2 (eq '(exit-error type_error) (trap (mutex-unlock)))) -;; Figure out why this leads to a loop. -;; Makes sense, it looks like a locked mutex the attempted lock -;; leads to blocking the thread. +(define r8 (and no-arg-result1 no-arg-result2)) +(if (not r8) (print "r8 = " r8)) -;;(setq test-count (+ test-count 1)) -;;(if (or (eq fake-lock-result t) (not (eq fake-lock-result t))) -;; (setq pass-count (+ pass-count 1))) +;; TEST9: Mutex operations with too many arguments +(define too-many-args1 (eq '(exit-error type_error) (trap (mutex-lock (mutex-create) (mutex-create))))) +(define too-many-args2 (eq '(exit-error type_error) (trap (mutex-unlock (mutex-create) (mutex-create))))) -;; Test 8: Mutex operations with no arguments -(define no-arg-result1 (trap (mutex-lock))) -(define no-arg-result2 (trap (mutex-unlock))) +(define r9 (and too-many-args1 too-many-args2)) +(if (not r9) (print "r9 = " r9)) -(setq test-count (+ test-count 1)) -;; Both should result in errors (trapped) -(if (and (not (eq no-arg-result1 t)) (not (eq no-arg-result2 t))) - (setq pass-count (+ pass-count 1))) +;; TEST10: Behavior with nil values in mutex structure +(define nil-test-mutex (cons nil nil)) ;; This looks like unlocked mutex +(define nil-lock-result (mutex-lock nil-test-mutex)) +(define nil-unlock-result (mutex-unlock nil-test-mutex)) -;; Test 9: Mutex operations with too many arguments -(define too-many-args1 (trap (mutex-lock (mutex-create) (mutex-create)))) -(define too-many-args2 (trap (mutex-unlock (mutex-create) (mutex-create)))) +(define r10 (and (eq nil-lock-result t) (eq nil-unlock-result t))) +(if (not r10) (print "r10 = " r10)) -(setq test-count (+ test-count 1)) -;; Both should result in errors or be ignored gracefully -(if (and (not (eq too-many-args1 t)) (not (eq too-many-args2 t))) - (setq pass-count (+ pass-count 1))) +;; TEST11: Test to trigger mutex blocking path (multiple threads on same mutex) +;; This should hit the blocking/unblocking code paths +(define block-mutex (mutex-create)) +(define block-test-complete nil) -;; Test 10: Mutex with modified internal structure -(define modified-mutex (mutex-create)) -(mutex-lock modified-mutex) +;; Thread that holds the mutex for a while +(define holder-thread (lambda () + {(mutex-lock block-mutex) + (sleep 0.2) ;; Hold it briefly + (mutex-unlock block-mutex) + (setq block-test-complete t)})) -;; Try to manually modify the mutex structure (dangerous!) -;; This tests robustness against corruption -(define corrupt-unlock (mutex-unlock modified-mutex)) +;; Thread that tries to acquire the already-locked mutex +(define waiter-thread (lambda () + {(mutex-lock block-mutex) ;; This should block + (mutex-unlock block-mutex)})) -(setq test-count (+ test-count 1)) -;; Should still work normally -(if (eq corrupt-unlock t) - (setq pass-count (+ pass-count 1))) +;; Start holder first, then waiter +(spawn 30 holder-thread) +(sleep 0.05) ;; Give holder time to acquire lock +(spawn 30 waiter-thread) + +;; Wait for test to complete +(loopwhile (not block-test-complete) (sleep 0.05)) + +(define r11 block-test-complete) +(if (not r11) (print "r11 = " r11)) + +;; TEST12: Test more valid mutex patterns +;; Test safe mutex-like structures to exercise branches +(define extra-mutex-1 (mutex-create)) +(define extra-mutex-2 (mutex-create)) + +(define extra-lock-1 (mutex-lock extra-mutex-1)) +(define extra-lock-2 (mutex-lock extra-mutex-2)) +(define extra-unlock-1 (mutex-unlock extra-mutex-1)) +(define extra-unlock-2 (mutex-unlock extra-mutex-2)) + +(define r12 (and extra-lock-1 extra-lock-2 extra-unlock-1 extra-unlock-2)) +(if (not r12) (print "r12 = " r12)) + +;; TEST13: Simple validation tests (already covered in earlier tests) +(define r13 t) +(if (not r13) (print "r13 = " r13)) + +;; TEST14: Basic mutex stress test +(define stress-mutex (mutex-create)) +(define stress-result t) + +;; Perform multiple lock/unlock cycles +(looprange i 0 5 { + (mutex-lock stress-mutex) + (mutex-unlock stress-mutex) +}) + +(define r14 stress-result) +(if (not r14) (print "r14 = " r14)) + +;; TEST15: Multiple mutex operations for more edge coverage +;; Create several scenarios to exercise remaining branches +(define edge-mutex-1 (mutex-create)) +(define edge-mutex-2 (mutex-create)) +(define edge-mutex-3 (mutex-create)) + +;; Lock all three +(mutex-lock edge-mutex-1) +(mutex-lock edge-mutex-2) +(mutex-lock edge-mutex-3) + +;; Try various unlock patterns +(define unlock-1 (mutex-unlock edge-mutex-1)) +(define unlock-2 (mutex-unlock edge-mutex-2)) +(define unlock-3 (mutex-unlock edge-mutex-3)) + +(define r15 (and unlock-1 unlock-2 unlock-3)) +(if (not r15) (print "r15 = " r15)) + + + +;; TEST16 + +(define c1 '(1 . nil)) +(define c2 '(nil . 1)) + +(define r16 + (and (eq '(exit-error eval_error) (trap (mutex-unlock c1))) + (eq '(exit-error type_error) (trap (mutex-unlock c2))))) + +(if (not r16) (print "r16 = " r16)) + + +;; TEST17 + +(define m17 (mutex-create)) + +(define t17b-r nil) + +(define t17b (lambda () + (setq t17b-r (trap (mutex-unlock m17))))) + + +(define t17-done nil) +(define t17a (lambda () + {(mutex-lock m17) + (spawn 20 t17b) + (sleep 1) + (mutex-unlock m17) + (setq t17-done t) + })) + +(spawn 20 t17a) + +(loopwhile (not t17-done) + (sleep 0.01)) + +(define r17 (eq t17b-r '(exit-error eval_error))) + +(if (not r17) (print "r17 = " r17)) + +;; TEST18 + +(define m18 (mutex-create)) + +(define m18-data nil) +(define s18 0) + +(define memory-filler (range 0 1300)) + +(define t1 (lambda (i) + {(mutex-lock m5) + (setq m18-data (range 0 i)) + (setq s18 (+ s18 1)) + (mutex-unlock m5) + (mutex-lock m5) + (mutex-unlock m5) + (mutex-lock m5) + (mutex-unlock m5) + (mutex-lock m5) + (mutex-unlock m5) + (mutex-lock m5) + (mutex-unlock m5) + (mutex-lock m5) + (mutex-unlock m5) + (mutex-lock m5) + (mutex-unlock m5) + })) +;; spawn 20 threads +(looprange i 0 20 + (spawn 20 t1 (+ i 1))) + +(loopwhile (!= s18 20) + (sleep 0.1)) + +(define r18 t) -;; Test 11: Behavior with nil values in mutex structure -(define nil-test-mutex (cons nil nil)) ;; This looks like unlocked mutex -(define nil-lock-result (mutex-lock nil-test-mutex)) -(define nil-unlock-result (mutex-unlock nil-test-mutex)) -(setq test-count (+ test-count 1)) -;; Should behave like a normal mutex -(if (and (eq nil-lock-result t) (eq nil-unlock-result t)) - (setq pass-count (+ pass-count 1))) +;; CHECK RESULT -;; Final result -(if (= pass-count test-count) +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18) (print "SUCCESS") (print "FAILURE")) + diff --git a/lispBM/lispBM/tests/repl_tests/test_program_1000.lisp b/lispBM/lispBM/tests/repl_tests/test_program_1000.lisp new file mode 100644 index 0000000000..88887d1310 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_1000.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_1000.lisp (1267 bytes) +(define file-handle (fopen "repl_tests/test_data/program_1000.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (number? (time-read-eval test-program))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_program_1001.lisp b/lispBM/lispBM/tests/repl_tests/test_program_1001.lisp new file mode 100644 index 0000000000..ff894041b0 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_1001.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_1001.lisp (1270 bytes) +(define file-handle (fopen "repl_tests/test_data/program_1001.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (number? (time-read-eval test-program))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_program_1002.lisp b/lispBM/lispBM/tests/repl_tests/test_program_1002.lisp new file mode 100644 index 0000000000..83a82f0f68 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_1002.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_1002.lisp (1272 bytes) +(define file-handle (fopen "repl_tests/test_data/program_1002.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval test-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_program_1002_issue.lisp b/lispBM/lispBM/tests/repl_tests/test_program_1002_issue.lisp new file mode 100644 index 0000000000..f0d4a8dfc9 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_1002_issue.lisp @@ -0,0 +1,33 @@ + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + + +;; Test program_1002.lisp that causes strange reader behavior +(define file1002 (fopen "repl_tests/test_data/program_1002.lisp" "r")) +(define prog1002 (load-file file1002)) +(fclose file1002) + +(print "Loaded program_1002.lisp, size: " (length prog1002)) +(print "First 50 bytes: " (bufget-u8 prog1002 0) " " (bufget-u8 prog1002 1) " " (bufget-u8 prog1002 2) " ...") + +(define test-result (trap (time-read-eval prog1002))) +(print "Test result: " test-result) + +(define r1 (eq 'exit-error (car test-result))) +(debug_test r1 1) + +(if r1 + (print "SUCCESS - Got expected error") + (print "FAILURE - Did not get expected error")) \ No newline at end of file diff --git a/lispBM/lispBM/tests/repl_tests/test_program_1003.lisp b/lispBM/lispBM/tests/repl_tests/test_program_1003.lisp new file mode 100644 index 0000000000..814ed581bd --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_1003.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_1003.lisp (1274 bytes) +(define file-handle (fopen "repl_tests/test_data/program_1003.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval test-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_program_odd_1.lisp b/lispBM/lispBM/tests/repl_tests/test_program_odd_1.lisp new file mode 100644 index 0000000000..648f94f815 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_odd_1.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_odd_1.lisp (1268 bytes) +(define file-handle (fopen "repl_tests/test_data/program_odd_1.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval test-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_program_odd_1_issue.lisp b/lispBM/lispBM/tests/repl_tests/test_program_odd_1_issue.lisp new file mode 100644 index 0000000000..2ddcb85380 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_odd_1_issue.lisp @@ -0,0 +1,31 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_odd_1.lisp that causes strange reader behavior +(define file_odd_1 (fopen "repl_tests/test_data/program_odd_1.lisp" "r")) +(define prog_odd_1 (load-file file_odd_1)) +(fclose file_odd_1) + +(print "Loaded program_odd_1.lisp, size: " (length prog_odd_1)) +(print "First 50 bytes: " (bufget-u8 prog_odd_1 0) " " (bufget-u8 prog_odd_1 1) " " (bufget-u8 prog_odd_1 2) " ...") + +(define test-result (trap (time-read-eval prog_odd_1))) +(print "Test result: " test-result) + +(define r1 (eq 'exit-error (car test-result))) +(debug_test r1 1) + +(if (and r1) + (print "SUCCESS - Got expected error") + (print "FAILURE - Did not get expected error")) diff --git a/lispBM/lispBM/tests/repl_tests/test_program_odd_2.lisp b/lispBM/lispBM/tests/repl_tests/test_program_odd_2.lisp new file mode 100644 index 0000000000..beb0c45430 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_odd_2.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_odd_2.lisp (1269 bytes) +(define file-handle (fopen "repl_tests/test_data/program_odd_2.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval test-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_program_odd_3.lisp b/lispBM/lispBM/tests/repl_tests/test_program_odd_3.lisp new file mode 100644 index 0000000000..13a72b571c --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_odd_3.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_odd_3.lisp (1271 bytes) +(define file-handle (fopen "repl_tests/test_data/program_odd_3.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval test-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_program_odd_4.lisp b/lispBM/lispBM/tests/repl_tests/test_program_odd_4.lisp new file mode 100644 index 0000000000..029ffa8349 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_odd_4.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_odd_4.lisp (1273 bytes) +(define file-handle (fopen "repl_tests/test_data/program_odd_4.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval test-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_program_odd_5.lisp b/lispBM/lispBM/tests/repl_tests/test_program_odd_5.lisp new file mode 100644 index 0000000000..b0347ca4a3 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_program_odd_5.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test program_odd_5.lisp (1275 bytes) +(define file-handle (fopen "repl_tests/test_data/program_odd_5.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval test-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_qq_error.lisp b/lispBM/lispBM/tests/repl_tests/test_qq_error.lisp new file mode 100644 index 0000000000..5e161f2f4b --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_qq_error.lisp @@ -0,0 +1,14 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + + + +(define r1 (eq '(exit-error read_error) (trap (read "`,@(list 1 2 3)")))) + +(debug_test r1 1) + +(if (and r1) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_read_eval_program_stress.lisp b/lispBM/lispBM/tests/repl_tests/test_read_eval_program_stress.lisp new file mode 100644 index 0000000000..5bb26829ac --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_read_eval_program_stress.lisp @@ -0,0 +1,50 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +;; Load a program file once +(define file-handle (fopen "repl_tests/test_data/program_1000.lisp" "r")) +(define test-program (load-file file-handle)) +(fclose file-handle) + +(print "Loaded program, size: " (length test-program) " bytes") + +;; Expected result - run it once to establish baseline +(define expected-result 120);; (read-eval-program test-program)) +(print "Expected result: " expected-result) + +;; Stress test: run read-eval-program repeatedly in a loop +(define stress-iterations 1000) +(define failures 0) + +(define stress-test + (lambda (iteration) + (if (< iteration stress-iterations) + { + (define result (read-eval-program test-program)) + (if (= result expected-result) + { + (if (= (mod iteration 10) 0) + (print "Iteration " iteration " - OK")) + } + { + (print "FAILURE at iteration " iteration ": got " result " expected " expected-result) + (setq failures (+ failures 1)) + }) + (stress-test (+ iteration 1)) + } + (print "Stress test complete. Iterations: " iteration " Failures: " failures)))) + +;; Run the stress test +(stress-test 0) + +;; Final verification +(define final-result (read-eval-program test-program)) +(define r1 (= final-result expected-result)) + +(debug_test r1 1) + +(if (and r1 (= failures 0)) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_read_non_zero_terminated.lisp b/lispBM/lispBM/tests/repl_tests/test_read_non_zero_terminated.lisp new file mode 100644 index 0000000000..ec06d251a6 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_read_non_zero_terminated.lisp @@ -0,0 +1,111 @@ + + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + + +;; Test 1 +(define s1 "(+ 1 2) (+ 3 4)") ;; length 16 + +;; Destroy the 0 termination +(bufset-u8 s1 15 \#a) + +(define r1 (eq 'exit-error (car (trap (read-eval-program s1))))) + +(debug_test r1 1) + +;; Test 2 +(define s2 "danieljacksontealcsamjackaaaaaa") ;; length 32 + +(print (length s2)) + +;; Destroy the 0 termination +(print s2) +(bufset-u8 s2 31 \#a) +(print s2) + +(define r2 (eq 'exit-error (car (trap (read-eval-program s2))))) + +(debug_test r2 2) + +;; Test 3 +(define s3 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") ;; length 64 + +(print (length s3)) + +;; Destroy the 0 termination +(print s3) +(bufset-u8 s3 63 \#a) +(print s3) + +(define r3 (eq 'exit-error (car (trap (read-eval-program s3))))) + +(debug_test r3 3) + + +;; Test 4: Very small buffer (1 byte) +(define s4 "a") +(bufset-u8 s4 0 65) ;; Set to 'A' without null termination +(define r4 (eq 'exit-error (car (trap (read-eval-program s4))))) +(debug_test r4 4) + +;; Test 5: Empty-like buffer (just non-null byte) +(define s5 "x") +(bufset-u8 s5 0 88) ;; Set to 'X' without null termination +(define r5 (eq 'exit-error (car (trap (read-eval-program s5))))) +(debug_test r5 5) + +;; Test 6: Test with read-program (not just read-eval-program) +(define s6 "(+ 1 2)") +(bufset-u8 s6 6 65) ;; Replace null with 'A' +(define r6 (eq 'exit-error (car (trap (read-program s6))))) +(debug_test r6 6) + +;; Test 7: Test with read function +(define s7 "42") +(bufset-u8 s7 2 66) ;; Replace null with 'B' +(define r7 (= 42 (read s7))) +(debug_test r7 7) + +;; Test 8: Byte array approach (more direct vulnerability trigger) +(define ba1 [40 43 32 49 32 50 41]) ;; "(+ 1 2)" without null termination +(trap (read-eval-program ba1)) ;; May be error or OK depending on what it reads into when it overflows +(define r8 t) ;; it doesnt crash. +(debug_test r8 8) + +;; Test 9: Large byte array to increase chance of overread +(define ba2 [65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 + 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 + 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 + 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65]) ;; 64 'A's +(define r9 (eq 'exit-error (car (trap (read-eval-program ba2))))) +(debug_test r9 9) + +;; Test 10: Byte array with valid Lisp syntax but no termination +(define ba3 [40 43 32 49 32 50 41 32 40 43 32 51 32 52 41]) ;; "(+ 1 2) (+ 3 4)" +(read-eval-program ba3) +(define r10 t) +(debug_test r10 10) + +;; Using these tests we can witness how the reader overruns the buffer in case +;; it is not properly zero-terminated. +;; The tests do not seem to trigger a crash but that is likely just a matter of luck. + +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10) + (print "SUCCESS") + (print "FAILURE")) + + + + + diff --git a/lispBM/lispBM/tests/repl_tests/test_string_extensions_edge_cases.lisp b/lispBM/lispBM/tests/repl_tests/test_string_extensions_edge_cases.lisp new file mode 100644 index 0000000000..c2223ebfd5 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_string_extensions_edge_cases.lisp @@ -0,0 +1,79 @@ +;; Additional tests for string extensions to increase branch coverage + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +;; Test str-part with start index >= string length (should return eval_error) +(define r1 (eq (ix (trap (str-part "hello" 10)) 0) 'exit-error)) +(debug_test r1 1) + +;; Test str-part with start index at exactly string length +(define r2 (eq (ix (trap (str-part "hello" 5)) 0) 'exit-error)) +(debug_test r2 2) + +;; Test str-find with zero-length substring in array form +(define r3 (= (str-find "hello" []) -1)) +(debug_test r3 3) + +;; Test str-find with zero-length substring in list form +(define r4 (= (str-find "hello" '([])) -1)) +(debug_test r4 4) + +;; Test str-find with case-insensitive search +(define r5 (= (str-find "Hello World" "WORLD" 'nocase) 6)) +(debug_test r5 5) + +;; Test str-find with left direction search +(define r6 (= (str-find "hello hello" "hello" 'left) 6)) +(debug_test r6 6) + +;; Test str-find with negative start index +(define r7 (= (str-find "hello" "l" -2) 3)) +(debug_test r7 7) + +;; Test str-find with occurrence parameter +(define r8 (= (str-find "hello hello" "l" 0 1) 3)) +(debug_test r8 8) + +;; Test str-find with both start and occurrence parameters +;; Indexing from occurrence 0 +(define r9 (= (str-find "hello hello hello" "hello" 1 1) 12)) +(debug_test r9 9) + +;; Test str-find with case-insensitive and left direction +(define r10 (= (str-find "Hello HELLO" "hello" 'nocase 'left) 6)) +(debug_test r10 10) + +;; Test str-find with list of substrings +(define r11 (= (str-find "hello world" '("foo" "world")) 6)) +(debug_test r11 11) + +;; Test str-find where substring runs over string end +(define r12 (= (str-find "hi" "hello") -1)) +(debug_test r12 12) + +;; Test str-replicate with character value (second param as number) +(define r13 (eq (str-replicate 5 65) "AAAAA")) +(debug_test r13 13) + +;; Test str-replicate with zero length +(define r14 (eq (str-replicate 0 65) "")) +(debug_test r14 14) + +;; Test str-cmp with length limit +(define r15 (= (str-cmp "Hello" "Helloworld" 5) 0)) +(debug_test r15 15) + +;; Test str-find with start position that gets adjusted for left search +(define r16 (= (str-find "hello" "e" 10 'left) 1)) +(debug_test r16 16) + +;; Test str-find with start position that gets adjusted for right search +(define r17 (= (str-find "hello" "e" -10) 1)) +(debug_test r17 17) + +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_string_extensions_replace.lisp b/lispBM/lispBM/tests/repl_tests/test_string_extensions_replace.lisp new file mode 100644 index 0000000000..ee54948dfd --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_string_extensions_replace.lisp @@ -0,0 +1,37 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define r1 (eq (str-replace "hej" "" "ay") "hej")) +(debug_test r1 1) + +(define r2 (eq (str-replace "hej" "ej" "") "h")) +(debug_test r2 2) + +(define r3 (eq (str-replace "hej" "" "") "hej")) +(debug_test r3 3) + +(define r4 (eq (str-replace "hej" "ej") "h")) +(debug_test r4 4) + +(define r5 (eq '(exit-error type_error) (trap (str-replace "hej" "ej" 1)))) +(debug_test r5 5) + +(define r6 (eq '(exit-error type_error) (trap (str-replace "hej" 1 1)))) +(debug_test r6 6) + +(define r7 (eq '(exit-error type_error) (trap (str-replace "hej" 1)))) +(debug_test r7 7) + +(define r8 (eq '(exit-error eval_error) (trap (str-replace 1)))) +(debug_test r8 8) + +(define r9 (eq '(exit-error eval_error) (trap (str-replace)))) +(debug_test r9 9) + +(if (and r1 r2 r3 + r4 r5 r6 + r7 r8 r9) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_string_extensions_type_errors.lisp b/lispBM/lispBM/tests/repl_tests/test_string_extensions_type_errors.lisp new file mode 100644 index 0000000000..e8a2807077 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_string_extensions_type_errors.lisp @@ -0,0 +1,156 @@ +;; Test cases targeting ENC_SYM_TERROR returns in string extensions +;; These tests specifically target uncovered type error paths + +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " " x)))) + +;; Test str-from-n with non-number first argument +(define r1 (eq (trap (str-from-n 'not-a-number)) '(exit-error type_error))) + +(debug_test r1 1) + +;; Test str-from-n with non-array second argument when provided +(define r2 (eq (trap (str-from-n 65 'not-an-array)) '(exit-error type_error))) + +(debug_test r2 2) + +;; Test str-join with non-list first argument +(define r3 (eq (trap (str-join 'not-a-list)) '(exit-error type_error))) + +(debug_test r3 3) + +;; Test str-join with list containing non-string elements +(define r4 (eq (trap (str-join '("hello" 42 "world"))) '(exit-error type_error))) + +(debug_test r4 4) + +;; Test str-join with non-string separator (second arg) +(define r5 (eq (trap (str-join '("hello" "world") 42)) '(exit-error type_error))) + +(debug_test r5 5) + +;; Test str-to-i with non-string argument +(define r6 (eq (trap (str-to-i 42)) '(exit-error type_error))) + +(debug_test r6 6) + +;; Test str-to-i with non-number base argument +(define r7 (eq (trap (str-to-i "123" 'not-a-number)) '(exit-error type_error))) + +(debug_test r7 7) + +;; Test str-to-f with non-string argument +(define r8 (eq (trap (str-to-f 42)) '(exit-error type_error))) + +(debug_test r8 8) + +;; Test str-part with non-number second argument +(define r9 (eq (trap (str-part "hello" 'not-a-number)) '(exit-error type_error))) + +(debug_test r9 9) + +;; Test str-part with non-string first argument +(define r10 (eq (trap (str-part 42 1)) '(exit-error type_error))) + +(debug_test r10 10) + +;; Test str-part with non-number third argument +(define r11 (eq (trap (str-part "hello" 1 'not-a-number)) '(exit-error type_error))) + +(debug_test r11 11) + +;; Test str-split with wrong number of arguments +(define r12 (eq (trap (str-split "hello")) '(exit-error type_error))) + +(debug_test r12 12) + +;; Test str-split with non-string first argument +(define r13 (eq (trap (str-split 42 " ")) '(exit-error type_error))) + +(debug_test r13 13) + +;; Test str-split with non-string second argument (delimiter) +(define r14 (eq (ix (str-split "hello world" 42) 0) "hello world")) + +(debug_test r14 14) + +;; Test str-replace with non-string first argument +(define r15 (eq (trap (str-replace 42 "old" "new")) '(exit-error type_error))) + +(debug_test r15 15) + +;; Test str-replace with non-string second argument (pattern to replace) +(define r16 (eq (trap (str-replace "hello" 42 "new")) '(exit-error type_error))) + +(debug_test r16 16) + +;; Test str-replace with non-string third argument (replacement) +(define r17 (eq (trap (str-replace "hello" "old" 42)) '(exit-error type_error))) + +(debug_test r17 17) + +;; Test str-to-lower with non-string argument +(define r18 (eq (trap (str-to-lower 42)) '(exit-error type_error))) + +(debug_test r18 18) + +;; Test str-to-upper with non-string argument +(define r19 (eq (trap (str-to-upper 42)) '(exit-error type_error))) + +(debug_test r19 19) + +;; Test str-cmp with non-string first argument +(define r20 (eq (trap (str-cmp 42 "hello")) '(exit-error type_error))) + +(debug_test r20 20) + +;; Test str-cmp with non-string second argument +(define r21 (eq (trap (str-cmp "hello" 42)) '(exit-error type_error))) + +(debug_test r21 21) + +;; Test str-cmp with non-number third argument (length limit) +(define r22 (eq (trap (str-cmp "hello" "world" 'not-a-number)) '(exit-error type_error))) + +(debug_test r22 22) + +;; Test str-len with non-string argument +(define r23 (eq (trap (str-len 42)) '(exit-error type_error))) + +(debug_test r23 23) + +;; Test str-replicate with non-number first argument +(define r24 (eq (trap (str-replicate 'not-a-number 5)) '(exit-error type_error))) + +(debug_test r24 24) + +;; Test str-replicate with non-number second argument +(define r25 (eq (trap (str-replicate "hello" 'not-a-number)) '(exit-error type_error))) + +(debug_test r25 25) + +;; Test str-find with too few arguments (< 2) +(define r26 (eq (trap (str-find "hello")) '(exit-error eval_error))) + +(debug_test r26 26) + +;; Test str-find with too many arguments (> 6) +(define r27 (eq (trap (str-find "hello" "e" 0 5 t t t)) '(exit-error eval_error))) + +(debug_test r27 27) + +;; Test to-str-delim with no arguments +(define r28 (eq (trap (to-str-delim)) '(exit-error eval_error))) + +(debug_test r28 28) + +;; Test to-str-delim with non-string delimiter +(define r29 (eq (ix (trap (to-str-delim 42 "hello")) 0) 'exit-error)) + +(debug_test r29 29) + +(if (and r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 r26 r27 r28 r29) + (print "SUCCESS") + (print "FAILURE")) diff --git a/lispBM/lispBM/tests/repl_tests/test_unterminated_string.lisp b/lispBM/lispBM/tests/repl_tests/test_unterminated_string.lisp new file mode 100644 index 0000000000..e175179ce6 --- /dev/null +++ b/lispBM/lispBM/tests/repl_tests/test_unterminated_string.lisp @@ -0,0 +1,24 @@ +(hide-trapped-error) + +(define debug_test (lambda (x i) + (if (not x) (print "TEST " i " FAILED: " x)))) + +(define time-read-eval + (macro (str) + `(progn + (var t0 (systime)) + (var res (read-eval-program ,str)) + (print (- (systime) t0)) + res))) + +;; Test unterminated string from file (should trigger tokenizer error) +(define file-handle (fopen "repl_tests/test_data/unterminated_string.lisp" "r")) +(define unterminated-program (load-file file-handle)) +(fclose file-handle) +(define r1 (eq 'exit-error (car (trap (time-read-eval unterminated-program))))) + +(debug_test r1 1) + +(if r1 + (print "SUCCESS") + (print "FAILURE")) \ No newline at end of file diff --git a/lispBM/lispBM/tests/run_c_unit.sh b/lispBM/lispBM/tests/run_c_unit.sh index 6cf2a40044..698de9f15a 100755 --- a/lispBM/lispBM/tests/run_c_unit.sh +++ b/lispBM/lispBM/tests/run_c_unit.sh @@ -77,20 +77,19 @@ do fi done -echo "" -echo "C Unit Tests Summary:" -echo "Tests passed: $success_count" -echo "Tests failed: $fail_count" -echo "Expected fails: $expected_count" -echo "Actual fails: $((fail_count - expected_count))" - # Generate coverage report if gcovr is available if command -v gcovr &> /dev/null; then echo "Generating coverage report..." gcovr --filter ../../src --gcov-ignore-parse-errors=negative_hits.warn --json c_unit_tests_cov.json fi -cd .. + +echo "" +echo "C Unit Tests Summary:" +echo "Tests passed: $success_count" +echo "Tests failed: $fail_count" +echo "Expected fails: $expected_count" +echo "Actual fails: $((fail_count - expected_count))" if [ $((fail_count - expected_count)) -gt 0 ]; then exit 1 diff --git a/lispBM/lispBM/tests/test_lisp_code_cps.c b/lispBM/lispBM/tests/test_lisp_code_cps.c index a6ec2a8155..777e2f9fe7 100644 --- a/lispBM/lispBM/tests/test_lisp_code_cps.c +++ b/lispBM/lispBM/tests/test_lisp_code_cps.c @@ -38,6 +38,7 @@ #include "lbm_channel.h" #include "lbm_flat_value.h" #include "lbm_image.h" +#include "platform_timestamp.h" #define WAIT_TIMEOUT 2500 @@ -108,12 +109,6 @@ void *eval_thd_wrapper(void *v) { return NULL; } -uint32_t timestamp_callback() { - struct timeval tv; - gettimeofday(&tv,NULL); - return (uint32_t)(tv.tv_sec * 1000000 + tv.tv_usec); -} - void sleep_callback(uint32_t us) { struct timespec s; struct timespec r; @@ -461,9 +456,12 @@ int main(int argc, char **argv) { bool stream_source = false; bool incremental = false; + static pthread_t timestamp_thread = 0; pthread_t lispbm_thd; lbm_cons_t *heap_storage = NULL; + pthread_create(×tamp_thread, NULL, timestamp_cacher, NULL); + int c; opterr = 1; @@ -626,7 +624,6 @@ int main(int argc, char **argv) { } lbm_set_dynamic_load_callback(dyn_load); - lbm_set_timestamp_us_callback(timestamp_callback); lbm_set_usleep_callback(sleep_callback); lbm_set_printf_callback(printf); lbm_set_critical_error_callback(critical_error); diff --git a/lispBM/lispbm.mk b/lispBM/lispbm.mk index 0abe3a32d2..98884799ed 100644 --- a/lispBM/lispbm.mk +++ b/lispBM/lispbm.mk @@ -12,6 +12,7 @@ LISPBMSRC = $(LISPBM)/src/env.c \ $(LISPBM)/src/lispbm.c \ $(LISPBM)/src/eval_cps.c \ $(LISPBM)/platform/chibios/src/platform_mutex.c \ + $(LISPBM)/platform/chibios/src/platform_timestamp.c \ $(LISPBM)/src/lbm_channel.c \ $(LISPBM)/src/lbm_c_interop.c \ $(LISPBM)/src/lbm_custom_type.c \ diff --git a/lispBM/lispif.c b/lispBM/lispif.c index c930894cbc..f7cf7003c6 100644 --- a/lispBM/lispif.c +++ b/lispBM/lispif.c @@ -37,7 +37,7 @@ #define LBM_MEMORY_BITMAP_SIZE_28K LBM_MEMORY_BITMAP_SIZE(448) #ifndef EXTENSION_STORAGE_SIZE -#define EXTENSION_STORAGE_SIZE 306 +#define EXTENSION_STORAGE_SIZE 311 #endif #ifndef ADC_SAMPLE_MAX_LEN @@ -83,7 +83,6 @@ static int restart_cnt = 0; static volatile bool const_write_error = false; // Private functions -static uint32_t timestamp_callback(void); static void sleep_callback(uint32_t us); static bool image_write(uint32_t w, int32_t ix, bool const_heap); @@ -737,7 +736,6 @@ bool lispif_restart(bool print, bool load_code, bool load_imports) { PRINT_STACK_SIZE, extension_storage, EXTENSION_STORAGE_SIZE); - lbm_set_timestamp_us_callback(timestamp_callback); lbm_set_usleep_callback(sleep_callback); lbm_set_printf_callback(commands_printf_lisp); lbm_set_ctx_done_callback(done_callback); @@ -867,11 +865,6 @@ lbm_uint lispif_const_heap_max_ind(void) { return image_max_ind; } -static uint32_t timestamp_callback(void) { - systime_t t = chVTGetSystemTimeX(); - return (uint32_t) ((1000000 / CH_CFG_ST_FREQUENCY) * t); -} - static void sleep_callback(uint32_t us) { chThdSleepMicroseconds(us); } diff --git a/lispBM/lispif_c_lib.c b/lispBM/lispif_c_lib.c index 2a3ccb3b36..38f629daea 100644 --- a/lispBM/lispif_c_lib.c +++ b/lispBM/lispif_c_lib.c @@ -90,6 +90,8 @@ static THD_FUNCTION(lib_thd, arg) { lib_thd_info *t = (lib_thd_info*)arg; chRegSetThreadName(t->name); t->func(t->arg); + + // TODO: Lock system here? lbm_free(t->w_mem); lbm_free(t); } diff --git a/lispBM/lispif_vesc_extensions.c b/lispBM/lispif_vesc_extensions.c index 82b8483bfe..d33f33e4bd 100644 --- a/lispBM/lispif_vesc_extensions.c +++ b/lispBM/lispif_vesc_extensions.c @@ -217,6 +217,7 @@ typedef struct { lbm_uint m_ntcx_ptcx_res; lbm_uint m_encoder_counts; lbm_uint m_sensor_port_mode; + lbm_uint m_fault_stop_time_ms; lbm_uint si_motor_poles; lbm_uint si_gear_ratio; lbm_uint si_wheel_diameter; @@ -227,6 +228,7 @@ typedef struct { lbm_uint controller_id; lbm_uint timeout_msec; lbm_uint can_baud_rate; + lbm_uint can_mode; lbm_uint can_status_rate_1; lbm_uint can_status_msgs_r1; lbm_uint can_status_rate_2; @@ -238,6 +240,7 @@ typedef struct { lbm_uint ppm_pulse_center; lbm_uint ppm_ramp_time_pos; lbm_uint ppm_ramp_time_neg; + lbm_uint ppm_hyst; lbm_uint adc_ctrl_type; lbm_uint adc_ramp_time_pos; lbm_uint adc_ramp_time_neg; @@ -582,6 +585,8 @@ static bool compare_symbol(lbm_uint sym, lbm_uint *comp) { lbm_add_symbol_const("m-encoder-counts", comp); } else if (comp == &syms_vesc.m_sensor_port_mode) { lbm_add_symbol_const("m-sensor-port-mode", comp); + } else if (comp == &syms_vesc.m_fault_stop_time_ms) { + lbm_add_symbol_const("m-fault-stop-time-ms", comp); } else if (comp == &syms_vesc.si_motor_poles) { lbm_add_symbol_const("si-motor-poles", comp); } else if (comp == &syms_vesc.si_gear_ratio) { @@ -602,6 +607,8 @@ static bool compare_symbol(lbm_uint sym, lbm_uint *comp) { lbm_add_symbol_const("timeout-msec", comp); } else if (comp == &syms_vesc.can_baud_rate) { lbm_add_symbol_const("can-baud-rate", comp); + } else if (comp == &syms_vesc.can_mode) { + lbm_add_symbol_const("can-mode", comp); } else if (comp == &syms_vesc.can_status_rate_1) { lbm_add_symbol_const("can-status-rate-1", comp); } else if (comp == &syms_vesc.can_status_msgs_r1) { @@ -624,6 +631,8 @@ static bool compare_symbol(lbm_uint sym, lbm_uint *comp) { lbm_add_symbol_const("ppm-ramp-time-pos", comp); } else if (comp == &syms_vesc.ppm_ramp_time_neg) { lbm_add_symbol_const("ppm-ramp-time-neg", comp); + } else if (comp == &syms_vesc.ppm_hyst) { + lbm_add_symbol_const("ppm-hyst", comp); } else if (comp == &syms_vesc.adc_ctrl_type) { lbm_add_symbol_const("adc-ctrl-type", comp); } else if (comp == &syms_vesc.adc_ramp_time_pos) { @@ -2303,6 +2312,71 @@ static lbm_value ext_observer_error(lbm_value *args, lbm_uint argn) { return lbm_enc_float(utils_angle_difference(mcpwm_foc_get_phase_observer(), mcpwm_foc_get_phase_encoder())); } +static lbm_value ext_phase_all(lbm_value *args, lbm_uint argn) { + (void)args; (void)argn; + + float phase_observer = mcpwm_foc_get_phase_observer(); + float phase_encoder = mcpwm_foc_get_phase_encoder(); + float phase_bemf = mcpwm_foc_get_phase_bemf(); + float pos_encoder = encoder_read_deg(); + + float err_observer_encoder = utils_angle_difference(mcpwm_foc_get_phase_observer(), mcpwm_foc_get_phase_encoder()); + float err_bemf_encoder = utils_angle_difference(mcpwm_foc_get_phase_bemf(), mcpwm_foc_get_phase_encoder()); + float err_observer_bemf = utils_angle_difference(mcpwm_foc_get_phase_observer(), mcpwm_foc_get_phase_bemf()); + + lbm_value phase_all = ENC_SYM_NIL; + phase_all = lbm_cons(lbm_enc_float(err_observer_bemf), phase_all); + phase_all = lbm_cons(lbm_enc_float(err_bemf_encoder), phase_all); + phase_all = lbm_cons(lbm_enc_float(err_observer_encoder), phase_all); + phase_all = lbm_cons(lbm_enc_float(pos_encoder), phase_all); + phase_all = lbm_cons(lbm_enc_float(phase_bemf), phase_all); + phase_all = lbm_cons(lbm_enc_float(phase_encoder), phase_all); + phase_all = lbm_cons(lbm_enc_float(phase_observer), phase_all); + + return phase_all; + +} + +static lbm_value ext_enc_corr(lbm_value *args, lbm_uint argn) { + LBM_CHECK_NUMBER_ALL(); + + if (argn != 1 && argn != 2) { + return ENC_SYM_TERROR; + } + + int ind = lbm_dec_as_i32(args[0]); + + if (ind < 0 || ind >= 360) { + return ENC_SYM_TERROR; + } + + if (argn >= 2) { + int corr = lbm_dec_as_i32(args[1]); + + if (corr < -120 || corr > 120) { + return ENC_SYM_TERROR; + } + + g_backup.enc_corr[ind] = corr; + } + + return lbm_enc_i(g_backup.enc_corr[ind]); +} + +static lbm_value ext_enc_corr_en(lbm_value *args, lbm_uint argn) { + LBM_CHECK_NUMBER_ALL(); + + if (argn > 1) { + return ENC_SYM_TERROR; + } + + if (argn == 1) { + g_backup.enc_corr_en = lbm_dec_as_i32(args[0]); + } + + return lbm_enc_i(g_backup.enc_corr_en); +} + // CAN-commands static lbm_value ext_can_msg_age(lbm_value *args, lbm_uint argn) { @@ -3632,6 +3706,9 @@ static lbm_value ext_conf_set(lbm_value *args, lbm_uint argn) { } else if (compare_symbol(name, &syms_vesc.m_ntcx_ptcx_res)) { mcconf->m_ntcx_ptcx_res = lbm_dec_as_float(args[1]); changed_mc = 1; + } else if (compare_symbol(name, &syms_vesc.m_fault_stop_time_ms)) { + mcconf->m_fault_stop_time_ms = lbm_dec_as_i32(args[1]); + changed_mc = 1; } else if (compare_symbol(name, &syms_vesc.si_motor_poles)) { mcconf->si_motor_poles = lbm_dec_as_i32(args[1]); changed_mc = 1; @@ -3820,6 +3897,9 @@ static lbm_value ext_conf_set(lbm_value *args, lbm_uint argn) { } else if (compare_symbol(name, &syms_vesc.can_baud_rate)) { appconf->can_baud_rate = lbm_dec_as_i32(args[1]); changed_app = 2; + } else if (compare_symbol(name, &syms_vesc.can_mode)) { + appconf->can_mode = lbm_dec_as_i32(args[1]); + changed_app = 2; } else if (compare_symbol(name, &syms_vesc.app_to_use)) { appconf->app_to_use = lbm_dec_as_i32(args[1]); changed_app = 2; @@ -3841,6 +3921,9 @@ static lbm_value ext_conf_set(lbm_value *args, lbm_uint argn) { } else if (compare_symbol(name, &syms_vesc.ppm_ramp_time_neg)) { appconf->app_ppm_conf.ramp_time_neg = lbm_dec_as_float(args[1]); changed_app = 2; + } else if (compare_symbol(name, &syms_vesc.ppm_hyst)) { + appconf->app_ppm_conf.hyst = lbm_dec_as_float(args[1]); + changed_app = 2; } else if (compare_symbol(name, &syms_vesc.adc_ctrl_type)) { appconf->app_adc_conf.ctrl_type = lbm_dec_as_i32(args[1]); changed_app = 2; @@ -4150,6 +4233,8 @@ static lbm_value ext_conf_get(lbm_value *args, lbm_uint argn) { res = lbm_enc_float(mcconf->m_encoder_counts); } else if (compare_symbol(name, &syms_vesc.m_sensor_port_mode)) { res = lbm_enc_i(mcconf->m_sensor_port_mode); + } else if (compare_symbol(name, &syms_vesc.m_fault_stop_time_ms)) { + res = lbm_enc_i(mcconf->m_fault_stop_time_ms); } else if (compare_symbol(name, &syms_vesc.si_motor_poles)) { res = lbm_enc_i(mcconf->si_motor_poles); } else if (compare_symbol(name, &syms_vesc.si_gear_ratio)) { @@ -4170,6 +4255,8 @@ static lbm_value ext_conf_get(lbm_value *args, lbm_uint argn) { res = lbm_enc_i(appconf->timeout_msec); } else if (compare_symbol(name, &syms_vesc.can_baud_rate)) { res = lbm_enc_i(appconf->can_baud_rate); + } else if (compare_symbol(name, &syms_vesc.can_mode)) { + res = lbm_enc_i(appconf->can_mode); } else if (compare_symbol(name, &syms_vesc.can_status_rate_1)) { res = lbm_enc_u(appconf->can_status_rate_1); } else if (compare_symbol(name, &syms_vesc.can_status_msgs_r1)) { @@ -4192,6 +4279,8 @@ static lbm_value ext_conf_get(lbm_value *args, lbm_uint argn) { res = lbm_enc_float(appconf->app_ppm_conf.ramp_time_pos); } else if (compare_symbol(name, &syms_vesc.ppm_ramp_time_neg)) { res = lbm_enc_float(appconf->app_ppm_conf.ramp_time_neg); + } else if (compare_symbol(name, &syms_vesc.ppm_hyst)) { + res = lbm_enc_float(appconf->app_ppm_conf.hyst); } else if (compare_symbol(name, &syms_vesc.adc_ctrl_type)) { res = lbm_enc_i(appconf->app_adc_conf.ctrl_type); } else if (compare_symbol(name, &syms_vesc.adc_ramp_time_pos)) { @@ -4237,11 +4326,14 @@ static lbm_value ext_conf_store(lbm_value *args, lbm_uint argn) { bool res_app = conf_general_store_app_configuration(appconf); mempools_free_appconf(appconf); - conf_general_store_backup_data(); - return lbm_enc_sym((res_mc && res_app) ? SYM_TRUE : SYM_NIL); } +static lbm_value ext_store_backup(lbm_value *args, lbm_uint argn) { + (void)args; (void)argn; + return lbm_enc_sym(conf_general_store_backup_data() ? SYM_TRUE : SYM_NIL); +} + typedef struct { bool detect_can; float max_power_loss; @@ -4270,6 +4362,7 @@ static void detect_task(void *arg) { static lbm_value ext_conf_detect_foc(lbm_value *args, lbm_uint argn) { LBM_CHECK_ARGN_NUMBER(6); static detect_args a; + a.detect_can = lbm_dec_as_i32(args[0]); a.max_power_loss = lbm_dec_as_float(args[1]); a.min_current_in = lbm_dec_as_float(args[2]); @@ -4278,8 +4371,17 @@ static lbm_value ext_conf_detect_foc(lbm_value *args, lbm_uint argn) { a.sl_erpm = lbm_dec_as_float(args[5]); a.id = lbm_get_current_cid(); a.motor = mc_interface_get_motor_thread(); + +#ifdef HW_HAS_DUAL_MOTORS + if (!lispif_spawn(detect_task, 1024, "lbm_detect", &a)) { + return ENC_SYM_MERROR; + } + lbm_block_ctx_from_extension(); +#else lbm_block_ctx_from_extension(); worker_execute(detect_task, &a); +#endif + return ENC_SYM_TRUE; } @@ -4451,8 +4553,8 @@ static lbm_value ext_conf_measure_ind(lbm_value *args, lbm_uint argn) { return ENC_SYM_EERROR; } - worker_execute(measure_inductance_task, &a); lbm_block_ctx_from_extension(); + worker_execute(measure_inductance_task, &a); return ENC_SYM_TRUE; } @@ -4690,8 +4792,95 @@ static lbm_value ext_conf_detect_lambda_enc(lbm_value *args, lbm_uint argn) { a.id = lbm_get_current_cid(); a.motor = mc_interface_get_motor_thread(); +#ifdef HW_HAS_DUAL_MOTORS + if (!lispif_spawn(measure_lambda_enc_task, 1024, "lbm_detect", &a)) { + return ENC_SYM_MERROR; + } + lbm_block_ctx_from_extension(); +#else + lbm_block_ctx_from_extension(); worker_execute(measure_lambda_enc_task, &a); +#endif + + return ENC_SYM_TRUE; +} + +typedef struct { + float current; + lbm_cid id; + int motor; +} measure_hall_args; + +static void measure_hall_task(void *arg) { + int restart_cnt = lispif_get_restart_cnt(); + + measure_hall_args *a = (measure_hall_args*)arg; + + lbm_flat_value_t v; + bool ok = false; + if (lbm_start_flatten(&v, 20)) { + mc_interface_select_motor_thread(a->motor); + + uint8_t hall_tab[8]; + bool result; + int fault = mcpwm_foc_hall_detect(a->current, hall_tab, &result); + + mc_interface_select_motor_thread(1); + + if (restart_cnt != lispif_get_restart_cnt()) { + return; + } + + if (fault) { + f_i(&v, fault); + } else if (!result) { + f_sym(&v, SYM_NIL); + } else { + f_lbm_array(&v, 8, hall_tab); + } + + lbm_finish_flatten(&v); + if (lbm_unblock_ctx(a->id, &v)) { + ok = true; + } else { + lbm_free(v.buf); + } + } + + if (!ok) { + lbm_unblock_ctx_unboxed(a->id, ENC_SYM_NIL); + } +} + +static lbm_value ext_conf_detect_hall(lbm_value *args, lbm_uint argn) { + LBM_CHECK_ARGN_NUMBER(1); + + float current = lbm_dec_as_float(args[0]); + + if (!(current > 0.0 && current <= mc_interface_get_configuration()->l_current_max)) { + lbm_set_error_reason(lbm_error_str_incorrect_arg); + return ENC_SYM_TERROR; + } + + if (mc_interface_get_configuration()->motor_type != MOTOR_TYPE_FOC) { + return ENC_SYM_EERROR; + } + + static measure_hall_args a; + a.current = current; + a.id = lbm_get_current_cid(); + a.motor = mc_interface_get_motor_thread(); + +#ifdef HW_HAS_DUAL_MOTORS + if (!lispif_spawn(measure_hall_task, 1024, "lbm_detect", &a)) { + return ENC_SYM_MERROR; + } lbm_block_ctx_from_extension(); +#else + lbm_block_ctx_from_extension(); + worker_execute(measure_hall_task, &a); +#endif + return ENC_SYM_TRUE; } @@ -5876,6 +6065,9 @@ void lispif_load_vesc_extensions(bool main_found) { lbm_add_extension("phase-hall", ext_phase_hall); lbm_add_extension("phase-observer", ext_phase_observer); lbm_add_extension("observer-error", ext_observer_error); + lbm_add_extension("phase-all", ext_phase_all); + lbm_add_extension("enc-corr", ext_enc_corr); + lbm_add_extension("enc-corr-en", ext_enc_corr_en); // Setup values lbm_add_extension("setup-ah", ext_setup_ah); @@ -5961,6 +6153,7 @@ void lispif_load_vesc_extensions(bool main_found) { lbm_add_extension("conf-set", ext_conf_set); lbm_add_extension("conf-get", ext_conf_get); lbm_add_extension("conf-store", ext_conf_store); + lbm_add_extension("store-backup", ext_store_backup); lbm_add_extension("conf-detect-foc", ext_conf_detect_foc); lbm_add_extension("conf-set-pid-offset", ext_conf_set_pid_offset); lbm_add_extension("conf-measure-res", ext_conf_measure_res); @@ -5972,6 +6165,7 @@ void lispif_load_vesc_extensions(bool main_found) { lbm_add_extension("conf-enc-sincos", ext_conf_enc_sincos); lbm_add_extension("conf-get-limits", ext_conf_get_limits); lbm_add_extension("conf-detect-lambda-enc", ext_conf_detect_lambda_enc); + lbm_add_extension("conf-detect-hall", ext_conf_detect_hall); // Native libraries lbm_add_extension("load-native-lib", ext_load_native_lib); diff --git a/main.c b/main.c index 4a0caeb6b3..4dc7a002f0 100644 --- a/main.c +++ b/main.c @@ -60,6 +60,7 @@ #include "mempools.h" #include "events.h" #include "main.h" +#include "blackbox.h" #ifdef CAN_ENABLE #include "comm_can.h" @@ -286,6 +287,7 @@ int main(void) { } ledpwm_init(); + blackbox_init(); mc_interface_init(); commands_init(); diff --git a/make/fw.mk b/make/fw.mk index 7b63d603da..d253e2a32a 100755 --- a/make/fw.mk +++ b/make/fw.mk @@ -10,7 +10,7 @@ ifeq ($(USE_OPT),) USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 -std=gnu99 -D_GNU_SOURCE USE_OPT += -DBOARD_OTG_NOVBUSSENS $(build_args) USE_OPT += -DLBM_USE_DYN_FUNS -DLBM_USE_DYN_MACROS -DLBM_USE_DYN_LOOPS -DLBM_USE_TIME_QUOTA - USE_OPT += -DLBM_USE_ERROR_LINENO + USE_OPT += -DLBM_USE_ERROR_LINENO -DLBM_USE_MACRO_REST_ARGS # USE_OPT += -DUSE_GC_PTR_REV USE_OPT += -fsingle-precision-constant -Wdouble-promotion -specs=nosys.specs endif @@ -112,6 +112,7 @@ include libcanard/canard.mk include imu/imu.mk include blackmagic/blackmagic.mk include encoder/encoder.mk +include blackbox/blackbox.mk ifeq ($(USE_LISPBM),1) include lispBM/lispbm.mk @@ -147,6 +148,7 @@ CSRC = $(STARTUPSRC) \ $(BLACKMAGICSRC) \ qmlui/qmlui.c \ $(ENCSRC) \ + $(BLACKBOXSRC) \ conf_custom.c ifeq ($(USE_LISPBM),1) @@ -192,7 +194,8 @@ INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ qmlui \ qmlui/hw \ qmlui/app \ - $(ENCINC) + $(ENCINC) \ + $(BLACKBOXINC) include comm/comm.mk include motor/motor.mk diff --git a/motor/RTT_motor.h b/motor/RTT_motor.h new file mode 100644 index 0000000000..d3074c6f4f --- /dev/null +++ b/motor/RTT_motor.h @@ -0,0 +1,608 @@ +// This file is autogenerated by VESC Tool + +#ifndef RTT_MOTOR_H_ +#define RTT_MOTOR_H_ + +// PWM Mode +#define MCCONF_PWM_MODE 1 + +// Commutation Mode +#define MCCONF_COMM_MODE 0 + +// Motor Type +#define MCCONF_DEFAULT_MOTOR_TYPE 2 + +// Sensor Mode +#define MCCONF_SENSOR_MODE 0 + +// Motor Current Max +#define MCCONF_L_CURRENT_MAX 35.2106 + +// Motor Current Max Brake +#define MCCONF_L_CURRENT_MIN -35.2106 + +// Battery Current Max +#define MCCONF_L_IN_CURRENT_MAX 250 + +// Battery Current Max Regen +#define MCCONF_L_IN_CURRENT_MIN -200 + +// Input Current Limit Map Start +#define MCCONF_L_IN_CURRENT_MAP_START 1 + +// Input Current Map Filter +#define MCCONF_L_IN_CURRENT_MAP_FILTER 0.005 + +// Absolute Maximum Current +#define MCCONF_L_MAX_ABS_CURRENT 52.8159 + +// Max ERPM Reverse +#define MCCONF_L_RPM_MIN -100000 + +// Max ERPM +#define MCCONF_L_RPM_MAX 100000 + +// ERPM Limit Start +#define MCCONF_L_RPM_START 0.8 + +// Max ERPM Full Brake +#define MCCONF_L_CURR_MAX_RPM_FBRAKE 300 + +// Max ERPM Full Brake Current Control +#define MCCONF_L_CURR_MAX_RPM_FBRAKE_CC 1500 + +// Minimum Input Voltage +#define MCCONF_L_MIN_VOLTAGE 12 + +// Maximum Input Voltage +#define MCCONF_L_MAX_VOLTAGE 72 + +// Battery Voltage Cutoff Start +#define MCCONF_L_BATTERY_CUT_START 20.4 + +// Battery Voltage Cutoff End +#define MCCONF_L_BATTERY_CUT_END 18 + +// Battery Voltage Regen Cutoff Start +#define MCCONF_L_BATTERY_REGEN_CUT_START 1000 + +// Battery Voltage Regen Cutoff End +#define MCCONF_L_BATTERY_REGEN_CUT_END 1100 + +// Slow ABS Current Limit +#define MCCONF_L_SLOW_ABS_OVERCURRENT 0 + +// MOSFET Temp Cutoff Start +#define MCCONF_L_LIM_TEMP_FET_START 85 + +// MOSFET Temp Cutoff End +#define MCCONF_L_LIM_TEMP_FET_END 100 + +// Motor Temp Cutoff Start +#define MCCONF_L_LIM_TEMP_MOTOR_START 85 + +// Motor Temp Cutoff End +#define MCCONF_L_LIM_TEMP_MOTOR_END 100 + +// Acceleration Temperature Decrease +#define MCCONF_L_LIM_TEMP_ACCEL_DEC 0.15 + +// Minimum Duty Cycle +#define MCCONF_L_MIN_DUTY 0.005 + +// Maximum Duty Cycle +#define MCCONF_L_MAX_DUTY 0.95 + +// Maximum Wattage +#define MCCONF_L_WATT_MAX 1.5e+06 + +// Maximum Braking Wattage +#define MCCONF_L_WATT_MIN -1.5e+06 + +// Max Current Scale +#define MCCONF_L_CURRENT_MAX_SCALE 1 + +// Min Current Scale +#define MCCONF_L_CURRENT_MIN_SCALE 1 + +// Duty Cycle Current Limit Start +#define MCCONF_L_DUTY_START 1 + +// Minimum ERPM +#define MCCONF_SL_MIN_RPM 150 + +// Minimum ERPM Integrator +#define MCCONF_SL_MIN_ERPM_CYCLE_INT_LIMIT 1100 + +// Max Brake Current at Direction Change +#define MCCONF_SL_MAX_FB_CURR_DIR_CHANGE 10 + +// Cycle Integrator Limit +#define MCCONF_SL_CYCLE_INT_LIMIT 62 + +// Phase Advance at BR ERPM +#define MCCONF_SL_PHASE_ADVANCE_AT_BR 0.8 + +// BR ERPM +#define MCCONF_SL_CYCLE_INT_BR 80000 + +// BEMF Coupling +#define MCCONF_SL_BEMF_COUPLING_K 600 + +// Hall Table [0] +#define MCCONF_HALL_TAB_0 -1 + +// Hall Table [1] +#define MCCONF_HALL_TAB_1 1 + +// Hall Table [2] +#define MCCONF_HALL_TAB_2 3 + +// Hall Table [3] +#define MCCONF_HALL_TAB_3 2 + +// Hall Table [4] +#define MCCONF_HALL_TAB_4 5 + +// Hall Table [5] +#define MCCONF_HALL_TAB_5 6 + +// Hall Table [6] +#define MCCONF_HALL_TAB_6 4 + +// Hall Table [7] +#define MCCONF_HALL_TAB_7 -1 + +// Sensorless ERPM Hybrid +#define MCCONF_HALL_ERPM 2000 + +// Current KP +#define MCCONF_FOC_CURRENT_KP 0.0399033 + +// Current KI +#define MCCONF_FOC_CURRENT_KI 75.2818 + +// Zero Vector Frequency +#define MCCONF_FOC_F_ZV 30000 + +// Dead Time Compensation +#define MCCONF_FOC_DT_US 0.12 + +// Encoder Inverted +#define MCCONF_FOC_ENCODER_INVERTED 0 + +// Encoder Offset +#define MCCONF_FOC_ENCODER_OFFSET 180 + +// Encoder Ratio +#define MCCONF_FOC_ENCODER_RATIO 7 + +// Sensor Mode +#define MCCONF_FOC_SENSOR_MODE 0 + +// Speed Tracker Kp +#define MCCONF_FOC_PLL_KP 2000 + +// Speed Tracker Ki +#define MCCONF_FOC_PLL_KI 30000 + +// Motor Inductance (L) +#define MCCONF_FOC_MOTOR_L 3.99033e-05 + +// Motor Inductance Difference (Lq - Ld) +#define MCCONF_FOC_MOTOR_LD_LQ_DIFF 1.83806e-05 + +// Motor Resistance (R) +#define MCCONF_FOC_MOTOR_R 0.0752818 + +// Motor Flux Linkage (¦Ë) +#define MCCONF_FOC_MOTOR_FLUX_LINKAGE 0.0101199 + +// Observer Gain (x1M) +#define MCCONF_FOC_OBSERVER_GAIN 9.76449e+06 + +// Observer Gain At Minimum Duty +#define MCCONF_FOC_OBSERVER_GAIN_SLOW 0.05 + +// Observer Offset +#define MCCONF_FOC_OBSERVER_OFFSET -1 + +// Duty Downramp Kp +#define MCCONF_FOC_DUTY_DOWNRAMP_KP 50 + +// Duty Downramp Ki +#define MCCONF_FOC_DUTY_DOWNRAMP_KI 1000 + +// Start Current Decrease +#define MCCONF_FOC_START_CURR_DEC 1 + +// Start Current Decrease ERPM +#define MCCONF_FOC_START_CURR_DEC_RPM 2500 + +// Openloop ERPM +#define MCCONF_FOC_OPENLOOP_RPM 700 + +// Openloop ERPM at Min Current +#define MCCONF_FOC_OPENLOOP_RPM_LOW 0 + +// D Axis Gain Scaling Start +#define MCCONF_FOC_D_GAIN_SCALE_START 0.9 + +// D Axis Gain Scaling at Max Mod +#define MCCONF_FOC_D_GAIN_SCALE_MAX_MOD 0.9 + +// Openloop Hysteresis +#define MCCONF_FOC_SL_OPENLOOP_HYST 0.1 + +// Openloop Lock Time +#define MCCONF_FOC_SL_OPENLOOP_T_LOCK 0 + +// Openloop Ramp Time +#define MCCONF_FOC_SL_OPENLOOP_T_RAMP 0.1 + +// Openloop Time +#define MCCONF_FOC_SL_OPENLOOP_TIME 0.05 + +// Openloop Current Boost +#define MCCONF_FOC_SL_OPENLOOP_BOOST_Q 0 + +// Openloop Current Max +#define MCCONF_FOC_SL_OPENLOOP_MAX_Q -1 + +// Hall Table [0] +#define MCCONF_FOC_HALL_TAB_0 255 + +// Hall Table [1] +#define MCCONF_FOC_HALL_TAB_1 89 + +// Hall Table [2] +#define MCCONF_FOC_HALL_TAB_2 24 + +// Hall Table [3] +#define MCCONF_FOC_HALL_TAB_3 52 + +// Hall Table [4] +#define MCCONF_FOC_HALL_TAB_4 151 + +// Hall Table [5] +#define MCCONF_FOC_HALL_TAB_5 121 + +// Hall Table [6] +#define MCCONF_FOC_HALL_TAB_6 190 + +// Hall Table [7] +#define MCCONF_FOC_HALL_TAB_7 255 + +// Hall Interpolation ERPM +#define MCCONF_FOC_HALL_INTERP_ERPM 500 + +// Sensored ERPM Start +#define MCCONF_FOC_SL_ERPM_START 2500 + +// Sensorless ERPM +#define MCCONF_FOC_SL_ERPM 4000 + +// Control Sample Mode +#define MCCONF_FOC_CONTROL_SAMPLE_MODE 0 + +// Current Sample Mode +#define MCCONF_FOC_CURRENT_SAMPLE_MODE 0 + +// Saturation Compensation Mode +#define MCCONF_FOC_SAT_COMP_MODE 0 + +// Saturation Compensation Factor +#define MCCONF_FOC_SAT_COMP 0 + +// Temp Comp +#define MCCONF_FOC_TEMP_COMP 1 + +// Temp Comp Base Temp +#define MCCONF_FOC_TEMP_COMP_BASE_TEMP 33.5 + +// Current Filter Constant +#define MCCONF_FOC_CURRENT_FILTER_CONST 0.1 + +// Current Controller Decoupling +#define MCCONF_FOC_CC_DECOUPLING 0 + +// Observer Type +#define MCCONF_FOC_OBSERVER_TYPE 3 + +// HFI Ambiguity Resolve Mode +#define MCCONF_FOC_HFI_AMB_MODE 0 + +// HFI Ambiguity Resolve Current +#define MCCONF_FOC_HFI_AMB_CURRENT 60 + +// HFI Ambiguity Resolve Threshold +#define MCCONF_FOC_HFI_AMB_TRES 15 + +// HFI Start Voltage +#define MCCONF_FOC_HFI_VOLTAGE_START 20 + +// HFI Run Voltage +#define MCCONF_FOC_HFI_VOLTAGE_RUN 4 + +// HFI Max Voltage +#define MCCONF_FOC_HFI_VOLTAGE_MAX 6 + +// HFI Gain +#define MCCONF_FOC_HFI_GAIN 0.3 + +// HFI Max Error +#define MCCONF_FOC_HFI_MAX_ERR 0.3 + +// HFI Current Hysteresis +#define MCCONF_FOC_HFI_HYST 0 + +// Sensorless ERPM HFI +#define MCCONF_FOC_SL_ERPM_HFI 3000 + +// HFI Start Samples +#define MCCONF_FOC_HFI_START_SAMPLES 5 + +// HFI Observer Override Time +#define MCCONF_FOC_HFI_OBS_OVR_SEC 0.001 + +// HFI Samples +#define MCCONF_FOC_HFI_SAMPLES 1 + +// Offset Calibration Mode +#define MCCONF_FOC_OFFSETS_CAL_MODE 1 + +// Current Offset 0 +#define MCCONF_FOC_OFFSETS_CURRENT_0 2047.91 + +// Current Offset 1 +#define MCCONF_FOC_OFFSETS_CURRENT_1 2047.22 + +// Current Offset 2 +#define MCCONF_FOC_OFFSETS_CURRENT_2 2045.74 + +// Voltage Offset 0 +#define MCCONF_FOC_OFFSETS_VOLTAGE_0 0.0034 + +// Voltage Offset 1 +#define MCCONF_FOC_OFFSETS_VOLTAGE_1 -0.0032 + +// Voltage Offset 2 +#define MCCONF_FOC_OFFSETS_VOLTAGE_2 -0.0001 + +// Voltage Offset Undriven 0 +#define MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_0 0 + +// Voltage Offset Undriven 1 +#define MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_1 0 + +// Voltage Offset Undriven 2 +#define MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_2 0 + +// Enable Phase Filters +#define MCCONF_FOC_PHASE_FILTER_ENABLE 0 + +// Disable Phase Filter Fault Code +#define MCCONF_FOC_PHASE_FILTER_DISABLE_FAULT 1 + +// Maximum ERPM for phase filters +#define MCCONF_FOC_PHASE_FILTER_MAX_ERPM 4000 + +// MTPA Algorithm Mode +#define MCCONF_FOC_MTPA_MODE 0 + +// Field Weakening Current Max +#define MCCONF_FOC_FW_CURRENT_MAX 0 + +// Field Weakening Duty Start +#define MCCONF_FOC_FW_DUTY_START 0.9 + +// Field Weakening Ramp Time +#define MCCONF_FOC_FW_RAMP_TIME 0.2 + +// Q Axis Current Factor +#define MCCONF_FOC_FW_Q_CURRENT_FACTOR 0.02 + +// Speed Tracker Position Source +#define MCCONF_FOC_SPEED_SOURCE 0 + +// Short Low-Side FETs on Zero Duty +#define MCCONF_FOC_SHORT_LS_ON_ZERO_DUTY 0 + +// Overmodulation Factor +#define MCCONF_FOC_OVERMOD_FACTOR 1 + +// PID Loop Rate +#define MCCONF_SP_PID_LOOP_RATE 5 + +// Speed PID Kp +#define MCCONF_S_PID_KP 0.001 + +// Speed PID Ki +#define MCCONF_S_PID_KI 0.001 + +// Speed PID Kd +#define MCCONF_S_PID_KD 0.0001 + +// Speed PID Kd Filter +#define MCCONF_S_PID_KD_FILTER 0.2 + +// Minimum ERPM +#define MCCONF_S_PID_MIN_RPM 900 + +// Allow Braking +#define MCCONF_S_PID_ALLOW_BRAKING 1 + +// Ramp eRPMs per second +#define MCCONF_S_PID_RAMP_ERPMS_S 25000 + +// Speed Source +#define MCCONF_S_PID_SPEED_SOURCE 0 + +// Position PID Kp +#define MCCONF_P_PID_KP 0.025 + +// Position PID Ki +#define MCCONF_P_PID_KI 0 + +// Position PID Kd +#define MCCONF_P_PID_KD 0 + +// Position PID Kd Process +#define MCCONF_P_PID_KD_PROC 0.00035 + +// Position PID Kd Filter +#define MCCONF_P_PID_KD_FILTER 0.2 + +// Position Angle Division +#define MCCONF_P_PID_ANG_DIV 1 + +// Gain Decrease Angle +#define MCCONF_P_PID_GAIN_DEC_ANGLE 0 + +// Position PID Offset Angle +#define MCCONF_P_PID_OFFSET 0 + +// Startup boost +#define MCCONF_CC_STARTUP_BOOST_DUTY 0.01 + +// Minimum Current +#define MCCONF_CC_MIN_CURRENT 0.05 + +// Current Controller Gain +#define MCCONF_CC_GAIN 0.0046 + +// Current Control Ramp Step Max +#define MCCONF_CC_RAMP_STEP 0.04 + +// Fault Stop Time +#define MCCONF_M_FAULT_STOP_TIME 500 + +// Duty Ramp Step Max +#define MCCONF_M_RAMP_STEP 0.02 + +// Current Backoff Gain +#define MCCONF_M_CURRENT_BACKOFF_GAIN 0.5 + +// Encoder counts +#define MCCONF_M_ENCODER_COUNTS 8192 + +// Sine Amplitude +#define MCCONF_M_ENCODER_SIN_AMP 1 + +// Cosine Amplitude +#define MCCONF_M_ENCODER_COS_AMP 1 + +// Sine Offset +#define MCCONF_M_ENCODER_SIN_OFFSET 1.65 + +// Cosine Offset +#define MCCONF_M_ENCODER_COS_OFFSET 1.65 + +// Sin/Cos Filter Constant +#define MCCONF_M_ENCODER_SINCOS_FILTER 0.5 + +// Sin/Cos Phase Correction +#define MCCONF_M_ENCODER_SINCOS_PHASE 0 + +// Sensor Port Mode +#define MCCONF_M_SENSOR_PORT_MODE 0 + +// Invert Motor Direction +#define MCCONF_M_INVERT_DIRECTION 0 + +// DRV8301 OC Mode +#define MCCONF_M_DRV8301_OC_MODE 0 + +// DRV8301 OC Adjustment +#define MCCONF_M_DRV8301_OC_ADJ 16 + +// Minimum Switching Frequency +#define MCCONF_M_BLDC_F_SW_MIN 3000 + +// Maximum Switching Frequency +#define MCCONF_M_BLDC_F_SW_MAX 35000 + +// Switching Frequency +#define MCCONF_M_DC_F_SW 25000 + +// Beta Value for Motor Thermistor +#define MCCONF_M_NTC_MOTOR_BETA 3380 + +// Auxiliary Output Mode +#define MCCONF_M_OUT_AUX_MODE 0 + +// Motor Temperature Sensor Type +#define MCCONF_M_MOTOR_TEMP_SENS_TYPE 0 + +// Coefficient for PTC Motor Thermistor +#define MCCONF_M_PTC_MOTOR_COEFF 0.61 + +// Custom NTC/PTC Resistance +#define MCCONF_M_NTCX_PTCX_RES 10000 + +// Custom NTC/PTC Base Temperature +#define MCCONF_M_NTCX_PTCX_BASE_TEMP 25 + +// Hall Sensor Extra Samples +#define MCCONF_M_HALL_EXTRA_SAMPLES 3 + +// Battery Filter Constant +#define MCCONF_M_BATT_FILTER_CONST 45 + +// Motor Poles +#define MCCONF_SI_MOTOR_POLES 4 + +// Gear Ratio +#define MCCONF_SI_GEAR_RATIO 1 + +// Wheel Diameter +#define MCCONF_SI_WHEEL_DIAMETER 0.083 + +// Battery Type +#define MCCONF_SI_BATTERY_TYPE 0 + +// Battery Cells Series +#define MCCONF_SI_BATTERY_CELLS 6 + +// Battery Capacity +#define MCCONF_SI_BATTERY_AH 6 + +// Motor No Load Current +#define MCCONF_SI_MOTOR_NL_CURRENT 1 + +// BMS Type +#define MCCONF_BMS_TYPE 1 + +// BMS Limit Mode +#define MCCONF_BMS_LIMIT_MODE 3 + +// Temperature Limit Start +#define MCCONF_BMS_T_LIMIT_START 45 + +// Temperature Limit End +#define MCCONF_BMS_T_LIMIT_END 65 + +// SOC Limit Start +#define MCCONF_BMS_SOC_LIMIT_START 0.05 + +// SOC Limit End +#define MCCONF_BMS_SOC_LIMIT_END 0 + +// VCell Min Limit Start +#define MCCONF_BMS_VMIN_LIMIT_START 2.9 + +// VCell Min Limit End +#define MCCONF_BMS_VMIN_LIMIT_END 2.5 + +// VCell Max Limit Start +#define MCCONF_BMS_VMAX_LIMIT_START 4.2 + +// VCell Max Limit End +#define MCCONF_BMS_VMAX_LIMIT_END 4.3 + +// Forward CAN to Local +#define MCCONF_BMS_FWD_CAN_MODE 0 + +// RTT_MOTOR_H_ +#endif + diff --git a/motor/mc_interface.c b/motor/mc_interface.c index fb9928a72c..e16569bfd6 100644 --- a/motor/mc_interface.c +++ b/motor/mc_interface.c @@ -41,6 +41,7 @@ #include "crc.h" #include "bms.h" #include "events.h" +#include "blackbox.h" #include #include @@ -1847,6 +1848,10 @@ void mc_interface_fault_stop(mc_fault_code fault, bool is_second_motor, bool is_ m_fault_data.fault_code = fault; m_fault_data.is_second_motor = is_second_motor; + // Arm the blackbox post-trigger countdown at the exact trigger moment, + // before the fault_stop_thread runs. + blackbox_notify_fault((uint8_t)fault); + if (is_isr) { chSysLockFromISR(); chEvtSignalI(fault_stop_tp, (eventmask_t) 1); diff --git a/motor/mcconf_default.h b/motor/mcconf_default.h index 4ff8353a66..d0643f4f24 100644 --- a/motor/mcconf_default.h +++ b/motor/mcconf_default.h @@ -326,7 +326,7 @@ #define MCCONF_FOC_D_GAIN_SCALE_START 0.9 // Start reducing D axis current controller gain at this modulation #endif #ifndef MCCONF_FOC_D_GAIN_SCALE_MAX_MOD -#define MCCONF_FOC_D_GAIN_SCALE_MAX_MOD 0.2 // D axis currnet controller gain at maximum modulation +#define MCCONF_FOC_D_GAIN_SCALE_MAX_MOD 0.9 // D axis current controller gain at maximum modulation #endif #ifndef MCCONF_FOC_SL_OPENLOOP_HYST #define MCCONF_FOC_SL_OPENLOOP_HYST 0.1 // Time below min RPM to activate openloop (s) diff --git a/motor/mcpwm_foc.c b/motor/mcpwm_foc.c index 90c6d834fd..c805e7c37f 100644 --- a/motor/mcpwm_foc.c +++ b/motor/mcpwm_foc.c @@ -41,6 +41,7 @@ #include #include "virtual_motor.h" #include "foc_math.h" +#include "blackbox.h" // Private variables static volatile bool m_dccal_done = false; @@ -522,8 +523,11 @@ void mcpwm_foc_init(mc_configuration *conf_m1, mc_configuration *conf_m2) { // Wait for fault codes to go away if (!m_dccal_done) { - while (mc_interface_get_fault() != FAULT_CODE_NONE) { + while ((mc_interface_get_fault() != FAULT_CODE_NONE) && + (mc_interface_get_fault() != FAULT_CODE_OVER_TEMP_MOTOR)) { + chThdSleepMilliseconds(1); + if (UTILS_AGE_S(cal_start_time) >= cal_start_timeout) { m_dccal_done = true; break; @@ -1031,7 +1035,7 @@ float mcpwm_foc_get_duty_cycle_now(void) { } float mcpwm_foc_get_pid_speed_set(void) { - return get_motor_now()->m_speed_pid_set_rpm; + return get_motor_now()->m_speed_command_rpm; } float mcpwm_foc_get_pid_pos_set(void) { @@ -1107,12 +1111,12 @@ void mcpwm_foc_set_current_off_delay(float delay_sec) { float mcpwm_foc_get_tot_current_motor(bool is_second_motor) { volatile motor_all_state_t *motor = M_MOTOR(is_second_motor); - return SIGN(motor->m_motor_state.vq * motor->m_motor_state.iq) * motor->m_motor_state.i_abs; + return SIGN(motor->m_motor_state.i_bus) * motor->m_motor_state.i_abs; } float mcpwm_foc_get_tot_current_filtered_motor(bool is_second_motor) { volatile motor_all_state_t *motor = M_MOTOR(is_second_motor); - return SIGN(motor->m_motor_state.vq * motor->m_motor_state.iq_filter) * motor->m_motor_state.i_abs_filter; + return SIGN(motor->m_motor_state.i_bus) * motor->m_motor_state.i_abs_filter; } float mcpwm_foc_get_tot_current_in_motor(bool is_second_motor) { @@ -1393,6 +1397,13 @@ float mcpwm_foc_get_phase_observer(void) { return angle; } +float mcpwm_foc_get_phase_bemf(void) { + float phase_bemf = RAD2DEG_f(atan2f(mcpwm_foc_get_v_beta(), mcpwm_foc_get_v_alpha())); + phase_bemf -= 90.0; + utils_norm_angle(&phase_bemf); + return phase_bemf; +} + float mcpwm_foc_get_phase_encoder(void) { float angle = RAD2DEG_f(get_motor_now()->m_phase_now_encoder); utils_norm_angle(&angle); @@ -1429,6 +1440,14 @@ float mcpwm_foc_get_mod_beta_measured(void) { return get_motor_now()->m_motor_state.mod_beta_measured; } +float mcpwm_foc_get_v_alpha(void) { + return get_motor_now()->m_motor_state.v_alpha; +} + +float mcpwm_foc_get_v_beta(void) { + return get_motor_now()->m_motor_state.v_beta; +} + float mcpwm_foc_get_est_lambda(void) { return get_motor_now()->m_observer_state.lambda_est; } @@ -3140,18 +3159,18 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { if (tim->CCR1 <= tim->CCR2 && tim->CCR1 <= tim->CCR3) { // Curr 0 is best -// curr1 = curr0 * utils_fast_cos(phase_next - DEG2RAD_f(120.0)) / utils_fast_cos(phase_next); - curr1 = motor_now->m_motor_state.i_abs * utils_fast_sin(-phase_next - DEG2RAD_f(120.0)); + curr1 = curr0 * utils_fast_cos(phase_next - DEG2RAD_f(120.0)) / utils_fast_cos(phase_next); +// curr1 = motor_now->m_motor_state.i_abs * utils_fast_sin(-phase_next - DEG2RAD_f(120.0)); curr2 = -(curr0 + curr1); } else if (tim->CCR2 <= tim->CCR1 && tim->CCR2 <= tim->CCR3) { // Curr 1 is best -// curr0 = curr1 * utils_fast_cos(phase_next) / utils_fast_cos(phase_next - DEG2RAD_f(120.0)); - curr0 = motor_now->m_motor_state.i_abs * utils_fast_sin(-phase_next); + curr0 = curr1 * utils_fast_cos(phase_next) / utils_fast_cos(phase_next - DEG2RAD_f(120.0)); +// curr0 = motor_now->m_motor_state.i_abs * utils_fast_sin(-phase_next); curr2 = -(curr0 + curr1); } else if (tim->CCR3 <= tim->CCR1 && tim->CCR3 <= tim->CCR2) { // Curr 2 is best -// curr0 = curr2 * utils_fast_cos(phase_next) / utils_fast_cos(phase_next + DEG2RAD_f(120.0)); - curr0 = motor_now->m_motor_state.i_abs * utils_fast_sin(-phase_next); + curr0 = curr2 * utils_fast_cos(phase_next) / utils_fast_cos(phase_next + DEG2RAD_f(120.0)); +// curr0 = motor_now->m_motor_state.i_abs * utils_fast_sin(-phase_next); curr1 = -(curr0 + curr2); } } @@ -3162,20 +3181,28 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { tim->CCR3 > (tim->ARR - SHUNT_PICK_THR)) { full_clarke = false; - float phase_next = motor_now->m_motor_state.phase + motor_now->m_speed_est_fast * dt; + + float s = motor_now->m_motor_state.phase_sin; + float c = motor_now->m_motor_state.phase_cos; + + float predict_ia = c * motor_now->m_motor_state.id - s * motor_now->m_motor_state.iq; + float predict_ib = c * motor_now->m_motor_state.iq + s * motor_now->m_motor_state.id; if (tim->CCR1 <= tim->CCR2 && tim->CCR1 <= tim->CCR3) { // Curr 0 is best - curr1 = curr0 * utils_fast_cos(phase_next + DEG2RAD_f(120.0)) / utils_fast_cos(phase_next); + curr1 = -0.5 * predict_ia + SQRT3_BY_2 * predict_ib; curr2 = -(curr0 + curr1); } else if (tim->CCR2 <= tim->CCR1 && tim->CCR2 <= tim->CCR3) { // Curr 1 is best - curr0 = curr1 * utils_fast_cos(phase_next) / utils_fast_cos(phase_next - DEG2RAD_f(120.0)); + curr0 = predict_ia; curr2 = -(curr0 + curr1); } else if (tim->CCR3 <= tim->CCR1 && tim->CCR3 <= tim->CCR2) { // Curr 2 is best - curr0 = curr2 * utils_fast_cos(phase_next) / utils_fast_cos(phase_next + DEG2RAD_f(120.0)); - curr1 = -(curr0 + curr2); +// curr0 = predict_ia; +// curr1 = -(curr0 + curr2); + + curr1 = -0.5 * predict_ia + SQRT3_BY_2 * predict_ib; + curr0 = -(curr1 + curr2); } } #endif @@ -3214,8 +3241,18 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { if (conf_now->foc_encoder_inverted) { phase_tmp = 360.0 - phase_tmp; } + phase_tmp *= conf_now->foc_encoder_ratio; phase_tmp -= conf_now->foc_encoder_offset; + + // Apply error correction + if (g_backup.enc_corr_en == 1) { + utils_norm_angle((float*)(&enc_ang)); // Probably not needed + int corr_ind = (int)enc_ang; + utils_truncate_number_int(&corr_ind, 0, 359); + phase_tmp -= (float)g_backup.enc_corr[corr_ind]; + } + utils_norm_angle((float*)&phase_tmp); motor_now->m_phase_now_encoder = DEG2RAD_f(phase_tmp); } @@ -3502,7 +3539,8 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { // Apply MTPA. See: https://github.com/vedderb/bldc/pull/179 const float ld_lq_diff = conf_now->foc_motor_ld_lq_diff; - if (conf_now->foc_mtpa_mode != MTPA_MODE_OFF && ld_lq_diff != 0.0) { + if (conf_now->foc_mtpa_mode != MTPA_MODE_OFF && ld_lq_diff != 0.0 && + motor_now->m_control_mode != CONTROL_MODE_OPENLOOP_PHASE) { const float lambda = conf_now->foc_motor_flux_linkage; float iq_ref = iq_set_tmp; @@ -3608,7 +3646,14 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { case FOC_SENSOR_MODE_HFI_V5: case FOC_SENSOR_MODE_HFI_START:{ motor_now->m_motor_state.phase = motor_now->m_phase_now_observer; - if (fabsf(RADPS2RPM_f(motor_now->m_pll_speed)) < (conf_now->foc_sl_erpm_hfi * 1.1)) { + + // The Single and double pulse modes do not appear to work well when the motor + // already is spinning. Therefore use the openloop ERPM value for now, as it + // is a much lower value by default. TODO: This is a hack, look into this properly! + float rpm_tres = conf_now->foc_hfi_amb_mode == FOC_AMB_MODE_SIX_VECTOR ? + (conf_now->foc_sl_erpm_hfi * 1.1) : conf_now->foc_openloop_rpm; + + if (fabsf(RADPS2RPM_f(motor_now->m_pll_speed)) < rpm_tres) { motor_now->m_hfi.est_done_cnt = 0; motor_now->m_hfi.flip_cnt = 0; } @@ -3772,6 +3817,27 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { palSetPad(AD2S1205_SAMPLE_GPIO, AD2S1205_SAMPLE_PIN); #endif + // Blackbox: plain stores into a RAM ring buffer, no locks or formatting. + { + volatile bb_record_t *bb = blackbox_next_record_isr(); + if (bb) { + bb->ia = ia; + bb->ib = ib; + bb->ic = ic; + bb->id = motor_now->m_motor_state.id; + bb->iq = motor_now->m_motor_state.iq; + bb->i_abs = motor_now->m_motor_state.i_abs; + bb->i_abs_filter = motor_now->m_motor_state.i_abs_filter; + bb->duty_now = motor_now->m_motor_state.duty_now; + bb->v_bus = motor_now->m_motor_state.v_bus; + bb->phase = motor_now->m_motor_state.phase; + bb->speed_rad_s = motor_now->m_pll_speed; + bb->state = (uint8_t)motor_now->m_state; + bb->control_mode = (uint8_t)motor_now->m_control_mode; + blackbox_commit_isr(); + } + } + #ifdef HW_HAS_DUAL_MOTORS mc_interface_mc_timer_isr(is_second_motor); #else @@ -4548,14 +4614,19 @@ static void control_current(motor_all_state_t *motor, float dt) { // Saturation and anti-windup. Notice that the d-axis has priority as it controls field // weakening and the efficiency. - float vd_presat = state_m->vd; + //float vd_presat = state_m->vd; utils_truncate_number_abs((float*)&state_m->vd, max_v_mag); - state_m->vd_int += (state_m->vd - vd_presat); + utils_truncate_number_abs((float*)&state_m->vd_int, max_v_mag); + //Previously, the below line removed a large amount of voltage from the integrator, proportional to the overshoot from any noise and the Kp term. + //It is possible (likely even!) that a better implementation exists, than simple truncation, to max_v_mag, perhaps related to applying the Ki term to the integral truncation. + //state_m->vd_int += (state_m->vd - vd_presat); float max_vq = sqrtf(SQ(max_v_mag) - SQ(state_m->vd)); - float vq_presat = state_m->vq; + //float vq_presat = state_m->vq; utils_truncate_number_abs((float*)&state_m->vq, max_vq); - state_m->vq_int += (state_m->vq - vq_presat); + utils_truncate_number_abs((float*)&state_m->vq_int, max_vq); + + //state_m->vq_int += (state_m->vq - vq_presat); utils_saturate_vector_2d((float*)&state_m->vd, (float*)&state_m->vq, max_v_mag); diff --git a/motor/mcpwm_foc.h b/motor/mcpwm_foc.h index 067b63756d..85baeefec5 100644 --- a/motor/mcpwm_foc.h +++ b/motor/mcpwm_foc.h @@ -78,6 +78,7 @@ int mcpwm_foc_get_tachometer_value(bool reset); int mcpwm_foc_get_tachometer_abs_value(bool reset); float mcpwm_foc_get_phase(void); float mcpwm_foc_get_phase_observer(void); +float mcpwm_foc_get_phase_bemf(void); float mcpwm_foc_get_phase_encoder(void); float mcpwm_foc_get_phase_hall(void); float mcpwm_foc_get_vd(void); @@ -86,6 +87,8 @@ float mcpwm_foc_get_mod_alpha_raw(void); float mcpwm_foc_get_mod_beta_raw(void); float mcpwm_foc_get_mod_alpha_measured(void); float mcpwm_foc_get_mod_beta_measured(void); +float mcpwm_foc_get_v_alpha(void); +float mcpwm_foc_get_v_beta(void); float mcpwm_foc_get_est_lambda(void); float mcpwm_foc_get_est_res(void); float mcpwm_foc_get_est_ind(void); diff --git a/package_firmware.py b/package_firmware.py index 584ec6b745..8dbf262741 100755 --- a/package_firmware.py +++ b/package_firmware.py @@ -20,10 +20,6 @@ def get_git_revision_short_hash() -> str: # Add directories and targets to the dictionary # package_dict["group name diplayed in firmware tab of the vesc tool"] = [['.c filename minus the hw_', 'compiled .bin filename']] package_dict = {} -package_dict["46_o_47"] = [['46', default_name], - ['46_33k', 'VESC_33k.bin'], - ['46_0005ohm', 'VESC_0005ohm.bin']] -package_dict["48"] = [['48', default_name]] package_dict["410_o_411_o_412"] = [['410', default_name], ['410_no_limits', no_limits_name], ['410_0005ohm', 'VESC_0005ohm.bin'], @@ -39,18 +35,14 @@ def get_git_revision_short_hash() -> str: package_dict["60_MK6"] = [['60_mk6', default_name], ['60_mk6_no_limits', no_limits_name]] package_dict["60_MK6_MAX"] = [['60_mk6_max', default_name]] -package_dict["DAS_RS"] = [['das_rs', default_name]] package_dict["75_300"] = [['75_300', default_name], ['75_300_no_limits', no_limits_name]] package_dict["75_300_R2"] = [['75_300_r2', default_name], ['75_300_r2_no_limits', no_limits_name]] package_dict["75_300_R3"] = [['75_300_r3', default_name], ['75_300_r3_no_limits', no_limits_name]] -package_dict["AXIOM"] = [['axiom', default_name]] package_dict["HD60"] = [['hd60', default_name], ['hd60_no_limits', no_limits_name]] -package_dict["HD75"] = [['hd75', default_name], - ['hd75_no_limits', no_limits_name]] package_dict["A50S_6S"] = [['a50s_v22_6s', default_name]] package_dict["A50S_6S_HG"] = [['a50s_v22_6s_hg', default_name]] package_dict["A50S_12S"] = [['a50s_v22_12s', default_name]] @@ -110,7 +102,6 @@ def get_git_revision_short_hash() -> str: package_dict["JetFleetF6_20s"] = [['JetFleetF6_20s', default_name]] package_dict["JetFleetF6_24s"] = [['JetFleetF6_24s', default_name]] package_dict["JetFleetF6_32s"] = [['JetFleetF6_32s', default_name]] -package_dict["UXV_SR"] = [['uxv_sr', default_name]] package_dict["GESC"] = [['gesc', default_name]] package_dict["Warrior6"] = [['warrior6', default_name]] package_dict["Raiden7"] = [['raiden7', default_name]] @@ -191,14 +182,8 @@ def get_git_revision_short_hash() -> str: ['mksesc_100_300_hp_no_limits', no_limits_name]] package_dict["STR500"] = [['str500', default_name], ['str500_no_limits', no_limits_name]] -package_dict["STR500_01"] = [['str500_01', default_name]] -package_dict["STR500_HP"] = [['str500_hp', default_name], - ['str500_hp_no_limits', no_limits_name]] -package_dict["RB"] = [['rb', default_name]] package_dict["STR365"] = [['str365', default_name], ['str365_no_limits', no_limits_name]] -package_dict["STR365_150"] = [['str365_150', default_name], - ['str365_150_no_limits', no_limits_name]] package_dict["RSR_DD_V1"] = [['RSR_DD_V1', default_name], ['RSR_DD_V1_005', 'RSR_DD_V1_005.bin']] package_dict["RSR_DD_V2"] = [['RSR_DD_V2', default_name]] @@ -214,10 +199,18 @@ def get_git_revision_short_hash() -> str: ['maximp_150_no_limits', no_limits_name]] package_dict["Duet"] = [['duet', default_name], ['duet_no_limits', no_limits_name]] +package_dict["Duet XS100"] = [['duet_xs100', default_name], + ['duet_xs100_no_limits', no_limits_name]] +package_dict["Duet XS60"] = [['duet_xs60', default_name], + ['duet_xs60_no_limits', no_limits_name]] package_dict["Minim"] = [['minim', default_name], ['minim_no_limits', no_limits_name]] package_dict["Pronto"] = [['pronto', default_name], ['pronto_no_limits', no_limits_name]] +package_dict["Classic"] = [['classic', default_name], + ['classic_no_limits', no_limits_name]] +package_dict["Classicp"] = [['classicp', default_name], + ['classicp_no_limits', no_limits_name]] # This is the firmware stub string res_firmwares_string = ' TARGET_DESTINATION_DIRECTORY/TARGET_DESTINATION_FILENAME\n' diff --git a/terminal.c b/terminal.c index 64de080cb4..bcfdb95cf9 100644 --- a/terminal.c +++ b/terminal.c @@ -38,6 +38,7 @@ #include "mempools.h" #include "crc.h" #include "firmware_metadata.h" +#include "blackbox.h" #include #include @@ -184,6 +185,38 @@ __attribute__((section(".text2"))) void terminal_process_string(char *str) { commands_printf(" "); } } + } else if (strcmp(argv[0], "bb_status") == 0) { + commands_printf("Blackbox status"); + commands_printf("ISR ticks : %lu", blackbox_isr_tick()); + commands_printf("Samples : %lu", blackbox_sample_count()); + commands_printf("Freeze en. : %s", blackbox_freeze_enabled() ? "yes" : "no"); + commands_printf("Triggered : %s", blackbox_is_triggered() ? "yes" : "no"); + commands_printf("Frozen : %s", blackbox_is_frozen() ? "yes" : "no"); + commands_printf("Fault : %s", mc_interface_fault_to_string((mc_fault_code)blackbox_fault_code())); + + const volatile bb_record_t *r = blackbox_get_record(0); + if (r) { + commands_printf("Last record (tick %lu):", r->tick); + commands_printf(" ia/ib/ic : %.2f / %.2f / %.2f A", (double)r->ia, (double)r->ib, (double)r->ic); + commands_printf(" id/iq : %.2f / %.2f A", (double)r->id, (double)r->iq); + commands_printf(" i_abs (filt) : %.2f (%.2f) A", (double)r->i_abs, (double)r->i_abs_filter); + commands_printf(" duty : %.3f", (double)r->duty_now); + commands_printf(" v_bus : %.2f V", (double)r->v_bus); + commands_printf(" phase : %.3f rad", (double)r->phase); + commands_printf(" speed : %.1f rad/s (%.1f ERPM)", + (double)r->speed_rad_s, (double)(r->speed_rad_s * 60.0 / (2.0 * M_PI))); + commands_printf(" state/mode : %d / %d", r->state, r->control_mode); + commands_printf(" flags : 0x%02x", r->flags); + } else { + commands_printf("No records yet"); + } + commands_printf(" "); + } else if (strcmp(argv[0], "bb_clear") == 0) { + blackbox_clear(); + commands_printf("Blackbox cleared\n"); + } else if (strcmp(argv[0], "bb_dump") == 0) { + blackbox_request_dump(); + commands_printf("Blackbox dump over RTT requested\n"); } else if (strcmp(argv[0], "tim") == 0) { chSysLock(); volatile int t1_cnt = TIM1->CNT; @@ -608,8 +641,11 @@ __attribute__((section(".text2"))) void terminal_process_string(char *str) { commands_printf("Phase Shunts: No"); #endif - commands_printf("Odometer : %llu m", mc_interface_get_odometer()); - commands_printf("Runtime : %llu s", g_backup.runtime); + commands_printf("Odometer : %u m", (uint32_t)mc_interface_get_odometer()); + commands_printf("Runtime : %u s", (uint32_t)g_backup.runtime); + commands_printf("Enc Corr EN : %d", g_backup.enc_corr_en); + commands_printf("Bkp CAN ID : %d", g_backup.can_id); + commands_printf("Bkp CAN Baud: %d", g_backup.can_baud); float curr0_offset; float curr1_offset; @@ -1178,6 +1214,15 @@ __attribute__((section(".text2"))) void terminal_process_string(char *str) { commands_printf("faults"); commands_printf(" Prints all stored fault codes and conditions when they arrived"); + commands_printf("bb_status"); + commands_printf(" Prints the blackbox ring buffer status and the latest record"); + + commands_printf("bb_clear"); + commands_printf(" Clears and unfreezes the blackbox ring buffer"); + + commands_printf("bb_dump"); + commands_printf(" Streams the blackbox ring buffer over RTT as CSV"); + commands_printf("tim"); commands_printf(" Prints tim1 and tim8 settings"); diff --git a/util/worker.c b/util/worker.c index 031ea2c102..45f5435ed0 100644 --- a/util/worker.c +++ b/util/worker.c @@ -30,7 +30,7 @@ typedef struct { // Private variables static thread_t *m_tp = 0; static worker_arg_t m_wa; -static THD_WORKING_AREA(work_thread_wa, 512); +static THD_WORKING_AREA(work_thread_wa, 768); static THD_FUNCTION(work_thread, arg); void worker_execute(void(*func)(void *arg), void *arg) {