Added uBASIC-Plus program object example to STM32F4xx. (#967)
This commit is contained in:
@@ -48,7 +48,7 @@ struct object_data {
|
||||
bool Changed : 1;
|
||||
void *Context;
|
||||
/* return 0 for success, negative on error */
|
||||
int (*Load)(void *context, const char *location);
|
||||
int (*Load)(void *context);
|
||||
int (*Run)(void *context);
|
||||
int (*Halt)(void *context);
|
||||
int (*Restart)(void *context);
|
||||
@@ -960,9 +960,9 @@ void Program_Context_Set(uint32_t object_instance, void *context)
|
||||
* @brief Set the Load function for the object
|
||||
* @param object_instance [in] BACnet object instance number
|
||||
* @param load [in] pointer to the Load function
|
||||
* @note function should return 0 for success, negative on error
|
||||
*/
|
||||
void Program_Load_Set(
|
||||
uint32_t object_instance, int (*load)(void *context, const char *location))
|
||||
void Program_Load_Set(uint32_t object_instance, int (*load)(void *context))
|
||||
{
|
||||
struct object_data *pObject = Object_Data(object_instance);
|
||||
|
||||
@@ -975,6 +975,7 @@ void Program_Load_Set(
|
||||
* @brief Set the Run function for the object
|
||||
* @param object_instance [in] BACnet object instance number
|
||||
* @param run [in] pointer to the Run function
|
||||
* @note function should return 0 for success, negative on error
|
||||
*/
|
||||
void Program_Run_Set(uint32_t object_instance, int (*run)(void *context))
|
||||
{
|
||||
@@ -989,6 +990,7 @@ void Program_Run_Set(uint32_t object_instance, int (*run)(void *context))
|
||||
* @brief Set the Halt function for the object
|
||||
* @param object_instance [in] BACnet object instance number
|
||||
* @param halt [in] pointer to the Halt function
|
||||
* @note function should return 0 for success, negative on error
|
||||
*/
|
||||
void Program_Halt_Set(uint32_t object_instance, int (*halt)(void *context))
|
||||
{
|
||||
@@ -1003,6 +1005,7 @@ void Program_Halt_Set(uint32_t object_instance, int (*halt)(void *context))
|
||||
* @brief Set the Restart function for the object
|
||||
* @param object_instance [in] BACnet object instance number
|
||||
* @param restart [in] pointer to the Restart function
|
||||
* @note function should return 0 for success, negative on error
|
||||
*/
|
||||
void Program_Restart_Set(
|
||||
uint32_t object_instance, int (*restart)(void *context))
|
||||
@@ -1018,6 +1021,7 @@ void Program_Restart_Set(
|
||||
* @brief Set the Unload function for the object
|
||||
* @param object_instance [in] BACnet object instance number
|
||||
* @param unload [in] pointer to the Unload function
|
||||
* @note function should return 0 for success, negative on error
|
||||
*/
|
||||
void Program_Unload_Set(uint32_t object_instance, int (*unload)(void *context))
|
||||
{
|
||||
@@ -1028,13 +1032,17 @@ void Program_Unload_Set(uint32_t object_instance, int (*unload)(void *context))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle the IDLE state of the program
|
||||
* @param pObject [in] pointer to the object data
|
||||
*/
|
||||
static void Program_State_Idle_Handler(struct object_data *pObject)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
||||
if (pObject->Load) {
|
||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
||||
err = pObject->Load(pObject->Context);
|
||||
if (err == 0) {
|
||||
pObject->Program_State = PROGRAM_STATE_LOADING;
|
||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
||||
@@ -1047,7 +1055,7 @@ static void Program_State_Idle_Handler(struct object_data *pObject)
|
||||
}
|
||||
} else if (pObject->Program_Change == PROGRAM_REQUEST_RUN) {
|
||||
if (pObject->Load) {
|
||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
||||
err = pObject->Load(pObject->Context);
|
||||
if (err == 0) {
|
||||
pObject->Program_State = PROGRAM_STATE_RUNNING;
|
||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
||||
@@ -1074,6 +1082,10 @@ static void Program_State_Idle_Handler(struct object_data *pObject)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle the HALTED state of the program
|
||||
* @param pObject [in] pointer to the object data
|
||||
*/
|
||||
static void Program_State_Halted_Handler(struct object_data *pObject)
|
||||
{
|
||||
int err;
|
||||
@@ -1093,7 +1105,7 @@ static void Program_State_Halted_Handler(struct object_data *pObject)
|
||||
}
|
||||
} else if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
||||
if (pObject->Load) {
|
||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
||||
err = pObject->Load(pObject->Context);
|
||||
if (err == 0) {
|
||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
||||
pObject->Program_State = PROGRAM_STATE_LOADING;
|
||||
@@ -1123,6 +1135,10 @@ static void Program_State_Halted_Handler(struct object_data *pObject)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle the RUNNING state of the program
|
||||
* @param pObject [in] pointer to the object data
|
||||
*/
|
||||
static void Program_State_Running_Handler(struct object_data *pObject)
|
||||
{
|
||||
int err;
|
||||
@@ -1142,7 +1158,7 @@ static void Program_State_Running_Handler(struct object_data *pObject)
|
||||
}
|
||||
} else if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
||||
if (pObject->Load) {
|
||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
||||
err = pObject->Load(pObject->Context);
|
||||
if (err == 0) {
|
||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
||||
pObject->Program_State = PROGRAM_STATE_LOADING;
|
||||
|
||||
@@ -110,12 +110,13 @@ void Program_Cleanup(void);
|
||||
BACNET_STACK_EXPORT
|
||||
void Program_Init(void);
|
||||
|
||||
/* API for the program requests */
|
||||
/* API for the program requests
|
||||
note: return value is 0 for success, non-zero for failure
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void Program_Context_Set(uint32_t object_instance, void *context);
|
||||
BACNET_STACK_EXPORT
|
||||
void Program_Load_Set(
|
||||
uint32_t object_instance, int (*load)(void *context, const char *location));
|
||||
void Program_Load_Set(uint32_t object_instance, int (*load)(void *context));
|
||||
BACNET_STACK_EXPORT
|
||||
void Program_Run_Set(uint32_t object_instance, int (*run)(void *context));
|
||||
BACNET_STACK_EXPORT
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
|
||||
|
||||
add_library(ubasic STATIC
|
||||
ubasic.c
|
||||
tokenizer.c
|
||||
)
|
||||
@@ -0,0 +1,182 @@
|
||||
/*-
|
||||
* Copyright (c) 2017-18, Marijan Kostrun <mkostrun@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Undef it all */
|
||||
|
||||
/* Storage and arithmetic */
|
||||
#undef VARIABLE_STORAGE_INT16
|
||||
#undef VARIABLE_STORAGE_INT32
|
||||
#undef VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8
|
||||
#undef VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10
|
||||
#undef VARIABLE_TYPE_STRING
|
||||
#undef VARIABLE_TYPE_ARRAY
|
||||
#undef UBASIC_SCRIPT_HAVE_DEMO_SCRIPTS
|
||||
|
||||
/* Microcontroller related functionality */
|
||||
#undef UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR
|
||||
#undef UBASIC_SCRIPT_HAVE_PWM_CHANNELS
|
||||
#undef UBASIC_SCRIPT_HAVE_GPIO
|
||||
#undef UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS
|
||||
#undef UBASIC_SCRIPT_HAVE_SLEEP
|
||||
#undef UBASIC_SCRIPT_HAVE_HARDWARE_EVENTS
|
||||
#undef UBASIC_SCRIPT_PRINT_TO_SERIAL
|
||||
#undef UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL
|
||||
#undef UBASIC_SCRIPT_HAVE_ANALOG_READ
|
||||
#undef UBASIC_SCRIPT_HAVE_STORE_VARS_IN_FLASH
|
||||
#undef UBASIC_SCRIPT_HAVE_BACNET
|
||||
|
||||
/**
|
||||
*
|
||||
* UBASIC-PLUS: Start
|
||||
*
|
||||
*/
|
||||
/* default storage for all numeric values */
|
||||
#define VARIABLE_STORAGE_INT32
|
||||
|
||||
/* defines the representation of floating point numbers as fixed points:
|
||||
this is to allow UBASIC to run on Cortex M0 processors which do not
|
||||
support Floating Point Arithmetic in hardware (they emulate it which
|
||||
consumes lots of memory) */
|
||||
#define VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8
|
||||
|
||||
/* This many one-letter variables UBASIC supports */
|
||||
#define MAX_VARNUM 26
|
||||
|
||||
/* have numeric arrays and set their storage to this many VARIABLE_TYPE entries
|
||||
*/
|
||||
#define VARIABLE_TYPE_ARRAY 64
|
||||
|
||||
/* have strings and related functions */
|
||||
#define VARIABLE_TYPE_STRING
|
||||
|
||||
/* can go to sleep: leave UBASIC for other stuff while waiting for timer to
|
||||
* expire */
|
||||
#define UBASIC_SCRIPT_HAVE_SLEEP
|
||||
|
||||
/* have microcontroller support for PWM: specify how many channels */
|
||||
#define UBASIC_SCRIPT_HAVE_PWM_CHANNELS (4)
|
||||
|
||||
/* have internal timer channels available through rlab-like toc(ch) functions */
|
||||
#define UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS (8)
|
||||
|
||||
/* support for random number generator by micro-controller */
|
||||
#define UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR
|
||||
|
||||
/* support for direct access to pin inputs and outputs */
|
||||
#define UBASIC_SCRIPT_HAVE_GPIO_CHANNELS
|
||||
|
||||
/* support flags in BASIC that change on hardware events:
|
||||
for STM32F0XX nucleo and discovery boards
|
||||
source of the events is push-button
|
||||
*/
|
||||
#define UBASIC_SCRIPT_HAVE_HARDWARE_EVENTS
|
||||
|
||||
/* have a standard print to serial console function */
|
||||
#define UBASIC_SCRIPT_PRINT_TO_SERIAL
|
||||
|
||||
/* how is input function supported ? */
|
||||
#define UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL
|
||||
|
||||
/* support for analog inputs */
|
||||
#define UBASIC_SCRIPT_HAVE_ANALOG_READ
|
||||
|
||||
/* support for BACnet objects and ReadProperty and WriteProperty (internal) */
|
||||
#define UBASIC_SCRIPT_HAVE_BACNET
|
||||
|
||||
/* Demo scripts are huge. Do we need them? */
|
||||
#define UBASIC_SCRIPT_HAVE_DEMO_SCRIPTS
|
||||
|
||||
/* support for storing/recalling variables in/from flash memory */
|
||||
#define UBASIC_SCRIPT_HAVE_STORE_VARS_IN_FLASH
|
||||
/**
|
||||
*
|
||||
* UBASIC-PLUS: End
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Selectively load header files based on the ocnfiguration above.
|
||||
* Remember MC Hammer:
|
||||
* CAN'T TOUCH THIS!
|
||||
*
|
||||
*/
|
||||
#if defined(VARIABLE_STORAGE_INT32)
|
||||
|
||||
#define VARIABLE_TYPE int32_t
|
||||
|
||||
#if defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8) || \
|
||||
defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10)
|
||||
|
||||
#define FIXEDPT_BITS 32
|
||||
|
||||
#if defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8)
|
||||
#define FIXEDPT_WBITS 24
|
||||
#elif defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10)
|
||||
#define FIXEDPT_WBITS 22
|
||||
#else
|
||||
#error "Only 24.8 and 22.10 floats are currently supported"
|
||||
#endif
|
||||
|
||||
#include "fixedptc.h"
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(VARIABLE_STORAGE_INT16)
|
||||
|
||||
#define VARIABLE_TYPE int16_t
|
||||
#if defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8) || \
|
||||
defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10)
|
||||
#error "Fixed Point Floats are Supported for 32bit Storage Only!"
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#error "Only INT32 and INT16 variable types are supported."
|
||||
|
||||
#endif
|
||||
|
||||
#define UBASIC_STATEMENT_SIZE (64)
|
||||
|
||||
#define MAX_STRINGLEN 40
|
||||
#define MAX_LABEL_LEN 10
|
||||
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
#define MAX_STRINGVARLEN 64
|
||||
#define MAX_BUFFERLEN 256
|
||||
#define MAX_SVARNUM 26
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _CONFIG_H_ */
|
||||
@@ -0,0 +1,672 @@
|
||||
#ifndef _FIXEDPTC_H_
|
||||
#define _FIXEDPTC_H_
|
||||
|
||||
/*
|
||||
* fixedptc.h is a 32-bit or 64-bit fixed point numeric library.
|
||||
*
|
||||
* The symbol FIXEDPT_BITS, if defined before this library header file
|
||||
* is included, governs the number of bits in the data type (its "width").
|
||||
* The default width is 32-bit (FIXEDPT_BITS=32) and it can be used
|
||||
* on any recent C99 compiler. The 64-bit precision (FIXEDPT_BITS=64) is
|
||||
* available on compilers which implement 128-bit "long long" types. This
|
||||
* precision has been tested on GCC 4.2+.
|
||||
*
|
||||
* Since the precision in both cases is relatively low, many complex
|
||||
* functions (more complex than div & mul) take a large hit on the precision
|
||||
* of the end result because errors in precision accumulate.
|
||||
* This loss of precision can be lessened by increasing the number of
|
||||
* bits dedicated to the fraction part, but at the loss of range.
|
||||
*
|
||||
* Adventurous users might utilize this library to build two data types:
|
||||
* one which has the range, and one which has the precision, and carefully
|
||||
* convert between them (including adding two number of each type to produce
|
||||
* a simulated type with a larger range and precision).
|
||||
*
|
||||
* The ideas and algorithms have been cherry-picked from a large number
|
||||
* of previous implementations available on the Internet.
|
||||
* Tim Hartrick has contributed cleanup and 64-bit support patches.
|
||||
*
|
||||
* == Special notes for the 32-bit precision ==
|
||||
* Signed 32-bit fixed point numeric library for the 24.8 format.
|
||||
* The specific limits are -8388608.999... to 8388607.999... and the
|
||||
* most precise number is 0.00390625. In practice, you should not count
|
||||
* on working with numbers larger than a million or to the precision
|
||||
* of more than 2 decimal places. Make peace with the fact that PI
|
||||
* is 3.14 here. :)
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010-2012 Ivan Voras <ivoras@freebsd.org>
|
||||
* Copyright (c) 2012, Tim Hartrick <tim@edgecast.com>
|
||||
* Copyright (c) 2018, Marijan Kostrun <mksotrun@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Marijan Kostrun, added function str_fixedpt(char*,int, int)
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
#ifndef FIXEDPT_BITS
|
||||
#define FIXEDPT_BITS 32
|
||||
#endif
|
||||
|
||||
#if FIXEDPT_BITS == 32
|
||||
typedef int32_t fixedpt;
|
||||
typedef int64_t fixedptd;
|
||||
typedef uint32_t fixedptu;
|
||||
typedef uint64_t fixedptud;
|
||||
#elif FIXEDPT_BITS == 64
|
||||
typedef int64_t fixedpt;
|
||||
typedef __int128_t fixedptd;
|
||||
typedef uint64_t fixedptu;
|
||||
typedef __uint128_t fixedptud;
|
||||
#else
|
||||
#error "FIXEDPT_BITS must be equal to 32 or 64"
|
||||
#endif
|
||||
|
||||
#ifndef FIXEDPT_WBITS
|
||||
#define FIXEDPT_WBITS 24
|
||||
#endif
|
||||
|
||||
#if FIXEDPT_WBITS >= FIXEDPT_BITS
|
||||
#error "FIXEDPT_WBITS must be less than or equal to FIXEDPT_BITS"
|
||||
#endif
|
||||
|
||||
#define FIXEDPT_FBITS (FIXEDPT_BITS - FIXEDPT_WBITS)
|
||||
#define FIXEDPT_FMASK (((fixedpt)1 << FIXEDPT_FBITS) - 1)
|
||||
|
||||
#define fixedpt_rconst(R) \
|
||||
((fixedpt)((R) * \
|
||||
(((fixedptd)1 << FIXEDPT_FBITS) + ((R) >= 0 ? 0.5 : -0.5))))
|
||||
#define fixedpt_fromint(I) ((fixedptd)(I) << FIXEDPT_FBITS)
|
||||
#define fixedpt_toint(F) ((F) >> FIXEDPT_FBITS)
|
||||
#define fixedpt_add(A, B) ((A) + (B))
|
||||
#define fixedpt_sub(A, B) ((A) - (B))
|
||||
#define fixedpt_xmul(A, B) \
|
||||
((fixedpt)(((fixedptd)(A) * (fixedptd)(B)) >> FIXEDPT_FBITS))
|
||||
#define fixedpt_xdiv(A, B) \
|
||||
((fixedpt)(((fixedptd)(A) << FIXEDPT_FBITS) / (fixedptd)(B)))
|
||||
#define fixedpt_fracpart(A) ((fixedpt)(A) & FIXEDPT_FMASK)
|
||||
|
||||
#define FIXEDPT_ONE ((fixedpt)((fixedpt)1 << FIXEDPT_FBITS))
|
||||
#define FIXEDPT_ONE_HALF (FIXEDPT_ONE >> 1)
|
||||
#define FIXEDPT_TWO (FIXEDPT_ONE + FIXEDPT_ONE)
|
||||
#define FIXEDPT_PI fixedpt_rconst(3.14159265358979323846)
|
||||
#define FIXEDPT_TWO_PI fixedpt_rconst(2 * 3.14159265358979323846)
|
||||
#define FIXEDPT_HALF_PI fixedpt_rconst(3.14159265358979323846 / 2)
|
||||
#define FIXEDPT_E fixedpt_rconst(2.7182818284590452354)
|
||||
|
||||
#define fixedpt_abs(A) ((A) < 0 ? -(A) : (A))
|
||||
|
||||
/* Multiplies two fixedpt numbers, returns the result. */
|
||||
static inline fixedpt fixedpt_mul(fixedpt A, fixedpt B)
|
||||
{
|
||||
return (((fixedptd)A * (fixedptd)B) >> FIXEDPT_FBITS);
|
||||
}
|
||||
|
||||
/* Divides two fixedpt numbers, returns the result. */
|
||||
static inline fixedpt fixedpt_div(fixedpt A, fixedpt B)
|
||||
{
|
||||
return (((fixedptd)A << FIXEDPT_FBITS) / (fixedptd)B);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: adding and subtracting fixedpt numbers can be done by using
|
||||
* the regular integer operators + and -.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert decimal string to a fixedpt number up to specified
|
||||
* number of decimal places.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
static inline fixedpt
|
||||
str_fixedpt(const char *p, uint8_t plen, uint8_t decimal_places)
|
||||
{
|
||||
uint8_t i_minus = *p == '-' ? 1 : 0;
|
||||
|
||||
fixedpt rval = fixedpt_fromint(atoi(p));
|
||||
|
||||
/* find '.': the number is float because it has at least one */
|
||||
/* digit past decimal point */
|
||||
const char *s = p;
|
||||
while ((*s != '.') && ((s - p) < plen)) {
|
||||
s++;
|
||||
}
|
||||
s++;
|
||||
|
||||
/* are there any digits left past decimal point */
|
||||
if ((s - p) < plen) {
|
||||
/* pick up not more then 'decimal_places': */
|
||||
uint16_t f = 0, fpow10 = 1;
|
||||
uint8_t idec = 0;
|
||||
while (((s - p) < plen) && isdigit(*s) && (idec < decimal_places)) {
|
||||
f = 10 * f + ((*s) - '0');
|
||||
s++;
|
||||
fpow10 *= 10;
|
||||
idec++;
|
||||
}
|
||||
if (i_minus) {
|
||||
rval -= (f << FIXEDPT_FBITS) / fpow10;
|
||||
} else {
|
||||
rval += (f << FIXEDPT_FBITS) / fpow10;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given fixedpt number to a decimal string.
|
||||
* The max_dec argument specifies how many decimal digits to the right
|
||||
* of the decimal point to generate. If set to -1, the "default" number
|
||||
* of decimal digits will be used (2 for 32-bit fixedpt width, 10 for
|
||||
* 64-bit fixedpt width); If set to -2, "all" of the digits will
|
||||
* be returned, meaning there will be invalid, bogus digits outside the
|
||||
* specified precisions.
|
||||
*/
|
||||
static inline void fixedpt_str(fixedpt A, char *str, int max_dec)
|
||||
{
|
||||
int32_t ndec = 0, slen = 0;
|
||||
char tmp[12] = { 0 };
|
||||
fixedptud fr, ip;
|
||||
const fixedptud one = (fixedptud)1 << FIXEDPT_BITS;
|
||||
const fixedptud mask = one - 1;
|
||||
|
||||
if (max_dec == -1)
|
||||
#if FIXEDPT_BITS == 32
|
||||
max_dec = 2;
|
||||
#elif FIXEDPT_BITS == 64
|
||||
max_dec = 10;
|
||||
#else
|
||||
#error Invalid width
|
||||
#endif
|
||||
else if (max_dec == -2) {
|
||||
max_dec = 15;
|
||||
}
|
||||
|
||||
if (A < 0) {
|
||||
str[slen++] = '-';
|
||||
A *= -1;
|
||||
}
|
||||
|
||||
ip = fixedpt_toint(A);
|
||||
do {
|
||||
tmp[ndec++] = '0' + ip % 10;
|
||||
ip /= 10;
|
||||
} while (ip != 0);
|
||||
|
||||
while (ndec > 0) {
|
||||
str[slen++] = tmp[--ndec];
|
||||
}
|
||||
str[slen++] = '.';
|
||||
|
||||
fr = (fixedpt_fracpart(A) << FIXEDPT_WBITS) & mask;
|
||||
do {
|
||||
fr = (fr & mask) * 10;
|
||||
str[slen++] = '0' + (fr >> FIXEDPT_BITS) % 10;
|
||||
ndec++;
|
||||
} while (fr != 0 && ndec < max_dec);
|
||||
|
||||
if (ndec > 0 && str[slen - 1] == '0') {
|
||||
str[slen - 1] = '\0'; /* cut off trailing 0 */
|
||||
if (str[slen - 2] == '.') {
|
||||
str[slen - 2] = '\0'; /* cut off trailing .*/
|
||||
}
|
||||
} else {
|
||||
str[slen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts the given fixedpt number into a string, using a static
|
||||
* (non-threadsafe) string buffer */
|
||||
static inline char *fixedpt_cstr(const fixedpt A, const int max_dec)
|
||||
{
|
||||
static char str[25];
|
||||
|
||||
fixedpt_str(A, str, max_dec);
|
||||
return (str);
|
||||
}
|
||||
|
||||
/* Returns the square root of the given number, or -1 in case of error */
|
||||
static inline fixedpt fixedpt_sqrt(fixedpt A)
|
||||
{
|
||||
int invert = 0;
|
||||
int iter = FIXEDPT_FBITS;
|
||||
int l, i;
|
||||
|
||||
if (A < 0) {
|
||||
return (-1);
|
||||
}
|
||||
if (A == 0 || A == FIXEDPT_ONE) {
|
||||
return (A);
|
||||
}
|
||||
if (A < FIXEDPT_ONE && A > 6) {
|
||||
invert = 1;
|
||||
A = fixedpt_div(FIXEDPT_ONE, A);
|
||||
}
|
||||
if (A > FIXEDPT_ONE) {
|
||||
int s = A;
|
||||
|
||||
iter = 0;
|
||||
while (s > 0) {
|
||||
s >>= 2;
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Newton's iterations */
|
||||
l = (A >> 1) + 1;
|
||||
for (i = 0; i < iter; i++) {
|
||||
l = (l + fixedpt_div(A, l)) >> 1;
|
||||
}
|
||||
if (invert) {
|
||||
return (fixedpt_div(FIXEDPT_ONE, l));
|
||||
}
|
||||
return (l);
|
||||
}
|
||||
|
||||
/* Returns the sine of the given fixedpt number.
|
||||
* Note: the loss of precision is extraordinary! */
|
||||
static inline fixedpt fixedpt_sin(fixedpt fp)
|
||||
{
|
||||
int sign = 1;
|
||||
fixedpt sqr, result;
|
||||
const fixedpt SK[2] = { fixedpt_rconst(7.61e-03),
|
||||
fixedpt_rconst(1.6605e-01) };
|
||||
|
||||
fp %= 2 * FIXEDPT_PI;
|
||||
if (fp < 0) {
|
||||
fp = FIXEDPT_PI * 2 + fp;
|
||||
}
|
||||
if ((fp > FIXEDPT_HALF_PI) && (fp <= FIXEDPT_PI)) {
|
||||
fp = FIXEDPT_PI - fp;
|
||||
} else if ((fp > FIXEDPT_PI) && (fp <= (FIXEDPT_PI + FIXEDPT_HALF_PI))) {
|
||||
fp = fp - FIXEDPT_PI;
|
||||
sign = -1;
|
||||
} else if (fp > (FIXEDPT_PI + FIXEDPT_HALF_PI)) {
|
||||
fp = (FIXEDPT_PI << 1) - fp;
|
||||
sign = -1;
|
||||
}
|
||||
sqr = fixedpt_mul(fp, fp);
|
||||
result = SK[0];
|
||||
result = fixedpt_mul(result, sqr);
|
||||
result -= SK[1];
|
||||
result = fixedpt_mul(result, sqr);
|
||||
result += FIXEDPT_ONE;
|
||||
result = fixedpt_mul(result, fp);
|
||||
return sign * result;
|
||||
}
|
||||
|
||||
/* Returns the cosine of the given fixedpt number */
|
||||
static inline fixedpt fixedpt_cos(fixedpt A)
|
||||
{
|
||||
return (fixedpt_sin(FIXEDPT_HALF_PI - A));
|
||||
}
|
||||
|
||||
/* Returns the tangens of the given fixedpt number.
|
||||
tan(A) = sin(A) / cos(A) */
|
||||
static inline fixedpt fixedpt_tan(fixedpt A)
|
||||
{
|
||||
return fixedpt_div(fixedpt_sin(A), fixedpt_cos(A));
|
||||
}
|
||||
|
||||
/* Returns the value exp(x), i.e. e^x of the given fixedpt number. */
|
||||
static inline fixedpt fixedpt_exp(fixedpt fp)
|
||||
{
|
||||
fixedpt xabs, k, z, R, xp;
|
||||
const fixedpt LN2 = fixedpt_rconst(0.69314718055994530942);
|
||||
const fixedpt LN2_INV = fixedpt_rconst(1.4426950408889634074);
|
||||
const fixedpt EXP_P[5] = {
|
||||
fixedpt_rconst(1.66666666666666019037e-01),
|
||||
fixedpt_rconst(-2.77777777770155933842e-03),
|
||||
fixedpt_rconst(6.61375632143793436117e-05),
|
||||
fixedpt_rconst(-1.65339022054652515390e-06),
|
||||
fixedpt_rconst(4.13813679705723846039e-08),
|
||||
};
|
||||
|
||||
if (fp == 0) {
|
||||
return (FIXEDPT_ONE);
|
||||
}
|
||||
xabs = fixedpt_abs(fp);
|
||||
k = fixedpt_mul(xabs, LN2_INV);
|
||||
k += FIXEDPT_ONE_HALF;
|
||||
k &= ~FIXEDPT_FMASK;
|
||||
if (fp < 0) {
|
||||
k = -k;
|
||||
}
|
||||
fp -= fixedpt_mul(k, LN2);
|
||||
z = fixedpt_mul(fp, fp);
|
||||
/* Taylor */
|
||||
R = FIXEDPT_TWO +
|
||||
fixedpt_mul(
|
||||
z,
|
||||
EXP_P[0] +
|
||||
fixedpt_mul(
|
||||
z,
|
||||
EXP_P[1] +
|
||||
fixedpt_mul(
|
||||
z,
|
||||
EXP_P[2] +
|
||||
fixedpt_mul(
|
||||
z, EXP_P[3] + fixedpt_mul(z, EXP_P[4])))));
|
||||
xp = FIXEDPT_ONE + fixedpt_div(fixedpt_mul(fp, FIXEDPT_TWO), R - fp);
|
||||
if (k < 0) {
|
||||
k = FIXEDPT_ONE >> (-k >> FIXEDPT_FBITS);
|
||||
} else {
|
||||
k = FIXEDPT_ONE << (k >> FIXEDPT_FBITS);
|
||||
}
|
||||
return (fixedpt_mul(k, xp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the natural logarithm of the given fixedpt number.
|
||||
* @param x The number.
|
||||
* @return the natural logarithm of the given fixedpt number.
|
||||
*/
|
||||
static inline fixedpt fixedpt_ln(fixedpt x)
|
||||
{
|
||||
fixedpt log2, xi;
|
||||
fixedpt f, s, z, w, R;
|
||||
const fixedpt LN2 = fixedpt_rconst(0.69314718055994530942);
|
||||
const fixedpt LG[7] = { fixedpt_rconst(6.666666666666735130e-01),
|
||||
fixedpt_rconst(3.999999999940941908e-01),
|
||||
fixedpt_rconst(2.857142874366239149e-01),
|
||||
fixedpt_rconst(2.222219843214978396e-01),
|
||||
fixedpt_rconst(1.818357216161805012e-01),
|
||||
fixedpt_rconst(1.531383769920937332e-01),
|
||||
fixedpt_rconst(1.479819860511658591e-01) };
|
||||
|
||||
if (x < 0) {
|
||||
return (0);
|
||||
}
|
||||
if (x == 0) {
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
log2 = 0;
|
||||
xi = x;
|
||||
while (xi > FIXEDPT_TWO) {
|
||||
xi >>= 1;
|
||||
log2++;
|
||||
}
|
||||
f = xi - FIXEDPT_ONE;
|
||||
s = fixedpt_div(f, FIXEDPT_TWO + f);
|
||||
z = fixedpt_mul(s, s);
|
||||
w = fixedpt_mul(z, z);
|
||||
R = fixedpt_mul(w, LG[1] + fixedpt_mul(w, LG[3] + fixedpt_mul(w, LG[5]))) +
|
||||
fixedpt_mul(
|
||||
z,
|
||||
LG[0] +
|
||||
fixedpt_mul(
|
||||
w, LG[2] + fixedpt_mul(w, LG[4] + fixedpt_mul(w, LG[6]))));
|
||||
return (
|
||||
fixedpt_mul(LN2, (log2 << FIXEDPT_FBITS)) + f - fixedpt_mul(s, f - R));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the logarithm of the given base of the given fixedpt number
|
||||
* @param x The number.
|
||||
* @param base The base.
|
||||
* @return the logarithm of the given base of the given fixedpt number
|
||||
*/
|
||||
static inline fixedpt fixedpt_log(fixedpt x, fixedpt base)
|
||||
{
|
||||
return (fixedpt_div(fixedpt_ln(x), fixedpt_ln(base)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the power value (n^exp) of the given fixedpt numbers
|
||||
* @param n The base.
|
||||
* @param exp The exponent.
|
||||
* @return The power value.
|
||||
*/
|
||||
static inline fixedpt fixedpt_pow(fixedpt n, fixedpt exp)
|
||||
{
|
||||
if (exp == 0) {
|
||||
return (FIXEDPT_ONE);
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (fixedpt_exp(fixedpt_mul(fixedpt_ln(n), exp)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a weighted moving average.
|
||||
* @param latest_reading The latest reading.
|
||||
* @param previous_average The previous average.
|
||||
* @param nsamples The number of samples.
|
||||
* @return The weighted moving average.
|
||||
* @note The formula used is:
|
||||
* AN+1 = (XN+1 + N * AN)/(N+1)
|
||||
* where XN+1 is the latest reading, AN is the previous average, and N is the
|
||||
* number of samples.
|
||||
*/
|
||||
static inline fixedpt fixedpt_averagew(
|
||||
fixedpt latest_reading, fixedpt previous_average, fixedpt nsamples)
|
||||
{
|
||||
if (nsamples <= 0) {
|
||||
return latest_reading;
|
||||
}
|
||||
|
||||
return (fixedpt_div(
|
||||
fixedpt_add(latest_reading, fixedpt_mul(nsamples, previous_average)),
|
||||
fixedpt_add(nsamples, FIXEDPT_ONE)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts the fractional part of a fixedpt number and
|
||||
* rounds it to max_dec decimal places.
|
||||
*
|
||||
* @param A The fixedpt value to process.
|
||||
* @param max_dec The number of decimal places to round to.
|
||||
* @return The rounded fractional part as a fixedpt number.
|
||||
*/
|
||||
static inline fixedpt fixedpt_fracpart_round(fixedpt A, int max_dec)
|
||||
{
|
||||
/* Extract the fractional part */
|
||||
fixedpt frac = fixedpt_fracpart(A);
|
||||
|
||||
/* allow -1 or other negative to default to a fixed number of places */
|
||||
if (max_dec < 0) {
|
||||
#if FIXEDPT_BITS == 32
|
||||
max_dec = 2;
|
||||
#elif FIXEDPT_BITS == 64
|
||||
max_dec = 10;
|
||||
#else
|
||||
max_dec = 15;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Scale the fractional part to the desired decimal places */
|
||||
fixedpt scale = fixedpt_fromint(1);
|
||||
for (int i = 0; i < max_dec; i++) {
|
||||
scale = fixedpt_mul(scale, fixedpt_fromint(10));
|
||||
}
|
||||
fixedpt scaled_frac = fixedpt_mul(frac, scale);
|
||||
|
||||
return scaled_frac;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts the fractional part of a fixedpt number and
|
||||
* rounds it up to max_dec decimal places, returning it as an integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @param max_dec The number of decimal places to round to.
|
||||
* @return returns the smallest integer that is not less than the given number.
|
||||
*/
|
||||
static inline int fixedpt_fracpart_ceil_toint(fixedpt A, int max_dec)
|
||||
{
|
||||
fixedpt scaled_frac = fixedpt_fracpart_round(A, max_dec);
|
||||
|
||||
/* Add 0.5 (scaled) for rounding */
|
||||
scaled_frac = fixedpt_add(scaled_frac, FIXEDPT_ONE_HALF);
|
||||
|
||||
return fixedpt_toint(scaled_frac);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts the fractional part of a fixedpt number and
|
||||
* rounds it down to max_dec decimal places, returning it as an integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @param max_dec The number of decimal places to round to.
|
||||
* @return the largest integer that is not greater than the given number.
|
||||
*/
|
||||
static inline int fixedpt_fracpart_floor_toint(fixedpt A, int max_dec)
|
||||
{
|
||||
fixedpt scaled_frac = fixedpt_fracpart_round(A, max_dec);
|
||||
|
||||
return fixedpt_toint(scaled_frac);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief rounds a fixedpt number to the nearest integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @return the nearest fixedpt integer
|
||||
*/
|
||||
static inline fixedpt fixedpt_round(fixedpt A)
|
||||
{
|
||||
uint32_t f = (A & FIXEDPT_FMASK);
|
||||
|
||||
if (A >= 0) {
|
||||
A = A & (~FIXEDPT_FMASK);
|
||||
if (f >= FIXEDPT_ONE_HALF) {
|
||||
A += FIXEDPT_ONE;
|
||||
}
|
||||
} else {
|
||||
A = A & (~FIXEDPT_FMASK);
|
||||
if (f <= FIXEDPT_ONE_HALF) {
|
||||
A -= FIXEDPT_ONE;
|
||||
}
|
||||
}
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief rounds a fixedpt number to the nearest integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @return the nearest integer
|
||||
*/
|
||||
static inline int fixedpt_round_toint(fixedpt A)
|
||||
{
|
||||
return fixedpt_toint(fixedpt_round(A));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief rounds a number up to the nearest fixedpt integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @return the smallest fixedpt integer that is not less than the given number.
|
||||
*/
|
||||
static inline fixedpt fixedpt_ceil(fixedpt A)
|
||||
{
|
||||
if (A >= 0) {
|
||||
uint32_t f = (A & FIXEDPT_FMASK);
|
||||
A = A & (~FIXEDPT_FMASK);
|
||||
if (f > 0) {
|
||||
A += FIXEDPT_ONE;
|
||||
}
|
||||
} else {
|
||||
A = A & (~FIXEDPT_FMASK);
|
||||
}
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief rounds a number up to the nearest integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @return the smallest integer that is not less than the given number.
|
||||
*/
|
||||
static inline int fixedpt_ceil_toint(fixedpt A)
|
||||
{
|
||||
return fixedpt_toint(fixedpt_ceil(A));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function rounds a number down to the nearest fixedpt integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @return the largest fixedpt integer that is not greater than the given
|
||||
* number.
|
||||
*/
|
||||
static inline fixedpt fixedpt_floor(fixedpt A)
|
||||
{
|
||||
if (A >= 0) {
|
||||
A = A & (~FIXEDPT_FMASK);
|
||||
} else {
|
||||
uint32_t f = (A & FIXEDPT_FMASK);
|
||||
A = A & (~FIXEDPT_FMASK);
|
||||
if (f > 0) {
|
||||
A -= FIXEDPT_ONE;
|
||||
}
|
||||
}
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function rounds a number down to the nearest integer.
|
||||
* @param A The fixedpt value to process.
|
||||
* @return the largest integer that is not greater than the given number.
|
||||
*/
|
||||
static inline int fixedpt_floor_toint(fixedpt A)
|
||||
{
|
||||
return fixedpt_toint(fixedpt_floor(A));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a fixedpt value to a float.
|
||||
*
|
||||
* @param A The fixedpt value to convert.
|
||||
* @return The float representation of the fixedpt value.
|
||||
*/
|
||||
static inline float fixedpt_tofloat(fixedpt A)
|
||||
{
|
||||
return (float)A / (1 << FIXEDPT_FBITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a fixedpt value to a float.
|
||||
*
|
||||
* @param A The fixedpt value to convert.
|
||||
* @return The float representation of the fixedpt value.
|
||||
*/
|
||||
static inline fixedpt fixedpt_fromfloat(float F)
|
||||
{
|
||||
return fixedpt_rconst(F);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a fixedpt value to a double.
|
||||
*
|
||||
* @param A The fixedpt value to convert.
|
||||
* @return The double representation of the fixedpt value.
|
||||
*/
|
||||
static inline double fixedpt_todouble(fixedpt A)
|
||||
{
|
||||
return (double)A / (1 << FIXEDPT_FBITS);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||
* @date 2025
|
||||
* @brief Platform libc and compiler abstraction layer
|
||||
* @details This libc and compiler abstraction layer assists with differences
|
||||
* between compiler and libc versions, capabilities, and C standards.
|
||||
* @copyright SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef UBASIC_PLATFORM_H
|
||||
#define UBASIC_PLATFORM_H
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX (~0U >> 1U)
|
||||
#endif
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#ifndef max
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef islessgreater
|
||||
#define islessgreater(x, y) ((x) < (y) || (x) > (y))
|
||||
#endif
|
||||
|
||||
#ifndef isgreaterequal
|
||||
#define isgreaterequal(x, y) ((x) > (y) || !islessgreater((x), (y)))
|
||||
#endif
|
||||
|
||||
#ifndef islessequal
|
||||
#define islessequal(x, y) ((x) < (y) || !islessgreater((x), (y)))
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(array) ((size_t)(sizeof(array) / sizeof((array)[0])))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
* Copyright (c) 2006, Adam Dunkels
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Modified to support simple string variables and functions by David Mitchell
|
||||
* November 2008.
|
||||
* Changes and additions are marked 'string additions' throughout
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "tokenizer.h"
|
||||
|
||||
#define MAX_NUMLEN 8
|
||||
|
||||
struct keyword_token {
|
||||
const char *keyword;
|
||||
uint8_t token;
|
||||
};
|
||||
|
||||
static const struct keyword_token keywords[] = {
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
/* new string-related statements and functions */
|
||||
{ "left$", TOKENIZER_LEFT_STR },
|
||||
{ "right$", TOKENIZER_RIGHT_STR },
|
||||
{ "mid$", TOKENIZER_MID_STR },
|
||||
{ "str$", TOKENIZER_STR_STR },
|
||||
{ "chr$", TOKENIZER_CHR_STR },
|
||||
{ "val", TOKENIZER_VAL },
|
||||
{ "len", TOKENIZER_LEN },
|
||||
{ "instr", TOKENIZER_INSTR },
|
||||
{ "asc", TOKENIZER_ASC },
|
||||
#endif
|
||||
/* end of string additions */
|
||||
{ "let ", TOKENIZER_LET },
|
||||
{ "println ", TOKENIZER_PRINTLN },
|
||||
{ "print ", TOKENIZER_PRINT },
|
||||
{ "if", TOKENIZER_IF },
|
||||
{ "then", TOKENIZER_THEN },
|
||||
{ "else", TOKENIZER_ELSE },
|
||||
{ "endif", TOKENIZER_ENDIF },
|
||||
#if defined(UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS)
|
||||
{ "toc", TOKENIZER_TOC },
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL)
|
||||
{ "input", TOKENIZER_INPUT },
|
||||
#endif
|
||||
{ "for ", TOKENIZER_FOR },
|
||||
{ "to ", TOKENIZER_TO },
|
||||
{ "next ", TOKENIZER_NEXT },
|
||||
{ "step ", TOKENIZER_STEP },
|
||||
{ "while", TOKENIZER_WHILE },
|
||||
{ "endwhile", TOKENIZER_ENDWHILE },
|
||||
{ "goto ", TOKENIZER_GOTO },
|
||||
{ "gosub ", TOKENIZER_GOSUB },
|
||||
{ "return", TOKENIZER_RETURN },
|
||||
{ "end", TOKENIZER_END },
|
||||
#if defined(UBASIC_SCRIPT_HAVE_SLEEP)
|
||||
{ "sleep", TOKENIZER_SLEEP },
|
||||
#endif
|
||||
#if defined(VARIABLE_TYPE_ARRAY)
|
||||
{ "dim ", TOKENIZER_DIM },
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS)
|
||||
{ "tic", TOKENIZER_TIC },
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_HARDWARE_EVENTS)
|
||||
{ "flag", TOKENIZER_HWE },
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR)
|
||||
{ "ran", TOKENIZER_RAN },
|
||||
#endif
|
||||
#if defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8) || \
|
||||
defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10)
|
||||
{ "sqrt", TOKENIZER_SQRT },
|
||||
{ "sin", TOKENIZER_SIN },
|
||||
{ "cos", TOKENIZER_COS },
|
||||
{ "tan", TOKENIZER_TAN },
|
||||
{ "exp", TOKENIZER_EXP },
|
||||
{ "ln", TOKENIZER_LN },
|
||||
#if defined(UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR)
|
||||
{ "uniform", TOKENIZER_UNIFORM },
|
||||
#endif
|
||||
{ "abs", TOKENIZER_ABS },
|
||||
{ "floor", TOKENIZER_FLOOR },
|
||||
{ "ceil", TOKENIZER_CEIL },
|
||||
{ "round", TOKENIZER_ROUND },
|
||||
{ "pow", TOKENIZER_POWER },
|
||||
{ "avgw", TOKENIZER_AVERAGEW },
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_GPIO_CHANNELS)
|
||||
{ "pinmode", TOKENIZER_PINMODE },
|
||||
{ "dread", TOKENIZER_DREAD },
|
||||
{ "dwrite", TOKENIZER_DWRITE },
|
||||
#endif
|
||||
#ifdef UBASIC_SCRIPT_HAVE_PWM_CHANNELS
|
||||
{ "awrite_conf", TOKENIZER_PWMCONF },
|
||||
{ "awrite", TOKENIZER_PWM },
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_ANALOG_READ)
|
||||
{ "aread_conf", TOKENIZER_AREADCONF },
|
||||
{ "aread", TOKENIZER_AREAD },
|
||||
#endif
|
||||
{ "hex ", TOKENIZER_PRINT_HEX },
|
||||
{ "dec ", TOKENIZER_PRINT_DEC },
|
||||
{ ":", TOKENIZER_COLON },
|
||||
#if defined(UBASIC_SCRIPT_HAVE_STORE_VARS_IN_FLASH)
|
||||
{ "store", TOKENIZER_STORE },
|
||||
{ "recall", TOKENIZER_RECALL },
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_BACNET)
|
||||
{ "bac_create", TOKENIZER_BACNET_CREATE_OBJECT },
|
||||
{ "bac_read", TOKENIZER_BACNET_READ_PROPERTY },
|
||||
{ "bac_write", TOKENIZER_BACNET_WRITE_PROPERTY },
|
||||
#endif
|
||||
{ "clear", TOKENIZER_CLEAR },
|
||||
{ NULL, TOKENIZER_ERROR }
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint8_t
|
||||
singlechar_or_operator(struct tokenizer_data *tree, uint8_t *offset)
|
||||
{
|
||||
if (offset) {
|
||||
*offset = 1;
|
||||
}
|
||||
|
||||
if ((*tree->ptr == '\n') || (*tree->ptr == ';')) {
|
||||
return TOKENIZER_EOL;
|
||||
} else if (*tree->ptr == ',') {
|
||||
return TOKENIZER_COMMA;
|
||||
} else if (*tree->ptr == '+') {
|
||||
return TOKENIZER_PLUS;
|
||||
} else if (*tree->ptr == '-') {
|
||||
return TOKENIZER_MINUS;
|
||||
} else if (*tree->ptr == '&') {
|
||||
if (*(tree->ptr + 1) == '&') {
|
||||
if (offset) {
|
||||
*offset += 1;
|
||||
}
|
||||
return TOKENIZER_LAND;
|
||||
}
|
||||
return TOKENIZER_AND;
|
||||
} else if (*tree->ptr == '|') {
|
||||
if (*(tree->ptr + 1) == '|') {
|
||||
if (offset) {
|
||||
*offset += 1;
|
||||
}
|
||||
return TOKENIZER_LOR;
|
||||
}
|
||||
return TOKENIZER_OR;
|
||||
} else if (*tree->ptr == '*') {
|
||||
return TOKENIZER_ASTR;
|
||||
} else if (*tree->ptr == '!') {
|
||||
return TOKENIZER_LNOT;
|
||||
} else if (*tree->ptr == '~') {
|
||||
return TOKENIZER_NOT;
|
||||
} else if (*tree->ptr == '/') {
|
||||
return TOKENIZER_SLASH;
|
||||
} else if (*tree->ptr == '%') {
|
||||
return TOKENIZER_MOD;
|
||||
} else if (*tree->ptr == '(') {
|
||||
return TOKENIZER_LEFTPAREN;
|
||||
} else if (*tree->ptr == ')') {
|
||||
return TOKENIZER_RIGHTPAREN;
|
||||
} else if (*tree->ptr == '<') {
|
||||
if (tree->ptr[1] == '=') {
|
||||
if (offset) {
|
||||
*offset += 1;
|
||||
}
|
||||
return TOKENIZER_LE;
|
||||
} else if (tree->ptr[1] == '>') {
|
||||
if (offset) {
|
||||
*offset += 1;
|
||||
}
|
||||
return TOKENIZER_NE;
|
||||
}
|
||||
return TOKENIZER_LT;
|
||||
} else if (*tree->ptr == '>') {
|
||||
if (tree->ptr[1] == '=') {
|
||||
if (offset) {
|
||||
*offset += 1;
|
||||
}
|
||||
return TOKENIZER_GE;
|
||||
}
|
||||
return TOKENIZER_GT;
|
||||
} else if (*tree->ptr == '=') {
|
||||
if (tree->ptr[1] == '=') {
|
||||
if (offset) {
|
||||
*offset += 1;
|
||||
}
|
||||
}
|
||||
return TOKENIZER_EQ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint8_t tokenizer_next_token(struct tokenizer_data *tree)
|
||||
{
|
||||
const struct keyword_token *kt;
|
||||
uint8_t i, j;
|
||||
|
||||
/* eat all whitespace */
|
||||
while (*tree->ptr == ' ' || *tree->ptr == '\t' || *tree->ptr == '\r') {
|
||||
tree->ptr++;
|
||||
}
|
||||
|
||||
if (*tree->ptr == 0) {
|
||||
return TOKENIZER_ENDOFINPUT;
|
||||
}
|
||||
|
||||
uint8_t have_decdot = 0, i_dot = 0;
|
||||
if ((tree->ptr[0] == '0') &&
|
||||
((tree->ptr[1] == 'x') || (tree->ptr[1] == 'X'))) {
|
||||
/* is it HEX */
|
||||
tree->nextptr = tree->ptr + 2;
|
||||
while (1) {
|
||||
if (*tree->nextptr >= '0' && *tree->nextptr <= '9') {
|
||||
tree->nextptr++;
|
||||
continue;
|
||||
}
|
||||
if ((*tree->nextptr >= 'a') && (*tree->nextptr <= 'f')) {
|
||||
tree->nextptr++;
|
||||
continue;
|
||||
}
|
||||
if ((*tree->nextptr >= 'A') && (*tree->nextptr <= 'F')) {
|
||||
tree->nextptr++;
|
||||
continue;
|
||||
}
|
||||
return TOKENIZER_INT;
|
||||
}
|
||||
} else if (
|
||||
(tree->ptr[0] == '0') &&
|
||||
((tree->ptr[1] == 'b') || (tree->ptr[1] == 'B'))) {
|
||||
/* is it BIN */
|
||||
tree->nextptr = tree->ptr + 2;
|
||||
while (*tree->nextptr == '0' || *tree->nextptr == '1') {
|
||||
tree->nextptr++;
|
||||
}
|
||||
return TOKENIZER_INT;
|
||||
} else if (isdigit(*tree->ptr) || (*tree->ptr == '.')) {
|
||||
/* is it FLOAT (digits with at most one decimal point) */
|
||||
/* is it DEC (digits without decimal point which ends in d,D,L,l) */
|
||||
tree->nextptr = tree->ptr;
|
||||
have_decdot = 0;
|
||||
i_dot = 0;
|
||||
while (1) {
|
||||
if (*tree->nextptr >= '0' && *tree->nextptr <= '9') {
|
||||
tree->nextptr++;
|
||||
if (have_decdot) {
|
||||
i_dot++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (*tree->nextptr == '.') {
|
||||
tree->nextptr++;
|
||||
have_decdot++;
|
||||
if (have_decdot > 1) {
|
||||
return TOKENIZER_ERROR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (*tree->nextptr == 'd' || *tree->nextptr == 'D' ||
|
||||
*tree->nextptr == 'l' || *tree->nextptr == 'L') {
|
||||
return TOKENIZER_INT;
|
||||
}
|
||||
|
||||
#if defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8) || \
|
||||
defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10)
|
||||
if (i_dot) {
|
||||
return TOKENIZER_FLOAT;
|
||||
}
|
||||
#endif
|
||||
|
||||
return TOKENIZER_NUMBER;
|
||||
}
|
||||
} else if ((j = singlechar_or_operator(tree, &i))) {
|
||||
tree->nextptr = tree->ptr + i;
|
||||
return j;
|
||||
}
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
else if (
|
||||
(*tree->ptr == '"' || *tree->ptr == '\'') &&
|
||||
(*(tree->ptr - 1) != '\\')) {
|
||||
i = *tree->ptr;
|
||||
tree->nextptr = tree->ptr;
|
||||
do {
|
||||
++tree->nextptr;
|
||||
if ((*tree->nextptr == '\0') || (*tree->nextptr == '\n') ||
|
||||
(*tree->nextptr == ';')) {
|
||||
return TOKENIZER_ERROR;
|
||||
}
|
||||
} while (*tree->nextptr != i || *(tree->nextptr - 1) == '\\');
|
||||
|
||||
++tree->nextptr;
|
||||
|
||||
return TOKENIZER_STRING;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* Check for keywords: */
|
||||
for (kt = keywords; kt->keyword != NULL; ++kt) {
|
||||
if (strncmp(tree->ptr, kt->keyword, strlen(kt->keyword)) == 0) {
|
||||
tree->nextptr = tree->ptr + strlen(kt->keyword);
|
||||
return kt->token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* what is left after this point we call a label as long as
|
||||
* it starts with "_" or a..z
|
||||
* and contains only digits and letters
|
||||
*/
|
||||
i = 0;
|
||||
j = 0;
|
||||
if (*tree->ptr == '_' || (*tree->ptr >= 'a' && *tree->ptr <= 'z') ||
|
||||
(*tree->ptr >= 'A' && *tree->ptr <= 'Z')) {
|
||||
tree->nextptr = tree->ptr;
|
||||
while (1) {
|
||||
if (*tree->nextptr == '_') {
|
||||
j++;
|
||||
tree->nextptr++;
|
||||
continue;
|
||||
}
|
||||
if ((*tree->nextptr >= '0') && (*tree->nextptr <= '9')) {
|
||||
i++;
|
||||
tree->nextptr++;
|
||||
continue;
|
||||
}
|
||||
if ((*tree->nextptr >= 'a') && (*tree->nextptr <= 'z')) {
|
||||
i++;
|
||||
tree->nextptr++;
|
||||
continue;
|
||||
}
|
||||
if ((*tree->nextptr >= 'A') && (*tree->nextptr <= 'Z')) {
|
||||
i++;
|
||||
tree->nextptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (j > 0 || i > 1) {
|
||||
return TOKENIZER_LABEL;
|
||||
}
|
||||
|
||||
if (i == 1) {
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
if (*(tree->ptr + 1) == '$') {
|
||||
tree->nextptr++;
|
||||
return TOKENIZER_STRINGVARIABLE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(VARIABLE_TYPE_ARRAY)
|
||||
if (*(tree->ptr + 1) == '@') {
|
||||
tree->nextptr++;
|
||||
return TOKENIZER_ARRAYVARIABLE;
|
||||
}
|
||||
#endif
|
||||
return TOKENIZER_VARIABLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TOKENIZER_ERROR;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
int8_t tokenizer_stringlookahead(struct tokenizer_data *tree)
|
||||
{
|
||||
/* return 1 (true) if next 'defining' token is string not integer */
|
||||
const char *saveptr = tree->ptr;
|
||||
const char *savenextptr = tree->nextptr;
|
||||
uint8_t token = tree->current_token;
|
||||
int8_t si = -1;
|
||||
|
||||
while (si == -1) {
|
||||
if (token == TOKENIZER_EOL || token == TOKENIZER_ENDOFINPUT) {
|
||||
si = 0;
|
||||
} else if (
|
||||
token == TOKENIZER_NUMBER || token == TOKENIZER_VARIABLE ||
|
||||
token == TOKENIZER_FLOAT) {
|
||||
si = 0; /* number or numeric var */
|
||||
} else if (token == TOKENIZER_PLUS) {
|
||||
/* do nothing */
|
||||
} else if (token == TOKENIZER_STRING) {
|
||||
si = 1;
|
||||
} else if (
|
||||
token >= TOKENIZER_STRINGVARIABLE && token <= TOKENIZER_CHR_STR) {
|
||||
si = 1;
|
||||
} else if (token > TOKENIZER_CHR_STR) {
|
||||
si = 0; /* numeric function */
|
||||
}
|
||||
|
||||
token = tokenizer_next_token(tree);
|
||||
}
|
||||
tree->ptr = saveptr;
|
||||
tree->nextptr = savenextptr;
|
||||
return si;
|
||||
}
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void tokenizer_init(struct tokenizer_data *tree, const char *program)
|
||||
{
|
||||
tree->ptr = program;
|
||||
tree->prog = program;
|
||||
tree->current_token = tokenizer_next_token(tree);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t tokenizer_token(struct tokenizer_data *tree)
|
||||
{
|
||||
return tree->current_token;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void tokenizer_next(struct tokenizer_data *tree)
|
||||
{
|
||||
if (tokenizer_finished(tree)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tree->ptr = tree->nextptr;
|
||||
|
||||
while (*tree->ptr == ' ') {
|
||||
++tree->ptr;
|
||||
}
|
||||
|
||||
tree->current_token = tokenizer_next_token(tree);
|
||||
return;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
VARIABLE_TYPE tokenizer_num(struct tokenizer_data *tree)
|
||||
{
|
||||
const char *c = tree->ptr;
|
||||
VARIABLE_TYPE rval = 0;
|
||||
|
||||
while (1) {
|
||||
if (*c < '0' || *c > '9') {
|
||||
break;
|
||||
}
|
||||
|
||||
rval *= 10;
|
||||
rval += (*c - '0');
|
||||
c++;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
VARIABLE_TYPE tokenizer_int(struct tokenizer_data *tree)
|
||||
{
|
||||
const char *c = tree->ptr;
|
||||
VARIABLE_TYPE rval = 0;
|
||||
if ((*c == '0') && (*(c + 1) == 'x' || *(c + 1) == 'X')) {
|
||||
c += 2;
|
||||
while (1) {
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
rval <<= 4;
|
||||
rval += (*c - '0');
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
if ((*c >= 'a') && (*c <= 'f')) {
|
||||
rval <<= 4;
|
||||
rval += (*c - 87); /* 87 = 'a' - 10 */
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
if ((*c >= 'A') && (*c <= 'F')) {
|
||||
rval <<= 4;
|
||||
rval += (*c - 55); /* 55 = 'A' - 10 */
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
if ((*c == '0') && (*(c + 1) == 'b' || *(c + 1) == 'B')) {
|
||||
c += 2;
|
||||
while (1) {
|
||||
if (*c == '0' || *c == '1') {
|
||||
rval <<= 1;
|
||||
rval += (*c - '0');
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
return tokenizer_num(tree);
|
||||
}
|
||||
|
||||
#if defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8) || \
|
||||
defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
VARIABLE_TYPE tokenizer_float(struct tokenizer_data *tree)
|
||||
{
|
||||
return str_fixedpt(
|
||||
tree->ptr, tree->nextptr - tree->ptr, FIXEDPT_FBITS >> 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void tokenizer_string(struct tokenizer_data *tree, char *dest, uint8_t len)
|
||||
{
|
||||
const char *string_end;
|
||||
char quote_char;
|
||||
uint8_t string_len;
|
||||
|
||||
if (tokenizer_token(tree) != TOKENIZER_STRING) {
|
||||
return;
|
||||
}
|
||||
quote_char = *tree->ptr;
|
||||
|
||||
/** figure out the quote used for strings
|
||||
* ignore escaped string-quotes
|
||||
*/
|
||||
string_end = tree->ptr;
|
||||
do {
|
||||
string_end++;
|
||||
|
||||
string_end = strchr(string_end, quote_char);
|
||||
if (string_end == NULL) {
|
||||
return;
|
||||
}
|
||||
} while (*(string_end - 1) == '\\');
|
||||
|
||||
string_len = string_end - tree->ptr - 1;
|
||||
if (len < string_len) {
|
||||
string_len = len;
|
||||
}
|
||||
memcpy(dest, tree->ptr + 1, string_len);
|
||||
dest[string_len] = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
void tokenizer_label(struct tokenizer_data *tree, char *dest, uint8_t len)
|
||||
{
|
||||
const char *string_end = tree->nextptr;
|
||||
uint8_t string_len;
|
||||
|
||||
if (tokenizer_token(tree) != TOKENIZER_LABEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (string_len = 0; string_len < string_end - tree->ptr; string_len++) {
|
||||
if ((*(tree->ptr + string_len) == '_') ||
|
||||
((*(tree->ptr + string_len) >= '0') &&
|
||||
(*(tree->ptr + string_len) <= '9')) ||
|
||||
((*(tree->ptr + string_len) >= 'A') &&
|
||||
(*(tree->ptr + string_len) <= 'Z')) ||
|
||||
((*(tree->ptr + string_len) >= 'a') &&
|
||||
(*(tree->ptr + string_len) <= 'z'))) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (string_len > len) {
|
||||
string_len = len;
|
||||
}
|
||||
memcpy(dest, tree->ptr, string_len);
|
||||
dest[string_len] = 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool tokenizer_finished(struct tokenizer_data *tree)
|
||||
{
|
||||
return ((*tree->ptr == 0) || (tree->current_token == TOKENIZER_ENDOFINPUT));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t tokenizer_variable_num(struct tokenizer_data *tree)
|
||||
{
|
||||
if ((*tree->ptr >= 'a' && *tree->ptr <= 'z')) {
|
||||
return (((uint8_t)*tree->ptr) - 'a');
|
||||
}
|
||||
|
||||
if ((*tree->ptr >= 'A' && *tree->ptr <= 'Z')) {
|
||||
return (((uint8_t)*tree->ptr) - 'A');
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
uint16_t tokenizer_save_offset(struct tokenizer_data *tree)
|
||||
{
|
||||
return (tree->ptr - tree->prog);
|
||||
}
|
||||
|
||||
void tokenizer_jump_offset(struct tokenizer_data *tree, uint16_t offset)
|
||||
{
|
||||
tree->ptr = (tree->prog + offset);
|
||||
tree->current_token = tokenizer_next_token(tree);
|
||||
while ((tree->current_token == TOKENIZER_EOL) &&
|
||||
!tokenizer_finished(tree)) {
|
||||
tokenizer_next(tree);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const char *tokenizer_name(VARIABLE_TYPE token)
|
||||
{
|
||||
const struct keyword_token *kt;
|
||||
|
||||
for (kt = keywords; kt->keyword != NULL; ++kt) {
|
||||
if (kt->token == token) {
|
||||
return kt->keyword;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2006, Adam Dunkels
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Modified to support simple string variables and functions by David Mitchell
|
||||
* November 2008.
|
||||
* Changes and additions are marked 'string additions' throughout
|
||||
*
|
||||
* Modified to support Plus extension by Marijan Kostrun 2018.
|
||||
*
|
||||
* Added averagew function. Steve Karg <skarg@users.sourceforge.net> 2025
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef __TOKENIZER_H__
|
||||
#define __TOKENIZER_H__
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
|
||||
enum {
|
||||
/*0*/ TOKENIZER_ERROR,
|
||||
/*1*/ TOKENIZER_ENDOFINPUT,
|
||||
/*2*/ TOKENIZER_NUMBER,
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
/*3*/ TOKENIZER_STRING,
|
||||
#endif
|
||||
/*4*/ TOKENIZER_VARIABLE,
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
/* string additions - must be here and in this order */
|
||||
/*5*/ TOKENIZER_STRINGVARIABLE,
|
||||
/*6*/ TOKENIZER_PRINT_STR,
|
||||
/*7*/ TOKENIZER_LEFT_STR,
|
||||
/*8*/ TOKENIZER_RIGHT_STR,
|
||||
/*9*/ TOKENIZER_MID_STR,
|
||||
/*10*/ TOKENIZER_STR_STR,
|
||||
/*11*/ TOKENIZER_CHR_STR,
|
||||
/*12*/ TOKENIZER_VAL,
|
||||
/*13*/ TOKENIZER_LEN,
|
||||
/*14*/ TOKENIZER_INSTR,
|
||||
/*15*/ TOKENIZER_ASC,
|
||||
#endif
|
||||
/*16*/ TOKENIZER_LET,
|
||||
/*17*/ TOKENIZER_PRINTLN,
|
||||
/*18*/ TOKENIZER_PRINT,
|
||||
/*19*/ TOKENIZER_IF,
|
||||
/*20*/ TOKENIZER_THEN,
|
||||
/*21*/ TOKENIZER_ELSE,
|
||||
/*22*/ TOKENIZER_ENDIF,
|
||||
/*23*/ TOKENIZER_FOR,
|
||||
/*24*/ TOKENIZER_TO,
|
||||
/*25*/ TOKENIZER_NEXT,
|
||||
/*26*/ TOKENIZER_STEP,
|
||||
/*27*/ TOKENIZER_WHILE,
|
||||
/*28*/ TOKENIZER_ENDWHILE,
|
||||
/*29*/ TOKENIZER_GOTO,
|
||||
/*30*/ TOKENIZER_GOSUB,
|
||||
/*31*/ TOKENIZER_RETURN,
|
||||
/*32*/ TOKENIZER_END,
|
||||
/*33*/ TOKENIZER_COMMA,
|
||||
/*34*/ TOKENIZER_PLUS,
|
||||
/*35*/ TOKENIZER_MINUS,
|
||||
/*36*/ TOKENIZER_AND,
|
||||
/*37*/ TOKENIZER_OR,
|
||||
/*38*/ TOKENIZER_ASTR,
|
||||
/*39*/ TOKENIZER_SLASH,
|
||||
/*40*/ TOKENIZER_MOD,
|
||||
/*41*/ TOKENIZER_LEFTPAREN,
|
||||
/*42*/ TOKENIZER_RIGHTPAREN,
|
||||
/*43*/ TOKENIZER_LT,
|
||||
/*44*/ TOKENIZER_GT,
|
||||
/*45*/ TOKENIZER_EQ,
|
||||
/*46*/ TOKENIZER_EOL,
|
||||
/* */
|
||||
/* Plus : Start */
|
||||
/* */
|
||||
/*47*/ TOKENIZER_NE,
|
||||
/*48*/ TOKENIZER_GE,
|
||||
/*49*/ TOKENIZER_LE,
|
||||
/*50*/ TOKENIZER_LAND,
|
||||
/*51*/ TOKENIZER_LOR,
|
||||
/*52*/ TOKENIZER_LNOT,
|
||||
/*53*/ TOKENIZER_NOT,
|
||||
/*54*/ TOKENIZER_PRINT_HEX,
|
||||
/*55*/ TOKENIZER_PRINT_DEC,
|
||||
#if defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL)
|
||||
/*56*/ TOKENIZER_INPUT,
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_SLEEP)
|
||||
/*57*/ TOKENIZER_SLEEP,
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_GPIO_CHANNELS)
|
||||
/*58*/ TOKENIZER_PINMODE,
|
||||
/*59*/ TOKENIZER_DREAD,
|
||||
/*60*/ TOKENIZER_DWRITE,
|
||||
#endif
|
||||
#if defined(VARIABLE_TYPE_ARRAY)
|
||||
/*61*/ TOKENIZER_DIM,
|
||||
/*62*/ TOKENIZER_ARRAYVARIABLE,
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR)
|
||||
/*63*/ TOKENIZER_RAN,
|
||||
#if defined(UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS)
|
||||
/*64*/ TOKENIZER_TIC,
|
||||
/*65*/ TOKENIZER_TOC,
|
||||
#endif
|
||||
#endif
|
||||
#if defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_24_8) || \
|
||||
defined(VARIABLE_TYPE_FLOAT_AS_FIXEDPT_22_10)
|
||||
/*66*/ TOKENIZER_INT,
|
||||
/*67*/ TOKENIZER_FLOAT,
|
||||
/*68*/ TOKENIZER_SQRT,
|
||||
/*69*/ TOKENIZER_SIN,
|
||||
/*70*/ TOKENIZER_COS,
|
||||
/*71*/ TOKENIZER_TAN,
|
||||
/*72*/ TOKENIZER_EXP,
|
||||
/*73*/ TOKENIZER_LN,
|
||||
#if defined(UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR)
|
||||
/*74*/ TOKENIZER_UNIFORM,
|
||||
#endif
|
||||
/*75*/ TOKENIZER_ABS,
|
||||
/*76*/ TOKENIZER_FLOOR,
|
||||
/*77*/ TOKENIZER_CEIL,
|
||||
/*78*/ TOKENIZER_ROUND,
|
||||
/*79*/ TOKENIZER_POWER,
|
||||
/*80*/ TOKENIZER_AVERAGEW,
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_HARDWARE_EVENTS)
|
||||
/*81*/ TOKENIZER_HWE,
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_PWM_CHANNELS)
|
||||
/*82*/ TOKENIZER_PWMCONF,
|
||||
/*83*/ TOKENIZER_PWM,
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_ANALOG_READ)
|
||||
/*84*/ TOKENIZER_AREADCONF,
|
||||
/*85*/ TOKENIZER_AREAD,
|
||||
#endif
|
||||
/*86*/ TOKENIZER_LABEL,
|
||||
/*87*/ TOKENIZER_COLON,
|
||||
#if defined(UBASIC_SCRIPT_HAVE_STORE_VARS_IN_FLASH)
|
||||
/*88*/ TOKENIZER_STORE,
|
||||
/*89*/ TOKENIZER_RECALL,
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_BACNET)
|
||||
/*90*/ TOKENIZER_BACNET_CREATE_OBJECT,
|
||||
/*91*/ TOKENIZER_BACNET_READ_PROPERTY,
|
||||
/*92*/ TOKENIZER_BACNET_WRITE_PROPERTY,
|
||||
#endif
|
||||
/*93*/ TOKENIZER_CLEAR,
|
||||
/* */
|
||||
/* Plus: End */
|
||||
/* */
|
||||
};
|
||||
|
||||
struct tokenizer_data {
|
||||
const char *ptr;
|
||||
const char *nextptr;
|
||||
const char *prog;
|
||||
uint8_t current_token;
|
||||
};
|
||||
|
||||
void tokenizer_init(struct tokenizer_data *data, const char *program);
|
||||
void tokenizer_next(struct tokenizer_data *data);
|
||||
uint8_t tokenizer_token(struct tokenizer_data *data);
|
||||
VARIABLE_TYPE tokenizer_num(struct tokenizer_data *data);
|
||||
VARIABLE_TYPE tokenizer_int(struct tokenizer_data *data);
|
||||
|
||||
#ifdef FIXEDPT_FBITS
|
||||
VARIABLE_TYPE tokenizer_float(struct tokenizer_data *data);
|
||||
#endif
|
||||
|
||||
uint8_t tokenizer_variable_num(struct tokenizer_data *data);
|
||||
bool tokenizer_finished(struct tokenizer_data *data);
|
||||
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
void tokenizer_string(struct tokenizer_data *data, char *dest, uint8_t len);
|
||||
int8_t tokenizer_stringlookahead(struct tokenizer_data *data);
|
||||
#endif
|
||||
|
||||
void tokenizer_label(struct tokenizer_data *data, char *dest, uint8_t len);
|
||||
uint16_t tokenizer_save_offset(struct tokenizer_data *data);
|
||||
void tokenizer_jump_offset(struct tokenizer_data *data, uint16_t offset);
|
||||
|
||||
const char *tokenizer_name(VARIABLE_TYPE token);
|
||||
|
||||
#endif /* __TOKENIZER_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2006, Adam Dunkels
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Modified to support simple string variables and functions by David Mitchell
|
||||
* November 2008.
|
||||
* Changes and additions are marked 'string additions' throughout
|
||||
*
|
||||
* Modified to support fixed point arithmetic, and number of math and io and
|
||||
* hardware functions by Marijan Kostrun, January-February 2018.
|
||||
* uBasic-Plus Copyright (c) 2017-2018, M. Kostrun
|
||||
*
|
||||
* Modified to support multiple programs and use a structure to hold
|
||||
* each program state. 2025 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef __UBASIC_H__
|
||||
#define __UBASIC_H__
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include "platform.h"
|
||||
#include "tokenizer.h"
|
||||
|
||||
/* define a status structure with bit fields */
|
||||
typedef union {
|
||||
uint8_t byte;
|
||||
struct {
|
||||
uint8_t notInitialized : 1;
|
||||
uint8_t stringstackModified : 1;
|
||||
uint8_t bit2 : 1;
|
||||
uint8_t bit3 : 1;
|
||||
uint8_t bit4 : 1;
|
||||
uint8_t WaitForSerialInput : 1;
|
||||
uint8_t Error : 1;
|
||||
uint8_t isRunning : 1;
|
||||
} bit;
|
||||
} UBASIC_STATUS;
|
||||
|
||||
#define MAX_FOR_STACK_DEPTH 4
|
||||
struct ubasic_for_state {
|
||||
uint16_t line_after_for;
|
||||
uint8_t for_variable;
|
||||
VARIABLE_TYPE to;
|
||||
VARIABLE_TYPE step;
|
||||
};
|
||||
|
||||
#define MAX_WHILE_STACK_DEPTH 4
|
||||
struct ubasic_while_state {
|
||||
uint16_t line_while;
|
||||
int16_t line_after_endwhile;
|
||||
};
|
||||
|
||||
#define MAX_GOSUB_STACK_DEPTH 10
|
||||
#define MAX_IF_STACK_DEPTH 4
|
||||
|
||||
#define UBASIC_SERIAL_INPUT_MS 50
|
||||
|
||||
enum {
|
||||
UBASIC_RECALL_STORE_TYPE_VARIABLE = 0,
|
||||
UBASIC_RECALL_STORE_TYPE_STRING = 1,
|
||||
UBASIC_RECALL_STORE_TYPE_ARRAY = 2,
|
||||
UBASIC_RECALL_STORE_TYPE_MAX = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* A timer.
|
||||
*
|
||||
* This structure is used for declaring a timer. The timer must be set
|
||||
* with mstimer_set() before it can be used.
|
||||
*/
|
||||
struct ubasic_mstimer {
|
||||
uint32_t start;
|
||||
uint32_t interval;
|
||||
};
|
||||
|
||||
struct ubasic_data {
|
||||
UBASIC_STATUS status;
|
||||
uint8_t input_how;
|
||||
struct tokenizer_data tree;
|
||||
|
||||
#if defined(VARIABLE_TYPE_ARRAY)
|
||||
VARIABLE_TYPE arrays_data[VARIABLE_TYPE_ARRAY];
|
||||
int16_t free_arrayptr;
|
||||
int16_t arrayvariable[MAX_VARNUM];
|
||||
#endif
|
||||
const char *program_ptr;
|
||||
|
||||
uint16_t gosub_stack[MAX_GOSUB_STACK_DEPTH];
|
||||
uint8_t gosub_stack_ptr;
|
||||
|
||||
struct ubasic_for_state for_stack[MAX_FOR_STACK_DEPTH];
|
||||
uint8_t for_stack_ptr;
|
||||
|
||||
int16_t if_stack[MAX_IF_STACK_DEPTH];
|
||||
uint8_t if_stack_ptr;
|
||||
|
||||
struct ubasic_while_state while_stack[MAX_WHILE_STACK_DEPTH];
|
||||
uint8_t while_stack_ptr;
|
||||
|
||||
VARIABLE_TYPE variables[MAX_VARNUM];
|
||||
|
||||
#if defined(UBASIC_SCRIPT_HAVE_STORE_VARS_IN_FLASH)
|
||||
uint8_t varnum;
|
||||
#endif
|
||||
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
char stringstack[MAX_BUFFERLEN];
|
||||
int16_t freebufptr;
|
||||
int16_t stringvariables[MAX_SVARNUM];
|
||||
#endif
|
||||
|
||||
#if defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL)
|
||||
uint8_t input_varnum;
|
||||
uint8_t input_type;
|
||||
char statement[UBASIC_STATEMENT_SIZE];
|
||||
#endif
|
||||
#if defined(VARIABLE_TYPE_ARRAY)
|
||||
VARIABLE_TYPE input_array_index;
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS)
|
||||
uint32_t tic_toc_timer[UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS];
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_SLEEP)
|
||||
struct ubasic_mstimer input_wait_timer;
|
||||
struct ubasic_mstimer sleep_timer;
|
||||
#endif
|
||||
|
||||
/* API for hardware drivers */
|
||||
#if defined(UBASIC_SCRIPT_HAVE_PWM_CHANNELS)
|
||||
void (*pwm_config)(uint16_t psc, uint16_t per);
|
||||
void (*pwm_write)(uint8_t ch, int32_t dutycycle);
|
||||
int32_t (*pwm_read)(uint8_t ch);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_GPIO_CHANNELS)
|
||||
void (*gpio_config)(uint8_t ch, int8_t mode, uint8_t freq);
|
||||
void (*gpio_write)(uint8_t ch, uint8_t pin_state);
|
||||
int32_t (*gpio_read)(uint8_t ch);
|
||||
#endif
|
||||
#if ( \
|
||||
defined(UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS) || \
|
||||
defined(UBASIC_SCRIPT_HAVE_SLEEP) || \
|
||||
defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL))
|
||||
uint32_t (*mstimer_now)(void);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_ANALOG_READ)
|
||||
void (*adc_config)(uint8_t sampletime, uint8_t nreads);
|
||||
int32_t (*adc_read)(uint8_t channel);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_HARDWARE_EVENTS)
|
||||
int8_t (*hw_event)(uint8_t bit);
|
||||
void (*hw_event_clear)(uint8_t bit);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR)
|
||||
uint32_t (*random_uint32)(uint8_t size);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_STORE_VARS_IN_FLASH)
|
||||
void (*variable_write)(
|
||||
uint8_t Name, uint8_t Vartype, uint8_t datalen_bytes, uint8_t *dataptr);
|
||||
void (*variable_read)(
|
||||
uint8_t Name, uint8_t Vartype, uint8_t *dataptr, uint8_t *datalen);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL)
|
||||
int (*ubasic_getc)(void);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_PRINT_TO_SERIAL)
|
||||
void (*serial_write)(const char *buffer, uint16_t n);
|
||||
#endif
|
||||
#if defined(UBASIC_SCRIPT_HAVE_BACNET)
|
||||
void (*bacnet_create_object)(
|
||||
uint16_t object_type, uint32_t instance, char *object_name);
|
||||
void (*bacnet_write_property)(
|
||||
uint16_t object_type,
|
||||
uint32_t instance,
|
||||
uint32_t property_id,
|
||||
VARIABLE_TYPE value);
|
||||
VARIABLE_TYPE(*bacnet_read_property)
|
||||
(uint16_t object_type, uint32_t instance, uint32_t property_id);
|
||||
#endif
|
||||
};
|
||||
|
||||
void ubasic_load_program(struct ubasic_data *data, const char *program);
|
||||
void ubasic_clear_variables(struct ubasic_data *data);
|
||||
int32_t ubasic_run_program(struct ubasic_data *data);
|
||||
uint8_t ubasic_execute_statement(struct ubasic_data *data, char *statement);
|
||||
uint8_t ubasic_finished(struct ubasic_data *data);
|
||||
|
||||
uint8_t ubasic_waiting_for_input(struct ubasic_data *data);
|
||||
uint8_t ubasic_getline(struct ubasic_data *data, int ch);
|
||||
int ubasic_printf(struct ubasic_data *data, const char *format, ...);
|
||||
int ubasic_getc(struct ubasic_data *data);
|
||||
|
||||
VARIABLE_TYPE ubasic_get_variable(struct ubasic_data *data, char variable);
|
||||
void ubasic_set_variable(
|
||||
struct ubasic_data *data, char variable, VARIABLE_TYPE value);
|
||||
|
||||
#if defined(VARIABLE_TYPE_ARRAY)
|
||||
void ubasic_dim_arrayvariable(
|
||||
struct ubasic_data *data, char variable, int16_t size);
|
||||
void ubasic_set_arrayvariable(
|
||||
struct ubasic_data *data, char variable, uint16_t idx, VARIABLE_TYPE value);
|
||||
VARIABLE_TYPE
|
||||
ubasic_get_arrayvariable(struct ubasic_data *data, char variable, uint16_t idx);
|
||||
#endif
|
||||
|
||||
#if defined(VARIABLE_TYPE_STRING)
|
||||
int16_t ubasic_get_stringvariable(struct ubasic_data *data, uint8_t varnum);
|
||||
void ubasic_set_stringvariable(
|
||||
struct ubasic_data *data, uint8_t varnum, int16_t size);
|
||||
#endif
|
||||
|
||||
/* API to interface and initialize the ported hardware drivers */
|
||||
void ubasic_port_init(struct ubasic_data *data);
|
||||
|
||||
#endif /* __UBASIC_H__ */
|
||||
Reference in New Issue
Block a user