Added uBASIC-Plus program object example to STM32F4xx. (#967)
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@
|
|||||||
/*#define REMOVE_FLASH_BYTE_SUPPORT */
|
/*#define REMOVE_FLASH_BYTE_SUPPORT */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GCC doesn't optimize long int arithmetics very clever. As the
|
* GCC doesn't optimize long int arithmetic very cleverly. As the
|
||||||
* address only needs to be larger than 16 bits for the ATmega128 and
|
* address only needs to be larger than 16 bits for the ATmega128 and
|
||||||
* above (where flash consumptions isn't much of an issue as the
|
* above (where flash consumptions isn't much of an issue as the
|
||||||
* entire boot loader will still fit even into the smallest possible
|
* entire boot loader will still fit even into the smallest possible
|
||||||
|
|||||||
@@ -1,7 +1,27 @@
|
|||||||
---
|
---
|
||||||
# Disable formatting for now as there is external code. We should move external
|
BasedOnStyle: WebKit
|
||||||
# code to a separate directory and enable formatting for our code.
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: false
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 1
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
PointerAlignment: Right
|
||||||
|
InsertBraces: true
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
SortIncludes: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
# Const always to left side.
|
||||||
|
QualifierAlignment: Left
|
||||||
|
---
|
||||||
|
Language: JavaScript
|
||||||
DisableFormat: true
|
DisableFormat: true
|
||||||
|
...
|
||||||
# DisableFormat will not disable include sorting with some versions.
|
|
||||||
SortIncludes: Never
|
|
||||||
|
|||||||
Vendored
+51
-47
@@ -1,49 +1,53 @@
|
|||||||
{
|
{
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"type": "cortex-debug",
|
"type": "cortex-debug",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug with OpenOCD",
|
"name": "Debug with OpenOCD",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"executable": "${workspaceRoot}/build/bacnet-mstp.elf",
|
"executable": "${workspaceRoot}/build/bacnet-mstp.elf",
|
||||||
"servertype": "openocd",
|
"servertype": "openocd",
|
||||||
"device": "STM32F429ZI",
|
"device": "STM32F429ZI",
|
||||||
"serialNumber": "",
|
"serialNumber": "",
|
||||||
"configFiles": [
|
"configFiles": [
|
||||||
"interface/stlink.cfg",
|
"interface/stlink.cfg",
|
||||||
"target/stm32f4x.cfg"
|
"target/stm32f4x.cfg"
|
||||||
],
|
],
|
||||||
"searchDir": [],
|
"searchDir": [],
|
||||||
"svdFile":"${workspaceRoot}/stm32f429.svd",
|
"svdFile": "${workspaceRoot}/stm32f429.svd",
|
||||||
"runToEntryPoint": "main",
|
"runToEntryPoint": "main",
|
||||||
"liveWatch": {
|
"liveWatch": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"samplesPerSecond": 1
|
"samplesPerSecond": 1
|
||||||
},
|
},
|
||||||
"swoConfig": {
|
"swoConfig": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"cpuFrequency": 8000000,
|
"cpuFrequency": 8000000,
|
||||||
"swoFrequency": 2000000,
|
"swoFrequency": 2000000,
|
||||||
"source": "probe",
|
"source": "probe",
|
||||||
"decoders": [
|
"decoders": [
|
||||||
{ "type": "console", "label": "ITM", "port": 0 }
|
{
|
||||||
]
|
"type": "console",
|
||||||
},
|
"label": "ITM",
|
||||||
"preLaunchCommands": [
|
"port": 0
|
||||||
// guarantee the halt at soon as possible after reset
|
}
|
||||||
"monitor reset",
|
]
|
||||||
"monitor sleep 2000",
|
},
|
||||||
"monitor reset halt",
|
"preLaunchCommands": [
|
||||||
// synchronize GDB to the state of the target after reset
|
// guarantee the halt at soon as possible after reset
|
||||||
"monitor gdb_sync",
|
"monitor reset",
|
||||||
"stepi"
|
"monitor sleep 2000",
|
||||||
],
|
"monitor reset halt",
|
||||||
"postLaunchCommands": [
|
// synchronize GDB to the state of the target after reset
|
||||||
"monitor reset init",
|
"monitor gdb_sync",
|
||||||
"monitor sleep 200"
|
"stepi"
|
||||||
],
|
],
|
||||||
"showDevDebugOutput": "raw"
|
"postLaunchCommands": [
|
||||||
}
|
"monitor reset init",
|
||||||
]
|
"monitor sleep 200"
|
||||||
|
],
|
||||||
|
"showDevDebugOutput": "raw"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ set(BACNET_PROJECT_SOURCE
|
|||||||
${CMAKE_SOURCE_DIR}/mstimer-init.c
|
${CMAKE_SOURCE_DIR}/mstimer-init.c
|
||||||
${CMAKE_SOURCE_DIR}/rs485.c
|
${CMAKE_SOURCE_DIR}/rs485.c
|
||||||
|
|
||||||
|
${CMAKE_SOURCE_DIR}/program-ubasic.c
|
||||||
|
${CMAKE_SOURCE_DIR}/ubasic-port.c
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/device.c
|
${CMAKE_SOURCE_DIR}/device.c
|
||||||
${CMAKE_SOURCE_DIR}/netport.c
|
${CMAKE_SOURCE_DIR}/netport.c
|
||||||
|
|
||||||
@@ -163,6 +166,9 @@ set(BACNET_PROJECT_SOURCE
|
|||||||
${LIBRARY_BACNET_BASIC}/object/ms-input.c
|
${LIBRARY_BACNET_BASIC}/object/ms-input.c
|
||||||
${LIBRARY_BACNET_BASIC}/object/mso.c
|
${LIBRARY_BACNET_BASIC}/object/mso.c
|
||||||
${LIBRARY_BACNET_BASIC}/object/msv.c
|
${LIBRARY_BACNET_BASIC}/object/msv.c
|
||||||
|
${LIBRARY_BACNET_BASIC}/object/program.c
|
||||||
|
${LIBRARY_BACNET_BASIC}/program/ubasic/ubasic.c
|
||||||
|
${LIBRARY_BACNET_BASIC}/program/ubasic/tokenizer.c
|
||||||
|
|
||||||
${LIBRARY_BACNET_BASIC}/service/h_dcc.c
|
${LIBRARY_BACNET_BASIC}/service/h_dcc.c
|
||||||
${LIBRARY_BACNET_BASIC}/service/h_apdu.c
|
${LIBRARY_BACNET_BASIC}/service/h_apdu.c
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ PLATFORM_SRC = \
|
|||||||
$(PLATFORM_DIR)/netport.c \
|
$(PLATFORM_DIR)/netport.c \
|
||||||
$(PLATFORM_DIR)/rs485.c \
|
$(PLATFORM_DIR)/rs485.c \
|
||||||
$(PLATFORM_DIR)/mstimer-init.c \
|
$(PLATFORM_DIR)/mstimer-init.c \
|
||||||
|
$(PLATFORM_DIR)/program-ubasic.c \
|
||||||
|
$(PLATFORM_DIR)/ubasic-port.c \
|
||||||
$(PLATFORM_DIR)/stm32f4xx_it.c \
|
$(PLATFORM_DIR)/stm32f4xx_it.c \
|
||||||
$(PLATFORM_DIR)/system_stm32f4xx.c
|
$(PLATFORM_DIR)/system_stm32f4xx.c
|
||||||
|
|
||||||
@@ -43,6 +45,9 @@ BASIC_SRC = \
|
|||||||
$(BACNET_BASIC)/object/ms-input.c \
|
$(BACNET_BASIC)/object/ms-input.c \
|
||||||
$(BACNET_BASIC)/object/mso.c \
|
$(BACNET_BASIC)/object/mso.c \
|
||||||
$(BACNET_BASIC)/object/msv.c \
|
$(BACNET_BASIC)/object/msv.c \
|
||||||
|
$(BACNET_BASIC)/object/program.c \
|
||||||
|
$(BACNET_BASIC)/program/ubasic/ubasic.c \
|
||||||
|
$(BACNET_BASIC)/program/ubasic/tokenizer.c \
|
||||||
$(BACNET_BASIC)/service/h_apdu.c \
|
$(BACNET_BASIC)/service/h_apdu.c \
|
||||||
$(BACNET_BASIC)/service/h_dcc.c \
|
$(BACNET_BASIC)/service/h_dcc.c \
|
||||||
$(BACNET_BASIC)/service/h_rd.c \
|
$(BACNET_BASIC)/service/h_rd.c \
|
||||||
@@ -173,6 +178,7 @@ BACNET_FLAGS += -DMAX_TSM_TRANSACTIONS=0
|
|||||||
BACNET_FLAGS += -DMAX_CHARACTER_STRING_BYTES=64
|
BACNET_FLAGS += -DMAX_CHARACTER_STRING_BYTES=64
|
||||||
BACNET_FLAGS += -DMAX_OCTET_STRING_BYTES=64
|
BACNET_FLAGS += -DMAX_OCTET_STRING_BYTES=64
|
||||||
BACNET_FLAGS += -DBACAPP_MINIMAL
|
BACNET_FLAGS += -DBACAPP_MINIMAL
|
||||||
|
BACNET_FLAGS += -DBACNET_STACK_DEPRECATED_DISABLE
|
||||||
# if called from root Makefile, PRINT was already defined
|
# if called from root Makefile, PRINT was already defined
|
||||||
BACNET_FLAGS += -UPRINT_ENABLED
|
BACNET_FLAGS += -UPRINT_ENABLED
|
||||||
BACNET_FLAGS += -DPRINT_ENABLED=0
|
BACNET_FLAGS += -DPRINT_ENABLED=0
|
||||||
|
|||||||
+15
-75
@@ -1,15 +1,16 @@
|
|||||||
/**************************************************************************
|
/**
|
||||||
*
|
* @file
|
||||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
* @brief BACnet stack initialization and task processing
|
||||||
*
|
* @author Steve Karg
|
||||||
* SPDX-License-Identifier: MIT
|
* @date 2011
|
||||||
*
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*********************************************************************/
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
/* hardware layer includes */
|
/* hardware layer includes */
|
||||||
#include "bacnet/basic/sys/mstimer.h"
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
#include "rs485.h"
|
#include "rs485.h"
|
||||||
|
#include "program-ubasic.h"
|
||||||
/* BACnet Stack includes */
|
/* BACnet Stack includes */
|
||||||
#include "bacnet/datalink/datalink.h"
|
#include "bacnet/datalink/datalink.h"
|
||||||
#include "bacnet/npdu.h"
|
#include "bacnet/npdu.h"
|
||||||
@@ -20,15 +21,8 @@
|
|||||||
#include "bacnet/iam.h"
|
#include "bacnet/iam.h"
|
||||||
/* BACnet objects */
|
/* BACnet objects */
|
||||||
#include "bacnet/basic/object/device.h"
|
#include "bacnet/basic/object/device.h"
|
||||||
#include "bacnet/basic/object/ai.h"
|
#include "bacnet/basic/object/program.h"
|
||||||
#include "bacnet/basic/object/ao.h"
|
#include "bacnet/basic/program/ubasic/ubasic.h"
|
||||||
#include "bacnet/basic/object/av.h"
|
|
||||||
#include "bacnet/basic/object/bi.h"
|
|
||||||
#include "bacnet/basic/object/bo.h"
|
|
||||||
#include "bacnet/basic/object/bv.h"
|
|
||||||
#include "bacnet/basic/object/ms-input.h"
|
|
||||||
#include "bacnet/basic/object/mso.h"
|
|
||||||
#include "bacnet/basic/object/msv.h"
|
|
||||||
/* me */
|
/* me */
|
||||||
#include "bacnet.h"
|
#include "bacnet.h"
|
||||||
|
|
||||||
@@ -38,69 +32,14 @@ static struct mstimer DCC_Timer;
|
|||||||
/* Device ID to track changes */
|
/* Device ID to track changes */
|
||||||
static uint32_t Device_ID = 0xFFFFFFFF;
|
static uint32_t Device_ID = 0xFFFFFFFF;
|
||||||
|
|
||||||
#ifndef BACNET_ANALOG_INPUTS_MAX
|
|
||||||
#define BACNET_ANALOG_INPUTS_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_ANALOG_OUTPUTS_MAX
|
|
||||||
#define BACNET_ANALOG_OUTPUTS_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_ANALOG_VALUES_MAX
|
|
||||||
#define BACNET_ANALOG_VALUES_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_BINARY_INPUTS_MAX
|
|
||||||
#define BACNET_BINARY_INPUTS_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_BINARY_OUTPUTS_MAX
|
|
||||||
#define BACNET_BINARY_OUTPUTS_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_BINARY_VALUES_MAX
|
|
||||||
#define BACNET_BINARY_VALUES_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_MULTISTATE_INPUTS_MAX
|
|
||||||
#define BACNET_MULTISTATE_INPUTS_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_MULTISTATE_OUTPUTS_MAX
|
|
||||||
#define BACNET_MULTISTATE_OUTPUTS_MAX 12
|
|
||||||
#endif
|
|
||||||
#ifndef BACNET_MULTISTATE_VALUES_MAX
|
|
||||||
#define BACNET_MULTISTATE_VALUES_MAX 12
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the BACnet device object, the service handlers, and timers
|
* @brief Initialize the BACnet device object, the service handlers, and timers
|
||||||
*/
|
*/
|
||||||
void bacnet_init(void)
|
void bacnet_init(void)
|
||||||
{
|
{
|
||||||
uint32_t instance;
|
|
||||||
/* initialize objects */
|
/* initialize objects */
|
||||||
Device_Init(NULL);
|
Device_Init(NULL);
|
||||||
for (instance = 1; instance <= BACNET_ANALOG_INPUTS_MAX; instance++) {
|
Program_UBASIC_Init(BACNET_MAX_INSTANCE);
|
||||||
Analog_Input_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_ANALOG_OUTPUTS_MAX; instance++) {
|
|
||||||
Analog_Output_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_ANALOG_VALUES_MAX; instance++) {
|
|
||||||
Analog_Value_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_BINARY_INPUTS_MAX; instance++) {
|
|
||||||
Binary_Input_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_BINARY_OUTPUTS_MAX; instance++) {
|
|
||||||
Binary_Output_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_BINARY_VALUES_MAX; instance++) {
|
|
||||||
Binary_Value_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_MULTISTATE_INPUTS_MAX; instance++) {
|
|
||||||
Multistate_Input_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_MULTISTATE_OUTPUTS_MAX; instance++) {
|
|
||||||
Multistate_Output_Create(instance);
|
|
||||||
}
|
|
||||||
for (instance = 1; instance <= BACNET_MULTISTATE_VALUES_MAX; instance++) {
|
|
||||||
Multistate_Value_Create(instance);
|
|
||||||
}
|
|
||||||
/* set up our confirmed service unrecognized service handler - required! */
|
/* set up our confirmed service unrecognized service handler - required! */
|
||||||
apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
|
apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
|
||||||
/* we need to handle who-is to support dynamic device binding */
|
/* we need to handle who-is to support dynamic device binding */
|
||||||
@@ -118,12 +57,12 @@ void bacnet_init(void)
|
|||||||
SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
|
SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
|
||||||
/* local time and date */
|
/* local time and date */
|
||||||
apdu_set_unconfirmed_handler(
|
apdu_set_unconfirmed_handler(
|
||||||
SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION,
|
SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION, handler_timesync);
|
||||||
handler_timesync);
|
|
||||||
handler_timesync_set_callback_set(datetime_timesync);
|
handler_timesync_set_callback_set(datetime_timesync);
|
||||||
datetime_init();
|
datetime_init();
|
||||||
/* handle communication so we can shutup when asked */
|
/* handle communication so we can shutup when asked */
|
||||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
apdu_set_confirmed_handler(
|
||||||
|
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||||
handler_device_communication_control);
|
handler_device_communication_control);
|
||||||
/* start the cyclic 1 second timer for DCC */
|
/* start the cyclic 1 second timer for DCC */
|
||||||
mstimer_set(&DCC_Timer, DCC_CYCLE_SECONDS * 1000);
|
mstimer_set(&DCC_Timer, DCC_CYCLE_SECONDS * 1000);
|
||||||
@@ -154,6 +93,7 @@ void bacnet_task(void)
|
|||||||
mstimer_reset(&DCC_Timer);
|
mstimer_reset(&DCC_Timer);
|
||||||
dcc_timer_seconds(DCC_CYCLE_SECONDS);
|
dcc_timer_seconds(DCC_CYCLE_SECONDS);
|
||||||
}
|
}
|
||||||
|
Program_UBASIC_Task();
|
||||||
/* handle the messaging */
|
/* handle the messaging */
|
||||||
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
||||||
if (pdu_len) {
|
if (pdu_len) {
|
||||||
|
|||||||
@@ -1235,6 +1235,12 @@
|
|||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<name>BACnet Basic System</name>
|
<name>BACnet Basic System</name>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\..\src\bacnet\basic\program\ubasic\ubasic.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\..\src\bacnet\basic\program\ubasic\tokenizer.c</name>
|
||||||
|
</file>
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\..\src\bacnet\basic\sys\bigend.c</name>
|
<name>$PROJ_DIR$\..\..\src\bacnet\basic\sys\bigend.c</name>
|
||||||
</file>
|
</file>
|
||||||
@@ -1277,6 +1283,9 @@
|
|||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\system_stm32f4xx.c</name>
|
<name>$PROJ_DIR$\system_stm32f4xx.c</name>
|
||||||
</file>
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\ubasic-port.c</name>
|
||||||
|
</file>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<name>NUCLEO-BACnet</name>
|
<name>NUCLEO-BACnet</name>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/**************************************************************************
|
/**
|
||||||
*
|
* @file
|
||||||
* Copyright (C) 2010 Steve Karg <skarg@users.sourceforge.net>
|
* @brief BACnet stack initialization and task processing
|
||||||
*
|
* @author Steve Karg
|
||||||
* SPDX-License-Identifier: MIT
|
* @date 2021
|
||||||
*
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*********************************************************************/
|
*/
|
||||||
#ifndef BACNET_H
|
#ifndef BACNET_H
|
||||||
#define BACNET_H
|
#define BACNET_H
|
||||||
|
|
||||||
|
|||||||
+61
-41
@@ -1,14 +1,11 @@
|
|||||||
/**************************************************************************
|
/**
|
||||||
*
|
* @file
|
||||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
* @brief Base "class" for handling all BACnet objects belonging
|
||||||
*
|
* to a BACnet device, as well as Device-specific properties.
|
||||||
* SPDX-License-Identifier: MIT
|
* @author Steve Karg
|
||||||
*
|
* @date 2021
|
||||||
*********************************************************************/
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
/** @file device.c Base "class" for handling all BACnet objects belonging
|
|
||||||
* to a BACnet device, as well as Device-specific properties. */
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -33,12 +30,12 @@
|
|||||||
#include "bacnet/basic/object/ms-input.h"
|
#include "bacnet/basic/object/ms-input.h"
|
||||||
#include "bacnet/basic/object/mso.h"
|
#include "bacnet/basic/object/mso.h"
|
||||||
#include "bacnet/basic/object/msv.h"
|
#include "bacnet/basic/object/msv.h"
|
||||||
|
#include "bacnet/basic/object/program.h"
|
||||||
#if (BACNET_PROTOCOL_REVISION >= 17)
|
#if (BACNET_PROTOCOL_REVISION >= 17)
|
||||||
#include "bacnet/basic/object/netport.h"
|
#include "bacnet/basic/object/netport.h"
|
||||||
#endif
|
#endif
|
||||||
#include "bacnet/basic/object/device.h"
|
#include "bacnet/basic/object/device.h"
|
||||||
|
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
static struct my_object_functions {
|
static struct my_object_functions {
|
||||||
BACNET_OBJECT_TYPE Object_Type;
|
BACNET_OBJECT_TYPE Object_Type;
|
||||||
@@ -93,6 +90,10 @@ static struct my_object_functions {
|
|||||||
Multistate_Value_Index_To_Instance, Multistate_Value_Valid_Instance,
|
Multistate_Value_Index_To_Instance, Multistate_Value_Valid_Instance,
|
||||||
Multistate_Value_Object_Name, Multistate_Value_Read_Property,
|
Multistate_Value_Object_Name, Multistate_Value_Read_Property,
|
||||||
Multistate_Value_Write_Property, Multistate_Value_Property_Lists},
|
Multistate_Value_Write_Property, Multistate_Value_Property_Lists},
|
||||||
|
{ OBJECT_PROGRAM, Program_Init, Program_Count,
|
||||||
|
Program_Index_To_Instance, Program_Valid_Instance,
|
||||||
|
Program_Object_Name, Program_Read_Property,
|
||||||
|
Program_Write_Property, Program_Property_Lists},
|
||||||
#if (BACNET_PROTOCOL_REVISION >= 17)
|
#if (BACNET_PROTOCOL_REVISION >= 17)
|
||||||
{ OBJECT_NETWORK_PORT, Network_Port_Init, Network_Port_Count,
|
{ OBJECT_NETWORK_PORT, Network_Port_Init, Network_Port_Count,
|
||||||
Network_Port_Index_To_Instance, Network_Port_Valid_Instance,
|
Network_Port_Index_To_Instance, Network_Port_Valid_Instance,
|
||||||
@@ -121,14 +122,27 @@ static uint8_t Device_UUID[16];
|
|||||||
static const int Device_Properties_Required[] = {
|
static const int Device_Properties_Required[] = {
|
||||||
/* required properties for this object */
|
/* required properties for this object */
|
||||||
PROP_OBJECT_IDENTIFIER,
|
PROP_OBJECT_IDENTIFIER,
|
||||||
PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_SYSTEM_STATUS, PROP_VENDOR_NAME,
|
PROP_OBJECT_NAME,
|
||||||
PROP_VENDOR_IDENTIFIER, PROP_MODEL_NAME, PROP_FIRMWARE_REVISION,
|
PROP_OBJECT_TYPE,
|
||||||
PROP_APPLICATION_SOFTWARE_VERSION, PROP_PROTOCOL_VERSION,
|
PROP_SYSTEM_STATUS,
|
||||||
PROP_PROTOCOL_REVISION, PROP_PROTOCOL_SERVICES_SUPPORTED,
|
PROP_VENDOR_NAME,
|
||||||
PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, PROP_OBJECT_LIST,
|
PROP_VENDOR_IDENTIFIER,
|
||||||
PROP_MAX_APDU_LENGTH_ACCEPTED, PROP_SEGMENTATION_SUPPORTED,
|
PROP_MODEL_NAME,
|
||||||
PROP_APDU_TIMEOUT, PROP_NUMBER_OF_APDU_RETRIES, PROP_DEVICE_ADDRESS_BINDING,
|
PROP_FIRMWARE_REVISION,
|
||||||
PROP_DATABASE_REVISION, -1 };
|
PROP_APPLICATION_SOFTWARE_VERSION,
|
||||||
|
PROP_PROTOCOL_VERSION,
|
||||||
|
PROP_PROTOCOL_REVISION,
|
||||||
|
PROP_PROTOCOL_SERVICES_SUPPORTED,
|
||||||
|
PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,
|
||||||
|
PROP_OBJECT_LIST,
|
||||||
|
PROP_MAX_APDU_LENGTH_ACCEPTED,
|
||||||
|
PROP_SEGMENTATION_SUPPORTED,
|
||||||
|
PROP_APDU_TIMEOUT,
|
||||||
|
PROP_NUMBER_OF_APDU_RETRIES,
|
||||||
|
PROP_DEVICE_ADDRESS_BINDING,
|
||||||
|
PROP_DATABASE_REVISION,
|
||||||
|
-1
|
||||||
|
};
|
||||||
|
|
||||||
static const int Device_Properties_Optional[] = {
|
static const int Device_Properties_Optional[] = {
|
||||||
/* optional properties for this object */
|
/* optional properties for this object */
|
||||||
@@ -141,7 +155,8 @@ static const int Device_Properties_Optional[] = {
|
|||||||
PROP_LOCAL_TIME,
|
PROP_LOCAL_TIME,
|
||||||
PROP_UTC_OFFSET,
|
PROP_UTC_OFFSET,
|
||||||
PROP_DAYLIGHT_SAVINGS_STATUS,
|
PROP_DAYLIGHT_SAVINGS_STATUS,
|
||||||
-1 };
|
-1
|
||||||
|
};
|
||||||
|
|
||||||
static const int Device_Properties_Proprietary[] = { -1 };
|
static const int Device_Properties_Proprietary[] = { -1 };
|
||||||
|
|
||||||
@@ -153,8 +168,8 @@ static const int Device_Properties_Proprietary[] = { -1 };
|
|||||||
* @return Pointer to the group of object helper functions that implement this
|
* @return Pointer to the group of object helper functions that implement this
|
||||||
* type of Object.
|
* type of Object.
|
||||||
*/
|
*/
|
||||||
static struct my_object_functions *Device_Objects_Find_Functions(
|
static struct my_object_functions *
|
||||||
BACNET_OBJECT_TYPE Object_Type)
|
Device_Objects_Find_Functions(BACNET_OBJECT_TYPE Object_Type)
|
||||||
{
|
{
|
||||||
struct my_object_functions *pObject = NULL;
|
struct my_object_functions *pObject = NULL;
|
||||||
|
|
||||||
@@ -182,7 +197,8 @@ static struct my_object_functions *Device_Objects_Find_Functions(
|
|||||||
* list, separately, the Required, Optional, and Proprietary object
|
* list, separately, the Required, Optional, and Proprietary object
|
||||||
* properties with their counts.
|
* properties with their counts.
|
||||||
*/
|
*/
|
||||||
void Device_Objects_Property_List(BACNET_OBJECT_TYPE object_type,
|
void Device_Objects_Property_List(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
uint32_t object_instance,
|
uint32_t object_instance,
|
||||||
struct special_property_list_t *pPropertyList)
|
struct special_property_list_t *pPropertyList)
|
||||||
{
|
{
|
||||||
@@ -200,8 +216,9 @@ void Device_Objects_Property_List(BACNET_OBJECT_TYPE object_type,
|
|||||||
|
|
||||||
pObject = Device_Objects_Find_Functions(object_type);
|
pObject = Device_Objects_Find_Functions(object_type);
|
||||||
if ((pObject != NULL) && (pObject->Object_RPM_List != NULL)) {
|
if ((pObject != NULL) && (pObject->Object_RPM_List != NULL)) {
|
||||||
pObject->Object_RPM_List(&pPropertyList->Required.pList,
|
pObject->Object_RPM_List(
|
||||||
&pPropertyList->Optional.pList, &pPropertyList->Proprietary.pList);
|
&pPropertyList->Required.pList, &pPropertyList->Optional.pList,
|
||||||
|
&pPropertyList->Proprietary.pList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetch the counts if available otherwise zero them */
|
/* Fetch the counts if available otherwise zero them */
|
||||||
@@ -430,8 +447,9 @@ bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
|||||||
|
|
||||||
if (object_id <= BACNET_MAX_INSTANCE) {
|
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||||
Object_Instance_Number = object_id;
|
Object_Instance_Number = object_id;
|
||||||
} else
|
} else {
|
||||||
status = false;
|
status = false;
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -656,7 +674,8 @@ int Device_Object_List_Element_Encode(
|
|||||||
* Object.
|
* Object.
|
||||||
* @return True on success or else False if not found.
|
* @return True on success or else False if not found.
|
||||||
*/
|
*/
|
||||||
bool Device_Valid_Object_Name(const BACNET_CHARACTER_STRING *object_name1,
|
bool Device_Valid_Object_Name(
|
||||||
|
const BACNET_CHARACTER_STRING *object_name1,
|
||||||
BACNET_OBJECT_TYPE *object_type,
|
BACNET_OBJECT_TYPE *object_type,
|
||||||
uint32_t *object_instance)
|
uint32_t *object_instance)
|
||||||
{
|
{
|
||||||
@@ -675,7 +694,7 @@ bool Device_Valid_Object_Name(const BACNET_CHARACTER_STRING *object_name1,
|
|||||||
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE)type);
|
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE)type);
|
||||||
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
|
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
|
||||||
(pObject->Object_Name(instance, &object_name2) &&
|
(pObject->Object_Name(instance, &object_name2) &&
|
||||||
characterstring_same(object_name1, &object_name2))) {
|
characterstring_same(object_name1, &object_name2))) {
|
||||||
found = true;
|
found = true;
|
||||||
if (object_type) {
|
if (object_type) {
|
||||||
*object_type = type;
|
*object_type = type;
|
||||||
@@ -716,7 +735,8 @@ bool Device_Valid_Object_Id(
|
|||||||
* @param object_name [out] The Object Name found for this child Object.
|
* @param object_name [out] The Object Name found for this child Object.
|
||||||
* @return True on success or else False if not found.
|
* @return True on success or else False if not found.
|
||||||
*/
|
*/
|
||||||
bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type,
|
bool Device_Object_Name_Copy(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
uint32_t object_instance,
|
uint32_t object_instance,
|
||||||
BACNET_CHARACTER_STRING *object_name)
|
BACNET_CHARACTER_STRING *object_name)
|
||||||
{
|
{
|
||||||
@@ -811,7 +831,8 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
bitstring_init(&bit_string);
|
bitstring_init(&bit_string);
|
||||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||||
/* automatic lookup based on handlers set */
|
/* automatic lookup based on handlers set */
|
||||||
bitstring_set_bit(&bit_string, (uint8_t)i,
|
bitstring_set_bit(
|
||||||
|
&bit_string, (uint8_t)i,
|
||||||
apdu_service_supported((BACNET_SERVICES_SUPPORTED)i));
|
apdu_service_supported((BACNET_SERVICES_SUPPORTED)i));
|
||||||
}
|
}
|
||||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||||
@@ -836,9 +857,9 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
break;
|
break;
|
||||||
case PROP_OBJECT_LIST:
|
case PROP_OBJECT_LIST:
|
||||||
count = Device_Object_List_Count();
|
count = Device_Object_List_Count();
|
||||||
apdu_len = bacnet_array_encode(rpdata->object_instance,
|
apdu_len = bacnet_array_encode(
|
||||||
rpdata->array_index, Device_Object_List_Element_Encode, count,
|
rpdata->object_instance, rpdata->array_index,
|
||||||
apdu, apdu_max);
|
Device_Object_List_Element_Encode, count, apdu, apdu_max);
|
||||||
if (apdu_len == BACNET_STATUS_ABORT) {
|
if (apdu_len == BACNET_STATUS_ABORT) {
|
||||||
rpdata->error_code =
|
rpdata->error_code =
|
||||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
@@ -893,8 +914,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
break;
|
break;
|
||||||
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||||
datetime_local(&bdate, &btime, &utc_offset_minutes, &dst_active);
|
datetime_local(&bdate, &btime, &utc_offset_minutes, &dst_active);
|
||||||
apdu_len =
|
apdu_len = encode_application_boolean(&apdu[0], dst_active);
|
||||||
encode_application_boolean(&apdu[0], dst_active);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||||
@@ -949,16 +969,16 @@ static int Read_Property_Common(
|
|||||||
encode_application_character_string(&apdu[0], &char_string);
|
encode_application_character_string(&apdu[0], &char_string);
|
||||||
break;
|
break;
|
||||||
case PROP_OBJECT_TYPE:
|
case PROP_OBJECT_TYPE:
|
||||||
apdu_len = encode_application_enumerated(
|
apdu_len =
|
||||||
&apdu[0], rpdata->object_type);
|
encode_application_enumerated(&apdu[0], rpdata->object_type);
|
||||||
break;
|
break;
|
||||||
#if (BACNET_PROTOCOL_REVISION >= 14)
|
#if (BACNET_PROTOCOL_REVISION >= 14)
|
||||||
case PROP_PROPERTY_LIST:
|
case PROP_PROPERTY_LIST:
|
||||||
Device_Objects_Property_List(
|
Device_Objects_Property_List(
|
||||||
rpdata->object_type, rpdata->object_instance, &property_list);
|
rpdata->object_type, rpdata->object_instance, &property_list);
|
||||||
apdu_len = property_list_encode(rpdata,
|
apdu_len = property_list_encode(
|
||||||
property_list.Required.pList, property_list.Optional.pList,
|
rpdata, property_list.Required.pList,
|
||||||
property_list.Proprietary.pList);
|
property_list.Optional.pList, property_list.Proprietary.pList);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/**************************************************************************
|
/**
|
||||||
*
|
* @file
|
||||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
* @brief LED control for the STM32F4xx
|
||||||
*
|
* @author Steve Karg
|
||||||
* SPDX-License-Identifier: MIT
|
* @date 2021
|
||||||
*
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*********************************************************************/
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
#include "bacnet/basic/sys/mstimer.h"
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/**************************************************************************
|
/**
|
||||||
*
|
* @file
|
||||||
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
* @brief LED control for the STM32F4xx
|
||||||
*
|
* @author Steve Karg
|
||||||
* SPDX-License-Identifier: MIT
|
* @date 2021
|
||||||
*
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*********************************************************************/
|
*/
|
||||||
#ifndef LED_H
|
#ifndef LED_H
|
||||||
#define LED_H
|
#define LED_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/************************************************************************
|
/**
|
||||||
*
|
* @file
|
||||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
* @brief Main function for the STM32F4xx NUCLEO board
|
||||||
*
|
* @author Steve Karg
|
||||||
* SPDX-License-Identifier: MIT
|
* @date 2021
|
||||||
*
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*************************************************************************/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -102,7 +102,7 @@ int main(void)
|
|||||||
MSTP_Port.ZeroConfigEnabled = true;
|
MSTP_Port.ZeroConfigEnabled = true;
|
||||||
MSTP_Port.Zero_Config_Preferred_Station = 0;
|
MSTP_Port.Zero_Config_Preferred_Station = 0;
|
||||||
MSTP_Port.SlaveNodeEnabled = false;
|
MSTP_Port.SlaveNodeEnabled = false;
|
||||||
MSTP_Port.CheckAutoBaud = false;
|
MSTP_Port.CheckAutoBaud = true;
|
||||||
/* user data */
|
/* user data */
|
||||||
MSTP_User_Data.RS485_Driver = &RS485_Driver;
|
MSTP_User_Data.RS485_Driver = &RS485_Driver;
|
||||||
MSTP_Port.UserData = &MSTP_User_Data;
|
MSTP_Port.UserData = &MSTP_User_Data;
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
/**************************************************************************
|
/**
|
||||||
*
|
* @file
|
||||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
* @brief Generate a periodic timer tick for use by generic timers in the code.
|
||||||
*
|
* @author Steve Karg
|
||||||
* SPDX-License-Identifier: MIT
|
* @date 2011
|
||||||
*
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
* Module Description:
|
*/
|
||||||
* Generate a periodic timer tick for use by generic timers in the code.
|
|
||||||
*
|
|
||||||
*************************************************************************/
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "bacnet/basic/sys/mstimer.h"
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
|
|||||||
+38
-29
@@ -1,17 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
|
* @brief The Network Port object provides access to the configuration
|
||||||
|
* and properties of network ports of a device.
|
||||||
* @author Steve Karg
|
* @author Steve Karg
|
||||||
* @date 2016
|
* @date 2016
|
||||||
* @brief Network port objects, customize for your use
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*
|
|
||||||
* @section DESCRIPTION
|
|
||||||
*
|
|
||||||
* The Network Port object provides access to the configuration
|
|
||||||
* and properties of network ports of a device.
|
|
||||||
*
|
|
||||||
* @section LICENSE
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
*/
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -55,9 +48,15 @@ struct object_data Object_List[BACNET_NETWORK_PORTS_MAX];
|
|||||||
static uint32_t Link_Speeds[] = { 9600, 19200, 38400, 57600, 76800, 115200 };
|
static uint32_t Link_Speeds[] = { 9600, 19200, 38400, 57600, 76800, 115200 };
|
||||||
|
|
||||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||||
static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
|
static const int Network_Port_Properties_Required[] = {
|
||||||
PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY,
|
PROP_OBJECT_IDENTIFIER,
|
||||||
PROP_OUT_OF_SERVICE, PROP_NETWORK_TYPE, PROP_PROTOCOL_LEVEL,
|
PROP_OBJECT_NAME,
|
||||||
|
PROP_OBJECT_TYPE,
|
||||||
|
PROP_STATUS_FLAGS,
|
||||||
|
PROP_RELIABILITY,
|
||||||
|
PROP_OUT_OF_SERVICE,
|
||||||
|
PROP_NETWORK_TYPE,
|
||||||
|
PROP_PROTOCOL_LEVEL,
|
||||||
PROP_CHANGES_PENDING,
|
PROP_CHANGES_PENDING,
|
||||||
#if (BACNET_PROTOCOL_REVISION < 24)
|
#if (BACNET_PROTOCOL_REVISION < 24)
|
||||||
PROP_APDU_LENGTH,
|
PROP_APDU_LENGTH,
|
||||||
@@ -65,17 +64,22 @@ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
|
|||||||
PROP_NETWORK_NUMBER_QUALITY,
|
PROP_NETWORK_NUMBER_QUALITY,
|
||||||
PROP_LINK_SPEED,
|
PROP_LINK_SPEED,
|
||||||
#endif
|
#endif
|
||||||
-1 };
|
-1
|
||||||
|
};
|
||||||
|
|
||||||
static const int Network_Port_Properties_Optional[] = { PROP_MAC_ADDRESS,
|
static const int Network_Port_Properties_Optional[] = {
|
||||||
PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_LINK_SPEEDS,
|
PROP_MAC_ADDRESS,
|
||||||
|
PROP_MAX_MASTER,
|
||||||
|
PROP_MAX_INFO_FRAMES,
|
||||||
|
PROP_LINK_SPEEDS,
|
||||||
#if (BACNET_PROTOCOL_REVISION >= 24)
|
#if (BACNET_PROTOCOL_REVISION >= 24)
|
||||||
PROP_APDU_LENGTH,
|
PROP_APDU_LENGTH,
|
||||||
PROP_NETWORK_NUMBER,
|
PROP_NETWORK_NUMBER,
|
||||||
PROP_NETWORK_NUMBER_QUALITY,
|
PROP_NETWORK_NUMBER_QUALITY,
|
||||||
PROP_LINK_SPEED,
|
PROP_LINK_SPEED,
|
||||||
#endif
|
#endif
|
||||||
-1 };
|
-1
|
||||||
|
};
|
||||||
|
|
||||||
static const int Network_Port_Properties_Proprietary[] = { -1 };
|
static const int Network_Port_Properties_Proprietary[] = { -1 };
|
||||||
|
|
||||||
@@ -91,7 +95,8 @@ static const int Network_Port_Properties_Proprietary[] = { -1 };
|
|||||||
* @param pProprietary - pointer to list of int terminated by -1, of
|
* @param pProprietary - pointer to list of int terminated by -1, of
|
||||||
* BACnet proprietary properties for this object.
|
* BACnet proprietary properties for this object.
|
||||||
*/
|
*/
|
||||||
void Network_Port_Property_List(uint32_t object_instance,
|
void Network_Port_Property_List(
|
||||||
|
uint32_t object_instance,
|
||||||
const int **pRequired,
|
const int **pRequired,
|
||||||
const int **pOptional,
|
const int **pOptional,
|
||||||
const int **pProprietary)
|
const int **pProprietary)
|
||||||
@@ -438,8 +443,9 @@ bool Network_Port_Changes_Pending_Set(uint32_t instance, bool flag)
|
|||||||
index = Network_Port_Instance_To_Index(instance);
|
index = Network_Port_Instance_To_Index(instance);
|
||||||
if (index < BACNET_NETWORK_PORTS_MAX) {
|
if (index < BACNET_NETWORK_PORTS_MAX) {
|
||||||
Object_List[index].Changes_Pending = flag;
|
Object_List[index].Changes_Pending = flag;
|
||||||
} else
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -523,8 +529,8 @@ bool Network_Port_MSTP_Max_Info_Frames_Set(
|
|||||||
* @param object_property - object-property to be checked
|
* @param object_property - object-property to be checked
|
||||||
* @return true if the property is a member of this object instance
|
* @return true if the property is a member of this object instance
|
||||||
*/
|
*/
|
||||||
static bool Network_Port_Property_List_Member(
|
static bool
|
||||||
uint32_t object_instance, int object_property)
|
Network_Port_Property_List_Member(uint32_t object_instance, int object_property)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
const int *pRequired = NULL;
|
const int *pRequired = NULL;
|
||||||
@@ -640,9 +646,9 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
break;
|
break;
|
||||||
case PROP_LINK_SPEEDS:
|
case PROP_LINK_SPEEDS:
|
||||||
count = Network_Port_Link_Speeds_Count(rpdata->object_instance);
|
count = Network_Port_Link_Speeds_Count(rpdata->object_instance);
|
||||||
apdu_len = bacnet_array_encode(rpdata->object_instance,
|
apdu_len = bacnet_array_encode(
|
||||||
rpdata->array_index, Network_Port_Link_Speeds_Encode, count,
|
rpdata->object_instance, rpdata->array_index,
|
||||||
apdu, apdu_max);
|
Network_Port_Link_Speeds_Encode, count, apdu, apdu_max);
|
||||||
if (apdu_len == BACNET_STATUS_ABORT) {
|
if (apdu_len == BACNET_STATUS_ABORT) {
|
||||||
rpdata->error_code =
|
rpdata->error_code =
|
||||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
@@ -652,7 +658,8 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PROP_CHANGES_PENDING:
|
case PROP_CHANGES_PENDING:
|
||||||
apdu_len = encode_application_boolean(&apdu[0],
|
apdu_len = encode_application_boolean(
|
||||||
|
&apdu[0],
|
||||||
Network_Port_Changes_Pending(rpdata->object_instance));
|
Network_Port_Changes_Pending(rpdata->object_instance));
|
||||||
break;
|
break;
|
||||||
case PROP_APDU_LENGTH:
|
case PROP_APDU_LENGTH:
|
||||||
@@ -660,11 +667,13 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
&apdu[0], Network_Port_APDU_Length(rpdata->object_instance));
|
&apdu[0], Network_Port_APDU_Length(rpdata->object_instance));
|
||||||
break;
|
break;
|
||||||
case PROP_MAX_MASTER:
|
case PROP_MAX_MASTER:
|
||||||
apdu_len = encode_application_unsigned(&apdu[0],
|
apdu_len = encode_application_unsigned(
|
||||||
|
&apdu[0],
|
||||||
Network_Port_MSTP_Max_Master(rpdata->object_instance));
|
Network_Port_MSTP_Max_Master(rpdata->object_instance));
|
||||||
break;
|
break;
|
||||||
case PROP_MAX_INFO_FRAMES:
|
case PROP_MAX_INFO_FRAMES:
|
||||||
apdu_len = encode_application_unsigned(&apdu[0],
|
apdu_len = encode_application_unsigned(
|
||||||
|
&apdu[0],
|
||||||
Network_Port_MSTP_Max_Info_Frames(rpdata->object_instance));
|
Network_Port_MSTP_Max_Info_Frames(rpdata->object_instance));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -760,8 +769,8 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
|||||||
break;
|
break;
|
||||||
case PROP_MAC_ADDRESS:
|
case PROP_MAC_ADDRESS:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_OCTET_STRING) {
|
if (value.tag == BACNET_APPLICATION_TAG_OCTET_STRING) {
|
||||||
if (!Network_Port_MAC_Address_Set(wp_data->object_instance,
|
if (!Network_Port_MAC_Address_Set(
|
||||||
value.type.Octet_String.value,
|
wp_data->object_instance, value.type.Octet_String.value,
|
||||||
value.type.Octet_String.length)) {
|
value.type.Octet_String.length)) {
|
||||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief uBASIC-Plus program object for BACnet
|
||||||
|
* @author Steve Karg
|
||||||
|
* @date 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "bacnet/basic/object/program.h"
|
||||||
|
#include "bacnet/basic/program/ubasic/ubasic.h"
|
||||||
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
|
|
||||||
|
/* uBASIC-Plus program object */
|
||||||
|
static struct ubasic_data UBASIC_DATA = { 0 };
|
||||||
|
static struct mstimer UBASIC_Timer;
|
||||||
|
static uint32_t UBASIC_Instance = 0;
|
||||||
|
static const char *UBASIC_Program =
|
||||||
|
/* program listing with either \0, \n, or ';' at the end of each line.
|
||||||
|
note: indentation is not required */
|
||||||
|
"println 'Demo - BACnet & GPIO';"
|
||||||
|
"bac_create(0, 1, 'ADC-1');"
|
||||||
|
"bac_create(0, 2, 'ADC-2');"
|
||||||
|
"bac_create(4, 1, 'LED-1');"
|
||||||
|
"bac_create(4, 2, 'LED-2');"
|
||||||
|
":startover;"
|
||||||
|
" a = aread(1);"
|
||||||
|
" c = avgw(a, c, 10);"
|
||||||
|
" bac_write(0, 1, 85, c);"
|
||||||
|
" b = aread(2);"
|
||||||
|
" d = avgw(b, d, 10);"
|
||||||
|
" bac_write(0, 2, 85, d);"
|
||||||
|
" h = bac_read(4, 1, 85);"
|
||||||
|
" dwrite(1, (h % 2));"
|
||||||
|
" i = bac_read(4, 2, 85);"
|
||||||
|
" dwrite(2, (i % 2));"
|
||||||
|
" sleep (0.2);"
|
||||||
|
"goto startover;"
|
||||||
|
"end;";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load the program into the uBASIC interpreter
|
||||||
|
* @param context Pointer to the uBASIC data structure
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
static int Program_Load(void *context)
|
||||||
|
{
|
||||||
|
struct ubasic_data *data = (struct ubasic_data *)context;
|
||||||
|
|
||||||
|
ubasic_load_program(data, UBASIC_Program);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Run the program in the uBASIC interpreter
|
||||||
|
* @param context Pointer to the uBASIC data structure
|
||||||
|
* @return 0 while the programm is running, non-zero when finished
|
||||||
|
* or an error occurred
|
||||||
|
*/
|
||||||
|
static int Program_Run(void *context)
|
||||||
|
{
|
||||||
|
struct ubasic_data *data = (struct ubasic_data *)context;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
result = ubasic_run_program(data);
|
||||||
|
if (result <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Halt the program in the uBASIC interpreter
|
||||||
|
* @param context Pointer to the uBASIC data structure
|
||||||
|
* @return 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
|
static int Program_Halt(void *context)
|
||||||
|
{
|
||||||
|
struct ubasic_data *data = (struct ubasic_data *)context;
|
||||||
|
|
||||||
|
data->status.bit.isRunning = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Restart the program in the uBASIC interpreter
|
||||||
|
* @param context Pointer to the uBASIC data structure
|
||||||
|
* @return 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
|
static int Program_Restart(void *context)
|
||||||
|
{
|
||||||
|
struct ubasic_data *data = (struct ubasic_data *)context;
|
||||||
|
|
||||||
|
ubasic_clear_variables(data);
|
||||||
|
ubasic_load_program(data, UBASIC_Program);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unload the program in the uBASIC interpreter
|
||||||
|
* @param context Pointer to the uBASIC data structure
|
||||||
|
* @return 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
|
static int Program_Unload(void *context)
|
||||||
|
{
|
||||||
|
struct ubasic_data *data = (struct ubasic_data *)context;
|
||||||
|
|
||||||
|
ubasic_clear_variables(data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Timer task for the uBASIC program object
|
||||||
|
*/
|
||||||
|
void Program_UBASIC_Task(void)
|
||||||
|
{
|
||||||
|
if (mstimer_expired(&UBASIC_Timer)) {
|
||||||
|
mstimer_reset(&UBASIC_Timer);
|
||||||
|
Program_Timer(UBASIC_Instance, mstimer_interval(&UBASIC_Timer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the uBASIC program object
|
||||||
|
* @param instance Instance number of the program object
|
||||||
|
* @return 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
|
void Program_UBASIC_Init(uint32_t instance)
|
||||||
|
{
|
||||||
|
ubasic_port_init(&UBASIC_DATA);
|
||||||
|
UBASIC_Instance = Program_Create(instance);
|
||||||
|
Program_Context_Set(UBASIC_Instance, &UBASIC_DATA);
|
||||||
|
Program_Load_Set(UBASIC_Instance, Program_Load);
|
||||||
|
Program_Run_Set(UBASIC_Instance, Program_Run);
|
||||||
|
Program_Halt_Set(UBASIC_Instance, Program_Halt);
|
||||||
|
Program_Restart_Set(UBASIC_Instance, Program_Restart);
|
||||||
|
Program_Unload_Set(UBASIC_Instance, Program_Unload);
|
||||||
|
/* auto-run the program */
|
||||||
|
Program_Change_Set(UBASIC_Instance, PROGRAM_REQUEST_RUN);
|
||||||
|
/* start the cyclic 10ms run timer for the program object */
|
||||||
|
mstimer_set(&UBASIC_Timer, 10);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief uBASIC-Plus program object for BACnet
|
||||||
|
* @author Steve Karg
|
||||||
|
* @date 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#ifndef PROGRAM_UBASIC_H
|
||||||
|
#define PROGRAM_UBASIC_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
void Program_UBASIC_Task(void);
|
||||||
|
void Program_UBASIC_Init(uint32_t instance);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif
|
||||||
+27
-25
@@ -24,36 +24,36 @@
|
|||||||
#include "rs485.h"
|
#include "rs485.h"
|
||||||
|
|
||||||
#ifndef RS485_LINKSPRITE_ENABLED
|
#ifndef RS485_LINKSPRITE_ENABLED
|
||||||
#ifndef RS485_DFR0259_ENABLED
|
#ifndef RS485_DFR0259_ENABLED
|
||||||
#define RS485_DFR0259_ENABLED 1
|
#define RS485_DFR0259_ENABLED 1
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(RS485_DFR0259_ENABLED) || defined(RS485_LINKSPRITE_ENABLED)
|
#if defined(RS485_DFR0259_ENABLED) || defined(RS485_LINKSPRITE_ENABLED)
|
||||||
/* DFR0259 RS485 Shield - TXD=PG14, RXD=PG9, USART6 */
|
/* DFR0259 RS485 Shield - TXD=PG14, RXD=PG9, USART6 */
|
||||||
#define RS485_USARTx USART6
|
#define RS485_USARTx USART6
|
||||||
#define RS485_NVIC_IRQ USART6_IRQn
|
#define RS485_NVIC_IRQ USART6_IRQn
|
||||||
#define RS485_USARTx_ISR USART6_IRQHandler
|
#define RS485_USARTx_ISR USART6_IRQHandler
|
||||||
#define RS485_USARTx_RCC RCC_APB2Periph_USART6
|
#define RS485_USARTx_RCC RCC_APB2Periph_USART6
|
||||||
#define RS485_GPIO_RCC RCC_AHB1Periph_GPIOG
|
#define RS485_GPIO_RCC RCC_AHB1Periph_GPIOG
|
||||||
#define RS485_GPIO_PINS GPIO_Pin_9 | GPIO_Pin_14
|
#define RS485_GPIO_PINS GPIO_Pin_9 | GPIO_Pin_14
|
||||||
#define RS485_GPIO GPIOG
|
#define RS485_GPIO GPIOG
|
||||||
/* alternate function (AF) */
|
/* alternate function (AF) */
|
||||||
#define RS485_AF_PINSOURCE_RX GPIO_PinSource9
|
#define RS485_AF_PINSOURCE_RX GPIO_PinSource9
|
||||||
#define RS485_AF_PINSOURCE_TX GPIO_PinSource14
|
#define RS485_AF_PINSOURCE_TX GPIO_PinSource14
|
||||||
#define RS485_AF_FUNCTION GPIO_AF_USART6
|
#define RS485_AF_FUNCTION GPIO_AF_USART6
|
||||||
#endif
|
#endif
|
||||||
#if defined(RS485_DFR0259_ENABLED)
|
#if defined(RS485_DFR0259_ENABLED)
|
||||||
/* DFR0259 RS485 Shield - CE=PF15 */
|
/* DFR0259 RS485 Shield - CE=PF15 */
|
||||||
#define RS485_RTS_RCC RCC_AHB1Periph_GPIOF
|
#define RS485_RTS_RCC RCC_AHB1Periph_GPIOF
|
||||||
#define RS485_RTS_PIN GPIO_Pin_15
|
#define RS485_RTS_PIN GPIO_Pin_15
|
||||||
#define RS485_RTS_GPIO GPIOF
|
#define RS485_RTS_GPIO GPIOF
|
||||||
#endif
|
#endif
|
||||||
#if defined(RS485_LINKSPRITE_ENABLED)
|
#if defined(RS485_LINKSPRITE_ENABLED)
|
||||||
/* LINKSPRITE RS485 Shield - CE=PD15 */
|
/* LINKSPRITE RS485 Shield - CE=PD15 */
|
||||||
#define RS485_RTS_RCC RCC_AHB1Periph_GPIOD
|
#define RS485_RTS_RCC RCC_AHB1Periph_GPIOD
|
||||||
#define RS485_RTS_PIN GPIO_Pin_15
|
#define RS485_RTS_PIN GPIO_Pin_15
|
||||||
#define RS485_RTS_GPIO GPIOD
|
#define RS485_RTS_GPIO GPIOD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* buffer for storing received bytes - size must be power of two */
|
/* buffer for storing received bytes - size must be power of two */
|
||||||
@@ -305,9 +305,11 @@ void rs485_init(void)
|
|||||||
NVIC_InitTypeDef NVIC_InitStructure;
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
/* initialize the Rx and Tx byte queues */
|
/* initialize the Rx and Tx byte queues */
|
||||||
FIFO_Init(&Receive_Queue, &Receive_Queue_Data[0],
|
FIFO_Init(
|
||||||
|
&Receive_Queue, &Receive_Queue_Data[0],
|
||||||
(unsigned)sizeof(Receive_Queue_Data));
|
(unsigned)sizeof(Receive_Queue_Data));
|
||||||
FIFO_Init(&Transmit_Queue, &Transmit_Queue_Data[0],
|
FIFO_Init(
|
||||||
|
&Transmit_Queue, &Transmit_Queue_Data[0],
|
||||||
(unsigned)sizeof(Transmit_Queue_Data));
|
(unsigned)sizeof(Transmit_Queue_Data));
|
||||||
|
|
||||||
/* Enable GPIOx clock */
|
/* Enable GPIOx clock */
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file stm32f4xx_conf.h
|
* @file stm32f4xx_conf.h
|
||||||
* @author MCD Application Team
|
* @author MCD Application Team
|
||||||
* @version V1.0.0
|
* @version V1.0.0
|
||||||
* @date 19-September-2011
|
* @date 19-September-2011
|
||||||
* @brief Library configuration file.
|
* @brief Library configuration file.
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
*
|
*
|
||||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||||
#ifndef __STM32F4xx_CONF_H
|
#ifndef __STM32F4xx_CONF_H
|
||||||
@@ -25,53 +25,62 @@
|
|||||||
|
|
||||||
/* ########################## HSE/HSI Values adaptation ##################### */
|
/* ########################## HSE/HSI Values adaptation ##################### */
|
||||||
/**
|
/**
|
||||||
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
|
* @brief Adjust the value of External High Speed oscillator (HSE) used in your
|
||||||
* This value is used by the RCC HAL module to compute the system frequency
|
* application. This value is used by the RCC HAL module to compute the system
|
||||||
* (when HSE is used as system clock source, directly or through the PLL).
|
* frequency (when HSE is used as system clock source, directly or through the
|
||||||
*/
|
* PLL).
|
||||||
#if !defined (HSE_VALUE)
|
*/
|
||||||
#define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */
|
#if !defined(HSE_VALUE)
|
||||||
|
#define HSE_VALUE \
|
||||||
|
((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */
|
||||||
#endif /* HSE_VALUE */
|
#endif /* HSE_VALUE */
|
||||||
|
|
||||||
#if !defined (HSE_STARTUP_TIMEOUT)
|
#if !defined(HSE_STARTUP_TIMEOUT)
|
||||||
#define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */
|
#define HSE_STARTUP_TIMEOUT \
|
||||||
|
((uint32_t)100U) /*!< Time out for HSE start up, in ms */
|
||||||
#endif /* HSE_STARTUP_TIMEOUT */
|
#endif /* HSE_STARTUP_TIMEOUT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Internal High Speed oscillator (HSI) value.
|
* @brief Internal High Speed oscillator (HSI) value.
|
||||||
* This value is used by the RCC HAL module to compute the system frequency
|
* This value is used by the RCC HAL module to compute the system
|
||||||
* (when HSI is used as system clock source, directly or through the PLL).
|
* frequency (when HSI is used as system clock source, directly or through the
|
||||||
*/
|
* PLL).
|
||||||
#if !defined (HSI_VALUE)
|
*/
|
||||||
#define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
|
#if !defined(HSI_VALUE)
|
||||||
|
#define HSI_VALUE \
|
||||||
|
((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
|
||||||
#endif /* HSI_VALUE */
|
#endif /* HSI_VALUE */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Internal Low Speed oscillator (LSI) value.
|
* @brief Internal Low Speed oscillator (LSI) value.
|
||||||
*/
|
*/
|
||||||
#if !defined (LSI_VALUE)
|
#if !defined(LSI_VALUE)
|
||||||
#define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/
|
#define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/
|
||||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz \
|
||||||
The real value may vary depending on the variations
|
The real value may vary depending on the variations \
|
||||||
in voltage and temperature.*/
|
in voltage and temperature.*/
|
||||||
/**
|
/**
|
||||||
* @brief External Low Speed oscillator (LSE) value.
|
* @brief External Low Speed oscillator (LSE) value.
|
||||||
*/
|
*/
|
||||||
#if !defined (LSE_VALUE)
|
#if !defined(LSE_VALUE)
|
||||||
#define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz */
|
#define LSE_VALUE \
|
||||||
|
((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz \
|
||||||
|
*/
|
||||||
#endif /* LSE_VALUE */
|
#endif /* LSE_VALUE */
|
||||||
|
|
||||||
#if !defined (LSE_STARTUP_TIMEOUT)
|
#if !defined(LSE_STARTUP_TIMEOUT)
|
||||||
#define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */
|
#define LSE_STARTUP_TIMEOUT \
|
||||||
|
((uint32_t)5000U) /*!< Time out for LSE start up, in ms */
|
||||||
#endif /* LSE_STARTUP_TIMEOUT */
|
#endif /* LSE_STARTUP_TIMEOUT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief External clock source for I2S peripheral
|
* @brief External clock source for I2S peripheral
|
||||||
* This value is used by the I2S HAL module to compute the I2S clock source
|
* This value is used by the I2S HAL module to compute the I2S clock
|
||||||
* frequency, this source is inserted directly through I2S_CKIN pad.
|
* source frequency, this source is inserted directly through I2S_CKIN pad.
|
||||||
*/
|
*/
|
||||||
#if !defined (EXTERNAL_CLOCK_VALUE)
|
#if !defined(EXTERNAL_CLOCK_VALUE)
|
||||||
#define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/
|
#define EXTERNAL_CLOCK_VALUE \
|
||||||
|
((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/
|
||||||
#endif /* EXTERNAL_CLOCK_VALUE */
|
#endif /* EXTERNAL_CLOCK_VALUE */
|
||||||
|
|
||||||
/* Tip: To avoid modifying this file each time you need to use different HSE,
|
/* Tip: To avoid modifying this file each time you need to use different HSE,
|
||||||
@@ -79,14 +88,14 @@
|
|||||||
|
|
||||||
/* ########################### System Configuration ######################### */
|
/* ########################### System Configuration ######################### */
|
||||||
/**
|
/**
|
||||||
* @brief This is the HAL system configuration section
|
* @brief This is the HAL system configuration section
|
||||||
*/
|
*/
|
||||||
#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */
|
#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */
|
||||||
#define TICK_INT_PRIORITY ((uint32_t)0U) /*!< tick interrupt priority */
|
#define TICK_INT_PRIORITY ((uint32_t)0U) /*!< tick interrupt priority */
|
||||||
#define USE_RTOS 0U
|
#define USE_RTOS 0U
|
||||||
#define PREFETCH_ENABLE 1U
|
#define PREFETCH_ENABLE 1U
|
||||||
#define INSTRUCTION_CACHE_ENABLE 1U
|
#define INSTRUCTION_CACHE_ENABLE 1U
|
||||||
#define DATA_CACHE_ENABLE 1U
|
#define DATA_CACHE_ENABLE 1U
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
|
||||||
@@ -123,29 +132,30 @@
|
|||||||
/* If an external clock source is used, then the value of the following define
|
/* If an external clock source is used, then the value of the following define
|
||||||
should be set to the value of the external clock source, else, if no external
|
should be set to the value of the external clock source, else, if no external
|
||||||
clock is used, keep this define commented */
|
clock is used, keep this define commented */
|
||||||
/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
|
/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in
|
||||||
|
Hz */
|
||||||
|
|
||||||
/* Uncomment the line below to expanse the "assert_param" macro in the
|
/* Uncomment the line below to expanse the "assert_param" macro in the
|
||||||
Standard Peripheral Library drivers code */
|
Standard Peripheral Library drivers code */
|
||||||
/* #define USE_FULL_ASSERT 1 */
|
/* #define USE_FULL_ASSERT 1 */
|
||||||
|
|
||||||
/* Exported macro ------------------------------------------------------------*/
|
/* Exported macro ------------------------------------------------------------*/
|
||||||
#ifdef USE_FULL_ASSERT
|
#ifdef USE_FULL_ASSERT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The assert_param macro is used for function's parameters check.
|
* @brief The assert_param macro is used for function's parameters check.
|
||||||
* @param expr: If expr is false, it calls assert_failed function
|
* @param expr: If expr is false, it calls assert_failed function
|
||||||
* which reports the name of the source file and the source
|
* which reports the name of the source file and the source
|
||||||
* line number of the call that failed.
|
* line number of the call that failed.
|
||||||
* If expr is true, it returns no value.
|
* If expr is true, it returns no value.
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
|
#define assert_param(expr) \
|
||||||
|
((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
|
||||||
/* Exported functions ------------------------------------------------------- */
|
/* Exported functions ------------------------------------------------------- */
|
||||||
void assert_failed(uint8_t* file, uint32_t line);
|
void assert_failed(uint8_t *file, uint32_t line);
|
||||||
#else
|
#else
|
||||||
#define assert_param(expr) ((void)0)
|
#define assert_param(expr) ((void)0)
|
||||||
#endif /* USE_FULL_ASSERT */
|
#endif /* USE_FULL_ASSERT */
|
||||||
|
|
||||||
#endif /* __STM32F4xx_CONF_H */
|
#endif /* __STM32F4xx_CONF_H */
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file IO_Toggle/stm32f4xx_it.c
|
* @file IO_Toggle/stm32f4xx_it.c
|
||||||
* @author MCD Application Team
|
* @author MCD Application Team
|
||||||
* @version V1.0.0
|
* @version V1.0.0
|
||||||
* @date 19-September-2011
|
* @date 19-September-2011
|
||||||
* @brief Main Interrupt Service Routines.
|
* @brief Main Interrupt Service Routines.
|
||||||
* This file provides template for all exceptions handler and
|
* This file provides template for all exceptions handler and
|
||||||
* peripherals interrupt service routine.
|
* peripherals interrupt service routine.
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
*
|
*
|
||||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
#include "stm32f4xx_it.h"
|
#include "stm32f4xx_it.h"
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
|
|
||||||
/** @addtogroup STM32F4_Discovery_Peripheral_Examples
|
/** @addtogroup STM32F4_Discovery_Peripheral_Examples
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup IO_Toggle
|
/** @addtogroup IO_Toggle
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
/* Private define ------------------------------------------------------------*/
|
/* Private define ------------------------------------------------------------*/
|
||||||
@@ -45,89 +45,81 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles NMI exception.
|
* @brief This function handles NMI exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void NMI_Handler(void)
|
void NMI_Handler(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles Hard Fault exception.
|
* @brief This function handles Hard Fault exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void HardFault_Handler(void)
|
void HardFault_Handler(void)
|
||||||
{
|
{
|
||||||
/* Go to infinite loop when Hard Fault exception occurs */
|
/* Go to infinite loop when Hard Fault exception occurs */
|
||||||
while (1)
|
while (1) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles Memory Manage exception.
|
* @brief This function handles Memory Manage exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void MemManage_Handler(void)
|
void MemManage_Handler(void)
|
||||||
{
|
{
|
||||||
/* Go to infinite loop when Memory Manage exception occurs */
|
/* Go to infinite loop when Memory Manage exception occurs */
|
||||||
while (1)
|
while (1) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles Bus Fault exception.
|
* @brief This function handles Bus Fault exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void BusFault_Handler(void)
|
void BusFault_Handler(void)
|
||||||
{
|
{
|
||||||
/* Go to infinite loop when Bus Fault exception occurs */
|
/* Go to infinite loop when Bus Fault exception occurs */
|
||||||
while (1)
|
while (1) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles Usage Fault exception.
|
* @brief This function handles Usage Fault exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void UsageFault_Handler(void)
|
void UsageFault_Handler(void)
|
||||||
{
|
{
|
||||||
/* Go to infinite loop when Usage Fault exception occurs */
|
/* Go to infinite loop when Usage Fault exception occurs */
|
||||||
while (1)
|
while (1) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles SVCall exception.
|
* @brief This function handles SVCall exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void SVC_Handler(void)
|
void SVC_Handler(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles Debug Monitor exception.
|
* @brief This function handles Debug Monitor exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void DebugMon_Handler(void)
|
void DebugMon_Handler(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles PendSVC exception.
|
* @brief This function handles PendSVC exception.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void PendSV_Handler(void)
|
void PendSV_Handler(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -140,17 +132,16 @@ void PendSV_Handler(void)
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles PPP interrupt request.
|
* @brief This function handles PPP interrupt request.
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
/*void PPP_IRQHandler(void)
|
/*void PPP_IRQHandler(void)
|
||||||
{
|
{
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file GPIO/IOToggle/stm32f4xx_it.h
|
* @file GPIO/IOToggle/stm32f4xx_it.h
|
||||||
* @author MCD Application Team
|
* @author MCD Application Team
|
||||||
* @version V1.0.0
|
* @version V1.0.0
|
||||||
* @date 19-September-2011
|
* @date 19-September-2011
|
||||||
* @brief This file contains the headers of the interrupt handlers.
|
* @brief This file contains the headers of the interrupt handlers.
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
*
|
*
|
||||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||||
#ifndef __STM32F4xx_IT_H
|
#ifndef __STM32F4xx_IT_H
|
||||||
#define __STM32F4xx_IT_H
|
#define __STM32F4xx_IT_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
|||||||
+632
-612
File diff suppressed because it is too large
Load Diff
@@ -1,89 +1,87 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file system_stm32f4xx.h
|
* @file system_stm32f4xx.h
|
||||||
* @author MCD Application Team
|
* @author MCD Application Team
|
||||||
* @version V1.0.0
|
* @version V1.0.0
|
||||||
* @date 30-September-2011
|
* @date 30-September-2011
|
||||||
* @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices.
|
* @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices.
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
*
|
*
|
||||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup CMSIS
|
/** @addtogroup CMSIS
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup stm32f4xx_system
|
/** @addtogroup stm32f4xx_system
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Define to prevent recursive inclusion
|
* @brief Define to prevent recursive inclusion
|
||||||
*/
|
*/
|
||||||
#ifndef __SYSTEM_STM32F4XX_H
|
#ifndef __SYSTEM_STM32F4XX_H
|
||||||
#define __SYSTEM_STM32F4XX_H
|
#define __SYSTEM_STM32F4XX_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Includes
|
/** @addtogroup STM32F4xx_System_Includes
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_types
|
/** @addtogroup STM32F4xx_System_Exported_types
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
|
||||||
|
|
||||||
|
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_Constants
|
/** @addtogroup STM32F4xx_System_Exported_Constants
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_Macros
|
/** @addtogroup STM32F4xx_System_Exported_Macros
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_Functions
|
/** @addtogroup STM32F4xx_System_Exported_Functions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern void SystemInit(void);
|
extern void SystemInit(void);
|
||||||
extern void SystemCoreClockUpdate(void);
|
extern void SystemCoreClockUpdate(void);
|
||||||
extern void System_LSE_Init(void);
|
extern void System_LSE_Init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@@ -92,10 +90,10 @@ extern void System_LSE_Init(void);
|
|||||||
#endif /*__SYSTEM_STM32F4XX_H */
|
#endif /*__SYSTEM_STM32F4XX_H */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||||
|
|||||||
@@ -0,0 +1,644 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Example uBASIC-Plus porting layer for the uBASIC-Plus interpreter
|
||||||
|
* for STM32F4xx NUCLIO board
|
||||||
|
* @author Steve Karg
|
||||||
|
* @date 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "bacnet/basic/object/ai.h"
|
||||||
|
#include "bacnet/basic/object/ao.h"
|
||||||
|
#include "bacnet/basic/object/av.h"
|
||||||
|
#include "bacnet/basic/object/bi.h"
|
||||||
|
#include "bacnet/basic/object/bo.h"
|
||||||
|
#include "bacnet/basic/object/bv.h"
|
||||||
|
#include "bacnet/basic/object/device.h"
|
||||||
|
#include "bacnet/basic/object/ms-input.h"
|
||||||
|
#include "bacnet/basic/object/mso.h"
|
||||||
|
#include "bacnet/basic/object/msv.h"
|
||||||
|
#include "bacnet/basic/program/ubasic/ubasic.h"
|
||||||
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
|
#include "bacnet/wp.h"
|
||||||
|
#include "led.h"
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_PRINT_TO_SERIAL)
|
||||||
|
/**
|
||||||
|
* @brief Write a buffer to the serial port
|
||||||
|
* @param msg Pointer to the buffer to write
|
||||||
|
* @param n Number of bytes to write
|
||||||
|
*/
|
||||||
|
static void serial_write(const char *msg, uint16_t n)
|
||||||
|
{
|
||||||
|
(void)msg;
|
||||||
|
(void)n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gather key presses until new-line is recieved or buffer is full
|
||||||
|
* @return return the next byte from the input stream, or EOF(-1) if no byte is
|
||||||
|
* available
|
||||||
|
*/
|
||||||
|
static int serial_getc(void)
|
||||||
|
{
|
||||||
|
int ch = -1;
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_HARDWARE_EVENTS)
|
||||||
|
static uint32_t Event_Mask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hardware event status bit
|
||||||
|
* @param bit Event bit
|
||||||
|
* @return 1 if the event is set, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int8_t hw_event(uint8_t bit)
|
||||||
|
{
|
||||||
|
if (bit < 32) {
|
||||||
|
if (Event_Mask & (1UL << bit)) {
|
||||||
|
return 1; // Event is set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Event is not set
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear a hardware event state bit
|
||||||
|
* @param bit Event bit
|
||||||
|
*/
|
||||||
|
static void hw_event_clear(uint8_t bit)
|
||||||
|
{
|
||||||
|
if (bit < 32) {
|
||||||
|
Event_Mask &= ~(1UL << bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_STORE_VARS_IN_FLASH)
|
||||||
|
static uint8_t EEPROM_Buffer[256];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read some data from the EEPROM
|
||||||
|
* @param start_address EEPROM starting memory address
|
||||||
|
* @param buffer data to store
|
||||||
|
* @param length number of bytes of data to read
|
||||||
|
*/
|
||||||
|
static size_t
|
||||||
|
eepromRead(uint16_t start_address, uint8_t *buffer, uint16_t length)
|
||||||
|
{
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
uint16_t i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
if (start_address + i < sizeof(EEPROM_Buffer)) {
|
||||||
|
buffer[i] = EEPROM_Buffer[start_address + i];
|
||||||
|
bytes_read++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write some data to the EEPROM
|
||||||
|
* @param start_address EEPROM starting memory address
|
||||||
|
* @param buffer data to send
|
||||||
|
* @param length number of bytes of data
|
||||||
|
*/
|
||||||
|
static size_t
|
||||||
|
eepromWrite(uint16_t start_address, uint8_t *buffer, uint16_t length)
|
||||||
|
{
|
||||||
|
size_t bytes_written = 0;
|
||||||
|
uint16_t i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
if (start_address + i < sizeof(EEPROM_Buffer)) {
|
||||||
|
EEPROM_Buffer[start_address + i] = buffer[i];
|
||||||
|
bytes_written++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UBASIC_FLASH_PAGE_SIZE 256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a variable to the EEPROM
|
||||||
|
* @param Name Variable name
|
||||||
|
* @param Vartype Variable type
|
||||||
|
* @param datalen_bytes Data length in bytes
|
||||||
|
* @param dataptr Pointer to the data
|
||||||
|
*/
|
||||||
|
static void variable_write(
|
||||||
|
uint8_t Name, uint8_t vartype, uint8_t datalen_bytes, uint8_t *dataptr)
|
||||||
|
{
|
||||||
|
// Calculate the starting address based on variable name
|
||||||
|
uint16_t start_address = Name * UBASIC_FLASH_PAGE_SIZE;
|
||||||
|
uint8_t buffer[UBASIC_FLASH_PAGE_SIZE];
|
||||||
|
|
||||||
|
// Prepare the buffer with the variable type and data length
|
||||||
|
buffer[0] = vartype; // First byte is the variable type
|
||||||
|
buffer[1] = datalen_bytes; // Second byte is the data length
|
||||||
|
for (uint8_t i = 0; i < datalen_bytes; i++) {
|
||||||
|
buffer[i + 2] = dataptr[i]; // Copy the actual data into the buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the buffer to EEPROM
|
||||||
|
eepromWrite(start_address, buffer, datalen_bytes + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a variable from the EEPROM
|
||||||
|
* @param Name Variable name
|
||||||
|
* @param Vartype Variable type
|
||||||
|
* @param dataptr Pointer to store the data
|
||||||
|
* @param datalen Pointer to store the data length
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
variable_read(uint8_t Name, uint8_t vartype, uint8_t *dataptr, uint8_t *datalen)
|
||||||
|
{
|
||||||
|
// Calculate the starting address based on variable name
|
||||||
|
uint8_t buffer[UBASIC_FLASH_PAGE_SIZE] = { 0 };
|
||||||
|
uint16_t start_address = Name * UBASIC_FLASH_PAGE_SIZE;
|
||||||
|
|
||||||
|
// Read the data from EEPROM
|
||||||
|
eepromRead(start_address, buffer, UBASIC_FLASH_PAGE_SIZE);
|
||||||
|
// Check if the variable type matches
|
||||||
|
if (buffer[0] == vartype) {
|
||||||
|
*datalen = buffer[1]; // Get the data length
|
||||||
|
for (uint8_t i = 0; i < *datalen; i++) {
|
||||||
|
dataptr[i] =
|
||||||
|
buffer[i + 2]; // Copy the actual data into the provided pointer
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*datalen = 0; // If type does not match, set length to 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( \
|
||||||
|
defined(UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS) || \
|
||||||
|
defined(UBASIC_SCRIPT_HAVE_SLEEP) || \
|
||||||
|
defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL))
|
||||||
|
/* defined in mstimer.h */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR)
|
||||||
|
/**
|
||||||
|
* @brief Generate a random number
|
||||||
|
* @param size Size of the random number in bits
|
||||||
|
* @return Random number size-bits wide
|
||||||
|
*/
|
||||||
|
static uint32_t random_uint32(uint8_t size)
|
||||||
|
{
|
||||||
|
uint32_t value = 0, grains = 0;
|
||||||
|
uint8_t k, i;
|
||||||
|
static bool initialized = false;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
srand(0);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
for (k = 0; k < 4; k++) {
|
||||||
|
grains = 0;
|
||||||
|
for (i = 0; i < (size >> 1); i++) {
|
||||||
|
/* Two LS bits are most likely most random */
|
||||||
|
grains |= (rand() & 0x00000003) << (2 * i);
|
||||||
|
}
|
||||||
|
value ^= grains;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_PWM_CHANNELS)
|
||||||
|
static int32_t dutycycle_pwm_ch[UBASIC_SCRIPT_HAVE_PWM_CHANNELS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure the PWM
|
||||||
|
* @param psc Prescaler
|
||||||
|
* @param per Period
|
||||||
|
*/
|
||||||
|
static void pwm_config(uint16_t psc, uint16_t per)
|
||||||
|
{
|
||||||
|
(void)psc;
|
||||||
|
(void)per;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a value to the PWM
|
||||||
|
* @param ch Channel
|
||||||
|
* @param dutycycle Duty cycle
|
||||||
|
*/
|
||||||
|
static void pwm_write(uint8_t ch, int32_t dutycycle)
|
||||||
|
{
|
||||||
|
if (ch < UBASIC_SCRIPT_HAVE_PWM_CHANNELS) {
|
||||||
|
dutycycle_pwm_ch[ch] = dutycycle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a value from the PWM
|
||||||
|
* @param ch Channel
|
||||||
|
* @return Duty cycle
|
||||||
|
*/
|
||||||
|
static int32_t pwm_read(uint8_t ch)
|
||||||
|
{
|
||||||
|
if (ch < UBASIC_SCRIPT_HAVE_PWM_CHANNELS) {
|
||||||
|
return dutycycle_pwm_ch[ch];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_ANALOG_READ)
|
||||||
|
/**
|
||||||
|
* @brief Configure the ADC
|
||||||
|
* @param sampletime Sample time
|
||||||
|
* @param nreads Number of reads
|
||||||
|
*/
|
||||||
|
static void adc_config(uint8_t sampletime, uint8_t nreads)
|
||||||
|
{
|
||||||
|
(void)sampletime;
|
||||||
|
(void)nreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a value from the ADC
|
||||||
|
* @param channel Channel
|
||||||
|
* @return ADC value
|
||||||
|
*/
|
||||||
|
static int32_t adc_read(uint8_t channel)
|
||||||
|
{
|
||||||
|
return (int32_t)random_uint32(12);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_GPIO_CHANNELS)
|
||||||
|
/**
|
||||||
|
* @brief Configure the GPIO
|
||||||
|
* @param ch Channel
|
||||||
|
* @param mode Mode
|
||||||
|
* @param freq Frequency
|
||||||
|
*/
|
||||||
|
static void gpio_config(uint8_t ch, int8_t mode, uint8_t freq)
|
||||||
|
{
|
||||||
|
(void)ch;
|
||||||
|
(void)mode;
|
||||||
|
(void)freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a value to the GPIO
|
||||||
|
* @param ch Channel
|
||||||
|
* @param pin_state Pin state
|
||||||
|
*/
|
||||||
|
static void gpio_write(uint8_t ch, uint8_t pin_state)
|
||||||
|
{
|
||||||
|
switch (ch) {
|
||||||
|
case 1:
|
||||||
|
if (pin_state) {
|
||||||
|
led_on(LED_LD1);
|
||||||
|
} else {
|
||||||
|
led_off(LED_LD1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (pin_state) {
|
||||||
|
led_on(LED_LD2);
|
||||||
|
} else {
|
||||||
|
led_off(LED_LD2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a value from the GPIO
|
||||||
|
* @param ch Channel
|
||||||
|
* @return GPIO value
|
||||||
|
*/
|
||||||
|
static int32_t gpio_read(uint8_t ch)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_BACNET)
|
||||||
|
/**
|
||||||
|
* @brief Create a BACnet object
|
||||||
|
* @param object_type Object type
|
||||||
|
* @param instance Object instance
|
||||||
|
* @param object_name Object name
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
bacnet_create_object(uint16_t object_type, uint32_t instance, char *object_name)
|
||||||
|
{
|
||||||
|
uint32_t r;
|
||||||
|
|
||||||
|
switch (object_type) {
|
||||||
|
case OBJECT_ANALOG_INPUT:
|
||||||
|
if (!Analog_Input_Valid_Instance(instance)) {
|
||||||
|
r = Analog_Input_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Analog_Input_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_ANALOG_OUTPUT:
|
||||||
|
if (!Analog_Output_Valid_Instance(instance)) {
|
||||||
|
r = Analog_Output_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Analog_Output_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_ANALOG_VALUE:
|
||||||
|
if (!Analog_Value_Valid_Instance(instance)) {
|
||||||
|
r = Analog_Value_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Analog_Value_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_INPUT:
|
||||||
|
if (!Binary_Input_Valid_Instance(instance)) {
|
||||||
|
r = Binary_Input_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Binary_Input_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_OUTPUT:
|
||||||
|
if (!Binary_Output_Valid_Instance(instance)) {
|
||||||
|
r = Binary_Output_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Binary_Output_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_VALUE:
|
||||||
|
if (!Binary_Value_Valid_Instance(instance)) {
|
||||||
|
r = Binary_Value_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Binary_Value_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_INPUT:
|
||||||
|
if (!Multistate_Input_Valid_Instance(instance)) {
|
||||||
|
r = Multistate_Input_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Multistate_Input_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_OUTPUT:
|
||||||
|
if (!Multistate_Output_Valid_Instance(instance)) {
|
||||||
|
r = Multistate_Output_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Multistate_Output_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_VALUE:
|
||||||
|
if (!Multistate_Value_Valid_Instance(instance)) {
|
||||||
|
r = Multistate_Value_Create(instance);
|
||||||
|
if (r == instance) {
|
||||||
|
Multistate_Value_Name_Set(instance, strdup(object_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a property to a BACnet object
|
||||||
|
* @param object_type Object type
|
||||||
|
* @param instance Object instance
|
||||||
|
* @param property_id Property ID
|
||||||
|
* @param value Property value
|
||||||
|
*/
|
||||||
|
static void bacnet_write_property(
|
||||||
|
uint16_t object_type,
|
||||||
|
uint32_t instance,
|
||||||
|
uint32_t property_id,
|
||||||
|
VARIABLE_TYPE value)
|
||||||
|
{
|
||||||
|
BACNET_BINARY_PV value_binary = BINARY_INACTIVE;
|
||||||
|
|
||||||
|
switch (object_type) {
|
||||||
|
case OBJECT_ANALOG_INPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
Analog_Input_Present_Value_Set(
|
||||||
|
instance, fixedpt_tofloat(value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_ANALOG_OUTPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
Analog_Output_Present_Value_Set(
|
||||||
|
instance, fixedpt_tofloat(value), BACNET_MAX_PRIORITY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_ANALOG_VALUE:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
Analog_Value_Present_Value_Set(
|
||||||
|
instance, fixedpt_tofloat(value), BACNET_MAX_PRIORITY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_INPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
if (fixedpt_toint(value) != 0) {
|
||||||
|
value_binary = BINARY_ACTIVE;
|
||||||
|
}
|
||||||
|
Binary_Input_Present_Value_Set(instance, value_binary);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_OUTPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
if (fixedpt_toint(value) != 0) {
|
||||||
|
value_binary = BINARY_ACTIVE;
|
||||||
|
}
|
||||||
|
Binary_Output_Present_Value_Set(
|
||||||
|
instance, value_binary, BACNET_MAX_PRIORITY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_VALUE:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
if (fixedpt_toint(value) != 0) {
|
||||||
|
value_binary = BINARY_ACTIVE;
|
||||||
|
}
|
||||||
|
Binary_Value_Present_Value_Set(instance, value_binary);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_INPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
Multistate_Input_Present_Value_Set(
|
||||||
|
instance, fixedpt_toint(value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_OUTPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
Multistate_Output_Present_Value_Set(
|
||||||
|
instance, fixedpt_toint(value), BACNET_MAX_PRIORITY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_VALUE:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
Multistate_Value_Present_Value_Set(
|
||||||
|
instance, fixedpt_toint(value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a property from a BACnet object
|
||||||
|
* @param object_type Object type
|
||||||
|
* @param instance Object instance
|
||||||
|
* @param property_id Property ID
|
||||||
|
* @return Property value
|
||||||
|
*/
|
||||||
|
static VARIABLE_TYPE bacnet_read_property(
|
||||||
|
uint16_t object_type, uint32_t instance, uint32_t property_id)
|
||||||
|
{
|
||||||
|
VARIABLE_TYPE value = 0;
|
||||||
|
float value_float = 0.0;
|
||||||
|
BACNET_BINARY_PV value_binary = BINARY_INACTIVE;
|
||||||
|
|
||||||
|
switch (object_type) {
|
||||||
|
case OBJECT_ANALOG_INPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value_float = Analog_Input_Present_Value(instance);
|
||||||
|
value = fixedpt_fromfloat(value_float);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_ANALOG_OUTPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value_float = Analog_Output_Present_Value(instance);
|
||||||
|
value = fixedpt_fromfloat(value_float);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_ANALOG_VALUE:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value_float = Analog_Value_Present_Value(instance);
|
||||||
|
value = fixedpt_fromfloat(value_float);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_INPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value_binary = Binary_Input_Present_Value(instance);
|
||||||
|
value =
|
||||||
|
fixedpt_fromint((value_binary == BINARY_ACTIVE) ? 1 : 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_OUTPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value_binary = Binary_Output_Present_Value(instance);
|
||||||
|
value =
|
||||||
|
fixedpt_fromint((value_binary == BINARY_ACTIVE) ? 1 : 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_BINARY_VALUE:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value_binary = Binary_Value_Present_Value(instance);
|
||||||
|
value =
|
||||||
|
fixedpt_fromint((value_binary == BINARY_ACTIVE) ? 1 : 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_INPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value =
|
||||||
|
fixedpt_fromint(Multistate_Input_Present_Value(instance));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_OUTPUT:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value =
|
||||||
|
fixedpt_fromint(Multistate_Output_Present_Value(instance));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJECT_MULTI_STATE_VALUE:
|
||||||
|
if (property_id == PROP_PRESENT_VALUE) {
|
||||||
|
value =
|
||||||
|
fixedpt_fromint(Multistate_Value_Present_Value(instance));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the hardware drivers
|
||||||
|
* @param data Pointer to the ubasic data structure
|
||||||
|
*/
|
||||||
|
void ubasic_port_init(struct ubasic_data *data)
|
||||||
|
{
|
||||||
|
#if ( \
|
||||||
|
defined(UBASIC_SCRIPT_HAVE_TICTOC_CHANNELS) || \
|
||||||
|
defined(UBASIC_SCRIPT_HAVE_SLEEP) || \
|
||||||
|
defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL))
|
||||||
|
data->mstimer_now = mstimer_now;
|
||||||
|
#endif
|
||||||
|
data->variable_write = variable_write;
|
||||||
|
data->variable_read = variable_read;
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_HARDWARE_EVENTS)
|
||||||
|
data->hw_event = hw_event;
|
||||||
|
data->hw_event_clear = hw_event_clear;
|
||||||
|
#endif
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_PWM_CHANNELS)
|
||||||
|
data->pwm_config = pwm_config;
|
||||||
|
data->pwm_write = pwm_write;
|
||||||
|
data->pwm_read = pwm_read;
|
||||||
|
#endif
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_PWM_CHANNELS)
|
||||||
|
data->adc_config = adc_config;
|
||||||
|
data->adc_read = adc_read;
|
||||||
|
#endif
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_GPIO_CHANNELS)
|
||||||
|
data->gpio_config = gpio_config;
|
||||||
|
data->gpio_write = gpio_write;
|
||||||
|
data->gpio_read = gpio_read;
|
||||||
|
#endif
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_RANDOM_NUMBER_GENERATOR)
|
||||||
|
data->random_uint32 = random_uint32;
|
||||||
|
#endif
|
||||||
|
#if defined(UBASIC_SCRIPT_PRINT_TO_SERIAL)
|
||||||
|
data->serial_write = serial_write;
|
||||||
|
#endif
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_INPUT_FROM_SERIAL)
|
||||||
|
data->ubasic_getc = serial_getc;
|
||||||
|
#endif
|
||||||
|
#if defined(UBASIC_SCRIPT_HAVE_BACNET)
|
||||||
|
data->bacnet_create_object = bacnet_create_object;
|
||||||
|
data->bacnet_write_property = bacnet_write_property;
|
||||||
|
data->bacnet_read_property = bacnet_read_property;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ struct object_data {
|
|||||||
bool Changed : 1;
|
bool Changed : 1;
|
||||||
void *Context;
|
void *Context;
|
||||||
/* return 0 for success, negative on error */
|
/* return 0 for success, negative on error */
|
||||||
int (*Load)(void *context, const char *location);
|
int (*Load)(void *context);
|
||||||
int (*Run)(void *context);
|
int (*Run)(void *context);
|
||||||
int (*Halt)(void *context);
|
int (*Halt)(void *context);
|
||||||
int (*Restart)(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
|
* @brief Set the Load function for the object
|
||||||
* @param object_instance [in] BACnet object instance number
|
* @param object_instance [in] BACnet object instance number
|
||||||
* @param load [in] pointer to the Load function
|
* @param load [in] pointer to the Load function
|
||||||
|
* @note function should return 0 for success, negative on error
|
||||||
*/
|
*/
|
||||||
void Program_Load_Set(
|
void Program_Load_Set(uint32_t object_instance, int (*load)(void *context))
|
||||||
uint32_t object_instance, int (*load)(void *context, const char *location))
|
|
||||||
{
|
{
|
||||||
struct object_data *pObject = Object_Data(object_instance);
|
struct object_data *pObject = Object_Data(object_instance);
|
||||||
|
|
||||||
@@ -975,6 +975,7 @@ void Program_Load_Set(
|
|||||||
* @brief Set the Run function for the object
|
* @brief Set the Run function for the object
|
||||||
* @param object_instance [in] BACnet object instance number
|
* @param object_instance [in] BACnet object instance number
|
||||||
* @param run [in] pointer to the Run function
|
* @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))
|
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
|
* @brief Set the Halt function for the object
|
||||||
* @param object_instance [in] BACnet object instance number
|
* @param object_instance [in] BACnet object instance number
|
||||||
* @param halt [in] pointer to the Halt function
|
* @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))
|
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
|
* @brief Set the Restart function for the object
|
||||||
* @param object_instance [in] BACnet object instance number
|
* @param object_instance [in] BACnet object instance number
|
||||||
* @param restart [in] pointer to the Restart function
|
* @param restart [in] pointer to the Restart function
|
||||||
|
* @note function should return 0 for success, negative on error
|
||||||
*/
|
*/
|
||||||
void Program_Restart_Set(
|
void Program_Restart_Set(
|
||||||
uint32_t object_instance, int (*restart)(void *context))
|
uint32_t object_instance, int (*restart)(void *context))
|
||||||
@@ -1018,6 +1021,7 @@ void Program_Restart_Set(
|
|||||||
* @brief Set the Unload function for the object
|
* @brief Set the Unload function for the object
|
||||||
* @param object_instance [in] BACnet object instance number
|
* @param object_instance [in] BACnet object instance number
|
||||||
* @param unload [in] pointer to the Unload function
|
* @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))
|
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)
|
static void Program_State_Idle_Handler(struct object_data *pObject)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
||||||
if (pObject->Load) {
|
if (pObject->Load) {
|
||||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
err = pObject->Load(pObject->Context);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
pObject->Program_State = PROGRAM_STATE_LOADING;
|
pObject->Program_State = PROGRAM_STATE_LOADING;
|
||||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
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) {
|
} else if (pObject->Program_Change == PROGRAM_REQUEST_RUN) {
|
||||||
if (pObject->Load) {
|
if (pObject->Load) {
|
||||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
err = pObject->Load(pObject->Context);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
pObject->Program_State = PROGRAM_STATE_RUNNING;
|
pObject->Program_State = PROGRAM_STATE_RUNNING;
|
||||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
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)
|
static void Program_State_Halted_Handler(struct object_data *pObject)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@@ -1093,7 +1105,7 @@ static void Program_State_Halted_Handler(struct object_data *pObject)
|
|||||||
}
|
}
|
||||||
} else if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
} else if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
||||||
if (pObject->Load) {
|
if (pObject->Load) {
|
||||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
err = pObject->Load(pObject->Context);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
||||||
pObject->Program_State = PROGRAM_STATE_LOADING;
|
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)
|
static void Program_State_Running_Handler(struct object_data *pObject)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@@ -1142,7 +1158,7 @@ static void Program_State_Running_Handler(struct object_data *pObject)
|
|||||||
}
|
}
|
||||||
} else if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
} else if (pObject->Program_Change == PROGRAM_REQUEST_LOAD) {
|
||||||
if (pObject->Load) {
|
if (pObject->Load) {
|
||||||
err = pObject->Load(pObject->Context, pObject->Program_Location);
|
err = pObject->Load(pObject->Context);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
pObject->Reason_For_Halt = PROGRAM_ERROR_NORMAL;
|
||||||
pObject->Program_State = PROGRAM_STATE_LOADING;
|
pObject->Program_State = PROGRAM_STATE_LOADING;
|
||||||
|
|||||||
@@ -110,12 +110,13 @@ void Program_Cleanup(void);
|
|||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void Program_Init(void);
|
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
|
BACNET_STACK_EXPORT
|
||||||
void Program_Context_Set(uint32_t object_instance, void *context);
|
void Program_Context_Set(uint32_t object_instance, void *context);
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void Program_Load_Set(
|
void Program_Load_Set(uint32_t object_instance, int (*load)(void *context));
|
||||||
uint32_t object_instance, int (*load)(void *context, const char *location));
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void Program_Run_Set(uint32_t object_instance, int (*run)(void *context));
|
void Program_Run_Set(uint32_t object_instance, int (*run)(void *context));
|
||||||
BACNET_STACK_EXPORT
|
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__ */
|
||||||
@@ -30,6 +30,7 @@ if (CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "GNU")
|
|||||||
# since they are common in embedded
|
# since they are common in embedded
|
||||||
add_compile_options(-Wno-sign-conversion -Wno-conversion)
|
add_compile_options(-Wno-sign-conversion -Wno-conversion)
|
||||||
add_compile_options(-Wno-sign-compare)
|
add_compile_options(-Wno-sign-compare)
|
||||||
|
add_compile_options(-Wno-implicit-fallthrough)
|
||||||
|
|
||||||
# Just noise from clang
|
# Just noise from clang
|
||||||
if (CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "AppleClang")
|
if (CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "AppleClang")
|
||||||
@@ -43,6 +44,7 @@ if (CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "GNU")
|
|||||||
add_compile_options(-Wno-missing-declarations)
|
add_compile_options(-Wno-missing-declarations)
|
||||||
add_compile_options(-Wno-unused-but-set-variable)
|
add_compile_options(-Wno-unused-but-set-variable)
|
||||||
add_compile_options(-Wno-write-strings)
|
add_compile_options(-Wno-write-strings)
|
||||||
|
add_compile_options(-Wno-implicit-fallthrough)
|
||||||
|
|
||||||
add_link_options(-fprofile-arcs -ftest-coverage)
|
add_link_options(-fprofile-arcs -ftest-coverage)
|
||||||
endif()
|
endif()
|
||||||
@@ -171,6 +173,8 @@ list(APPEND testdirs
|
|||||||
bacnet/basic/object/structured_view
|
bacnet/basic/object/structured_view
|
||||||
bacnet/basic/object/time_value
|
bacnet/basic/object/time_value
|
||||||
bacnet/basic/object/trendlog
|
bacnet/basic/object/trendlog
|
||||||
|
# basic/program
|
||||||
|
bacnet/basic/program/ubasic
|
||||||
# basic/sys
|
# basic/sys
|
||||||
bacnet/basic/sys/color_rgb
|
bacnet/basic/sys/color_rgb
|
||||||
bacnet/basic/sys/days
|
bacnet/basic/sys/days
|
||||||
|
|||||||
@@ -16,11 +16,10 @@
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int Program_Load(void *context, const char *location)
|
static int Program_Load(void *context)
|
||||||
{
|
{
|
||||||
/* Placeholder for load function */
|
/* Placeholder for load function */
|
||||||
(void)context;
|
(void)context;
|
||||||
(void)location;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||||
|
|
||||||
|
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
project(test_${basename}
|
||||||
|
VERSION 1.0.0
|
||||||
|
LANGUAGES C)
|
||||||
|
|
||||||
|
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"/test/bacnet/[a-zA-Z_/-]*$"
|
||||||
|
"/src"
|
||||||
|
SRC_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"/test/bacnet/[a-zA-Z_/-]*$"
|
||||||
|
"/test"
|
||||||
|
TST_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
set(ZTST_DIR "${TST_DIR}/ztest/src")
|
||||||
|
|
||||||
|
add_compile_definitions(
|
||||||
|
BIG_ENDIAN=0
|
||||||
|
CONFIG_ZTEST=1
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${SRC_DIR}
|
||||||
|
${TST_DIR}/ztest/include
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
# File(s) under test
|
||||||
|
${SRC_DIR}/bacnet/basic/program/ubasic/ubasic.c
|
||||||
|
${SRC_DIR}/bacnet/basic/program/ubasic/tokenizer.c
|
||||||
|
# Support files and stubs (pathname alphabetical)
|
||||||
|
# Test and test library files
|
||||||
|
./src/main.c
|
||||||
|
${ZTST_DIR}/ztest_mock.c
|
||||||
|
${ZTST_DIR}/ztest.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,447 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @details Test the uBASIC implementation
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date 2025
|
||||||
|
* @brief Platform libc and compiler abstraction layer
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include <bacnet/bacdef.h>
|
||||||
|
#include <bacnet/basic/program/ubasic/ubasic.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup bacnet_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint32_t Tick_Counter = 0;
|
||||||
|
static void tick_increment(void)
|
||||||
|
{
|
||||||
|
Tick_Counter++;
|
||||||
|
}
|
||||||
|
static uint32_t tick_now(void)
|
||||||
|
{
|
||||||
|
return Tick_Counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t ADC_Value[UINT8_MAX + 1];
|
||||||
|
static int32_t adc_read(uint8_t channel)
|
||||||
|
{
|
||||||
|
return ADC_Value[channel];
|
||||||
|
}
|
||||||
|
static void adc_config(uint8_t sampletime, uint8_t nreads)
|
||||||
|
{
|
||||||
|
(void)sampletime;
|
||||||
|
(void)nreads;
|
||||||
|
}
|
||||||
|
static uint32_t Event_Mask;
|
||||||
|
static int8_t hw_event(uint8_t bit)
|
||||||
|
{
|
||||||
|
if (bit < 32) {
|
||||||
|
if (Event_Mask & (1UL << bit)) {
|
||||||
|
return 1; // Event is set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Event is not set
|
||||||
|
}
|
||||||
|
static void hw_event_clear(uint8_t bit)
|
||||||
|
{
|
||||||
|
if (bit < 32) {
|
||||||
|
Event_Mask &= ~(1UL << bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static uint8_t GPIO_Pin_State[UINT8_MAX + 1];
|
||||||
|
static void gpio_write(uint8_t ch, uint8_t pin_state)
|
||||||
|
{
|
||||||
|
GPIO_Pin_State[ch] = pin_state;
|
||||||
|
}
|
||||||
|
static void gpio_config(uint8_t ch, int8_t mode, uint8_t freq)
|
||||||
|
{
|
||||||
|
(void)ch;
|
||||||
|
(void)mode;
|
||||||
|
(void)freq;
|
||||||
|
}
|
||||||
|
static void pwm_config(uint16_t psc, uint16_t per)
|
||||||
|
{
|
||||||
|
(void)psc;
|
||||||
|
(void)per;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t Duty_Cycle[UINT8_MAX + 1];
|
||||||
|
static void pwm_write(uint8_t ch, int32_t dutycycle)
|
||||||
|
{
|
||||||
|
Duty_Cycle[ch] = dutycycle;
|
||||||
|
}
|
||||||
|
static int32_t pwm_read(uint8_t ch)
|
||||||
|
{
|
||||||
|
return Duty_Cycle[ch];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a buffer to the serial port
|
||||||
|
* @param msg Pointer to the buffer to write
|
||||||
|
* @param n Number of bytes to write
|
||||||
|
*/
|
||||||
|
static void serial_write(const char *msg, uint16_t n)
|
||||||
|
{
|
||||||
|
printf("%.*s", n, msg);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate a random number
|
||||||
|
* @param size Size of the random number in bits
|
||||||
|
* @return Random number size-bits wide
|
||||||
|
*/
|
||||||
|
static uint32_t random_uint32(uint8_t size)
|
||||||
|
{
|
||||||
|
uint32_t r = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
r |= (1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct test_bacnet_object {
|
||||||
|
uint16_t object_type;
|
||||||
|
uint32_t object_instance;
|
||||||
|
uint32_t property_id;
|
||||||
|
VARIABLE_TYPE property_value;
|
||||||
|
char *object_name;
|
||||||
|
};
|
||||||
|
static struct test_bacnet_object Test_BACnet_Object[5];
|
||||||
|
|
||||||
|
static void
|
||||||
|
bacnet_create_object(uint16_t object_type, uint32_t instance, char *object_name)
|
||||||
|
{
|
||||||
|
if (instance < ARRAY_SIZE(Test_BACnet_Object)) {
|
||||||
|
Test_BACnet_Object[instance].object_type = object_type;
|
||||||
|
Test_BACnet_Object[instance].object_instance = instance;
|
||||||
|
Test_BACnet_Object[instance].object_name = strdup(object_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bacnet_write_property(
|
||||||
|
uint16_t object_type,
|
||||||
|
uint32_t instance,
|
||||||
|
uint32_t property_id,
|
||||||
|
VARIABLE_TYPE value)
|
||||||
|
{
|
||||||
|
if (instance < ARRAY_SIZE(Test_BACnet_Object)) {
|
||||||
|
Test_BACnet_Object[instance].object_type = object_type;
|
||||||
|
Test_BACnet_Object[instance].object_instance = instance;
|
||||||
|
Test_BACnet_Object[instance].property_id = property_id;
|
||||||
|
Test_BACnet_Object[instance].property_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VARIABLE_TYPE bacnet_read_property(
|
||||||
|
uint16_t object_type, uint32_t instance, uint32_t property_id)
|
||||||
|
{
|
||||||
|
if (instance < ARRAY_SIZE(Test_BACnet_Object)) {
|
||||||
|
if (Test_BACnet_Object[instance].object_type == object_type &&
|
||||||
|
Test_BACnet_Object[instance].property_id == property_id) {
|
||||||
|
return Test_BACnet_Object[instance].property_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST(ubasic_tests, test_ubasic_gpio)
|
||||||
|
#else
|
||||||
|
static void test_ubasic_gpio(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct ubasic_data data = { 0 };
|
||||||
|
const char *program =
|
||||||
|
/* program listing with either \0, \n, or ';' at the end of each line.
|
||||||
|
note: indentation is not required */
|
||||||
|
"println 'Demo - GPIO & ADC';"
|
||||||
|
"pinmode(0xc0,-1,0);"
|
||||||
|
"pinmode(0xc1,-1,0);"
|
||||||
|
"pinmode(0xc2,-1,0);"
|
||||||
|
"pinmode(0xc3,-1,0);"
|
||||||
|
"for j = 0 to 2;"
|
||||||
|
" dwrite(0xc0,(j % 2));"
|
||||||
|
" dwrite(0xc1,(j % 2));"
|
||||||
|
" dwrite(0xc2,(j % 2));"
|
||||||
|
" dwrite(0xc3,(j % 2));"
|
||||||
|
" sleep(0.5);"
|
||||||
|
"next j;"
|
||||||
|
"aread_conf(7,16);"
|
||||||
|
"aread_conf(7,17);"
|
||||||
|
"a = 4096 / 2;"
|
||||||
|
"z = 4096 / 2;"
|
||||||
|
"s = 5;"
|
||||||
|
"for i = 1 to s;"
|
||||||
|
" x = aread(16);"
|
||||||
|
" y = aread(17);"
|
||||||
|
" println 'VREF,TEMP=', x, y;"
|
||||||
|
" a = avgw(x,a,s);"
|
||||||
|
" z = avgw(y,z,s);"
|
||||||
|
"next i;"
|
||||||
|
"println 'average x y=', a, z;"
|
||||||
|
"end;";
|
||||||
|
VARIABLE_TYPE value = 0;
|
||||||
|
data.mstimer_now = tick_now;
|
||||||
|
data.serial_write = serial_write;
|
||||||
|
data.gpio_config = gpio_config;
|
||||||
|
data.gpio_write = gpio_write;
|
||||||
|
data.adc_config = adc_config;
|
||||||
|
data.adc_read = adc_read;
|
||||||
|
data.pwm_config = pwm_config;
|
||||||
|
data.pwm_write = pwm_write;
|
||||||
|
data.pwm_read = pwm_read;
|
||||||
|
data.hw_event = hw_event;
|
||||||
|
data.hw_event_clear = hw_event_clear;
|
||||||
|
ADC_Value[16] = 2048;
|
||||||
|
ADC_Value[17] = 2048;
|
||||||
|
ubasic_load_program(&data, program);
|
||||||
|
zassert_equal(data.status.bit.isRunning, 1, NULL);
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
while (!ubasic_finished(&data)) {
|
||||||
|
ubasic_run_program(&data);
|
||||||
|
tick_increment();
|
||||||
|
}
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
/* check the final value of the bacnet read property */
|
||||||
|
value = ubasic_get_variable(&data, 'a');
|
||||||
|
zassert_equal(
|
||||||
|
fixedpt_toint(value), 2048, "a value=%d", fixedpt_toint(value));
|
||||||
|
value = ubasic_get_variable(&data, 'z');
|
||||||
|
zassert_equal(
|
||||||
|
fixedpt_toint(value), 2048, "z value=%d", fixedpt_toint(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST(ubasic_tests, test_ubasic_bacnet)
|
||||||
|
#else
|
||||||
|
static void test_ubasic_bacnet(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct ubasic_data data = { 0 };
|
||||||
|
const char *program =
|
||||||
|
/* program listing with either \0, \n, or ';' at the end of each line.
|
||||||
|
note: indentation is not required */
|
||||||
|
"println 'Demo - BACnet';"
|
||||||
|
"bac_create(0, 1, 'Object1');"
|
||||||
|
"bac_create(0, 2, 'Object2');"
|
||||||
|
"bac_create(0, 3, 'Object3');"
|
||||||
|
"bac_create(0, 4, 'Object4');"
|
||||||
|
"bac_write(0, 1, 85, 42);"
|
||||||
|
"a = bac_read(0, 1, 85);"
|
||||||
|
"println 'bac_read 0, 1, 85 = ' a;"
|
||||||
|
"end;";
|
||||||
|
VARIABLE_TYPE value = 0;
|
||||||
|
data.mstimer_now = tick_now;
|
||||||
|
data.serial_write = serial_write;
|
||||||
|
data.bacnet_create_object = bacnet_create_object;
|
||||||
|
data.bacnet_write_property = bacnet_write_property;
|
||||||
|
data.bacnet_read_property = bacnet_read_property;
|
||||||
|
ubasic_load_program(&data, program);
|
||||||
|
zassert_equal(data.status.bit.isRunning, 1, NULL);
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
while (!ubasic_finished(&data)) {
|
||||||
|
ubasic_run_program(&data);
|
||||||
|
tick_increment();
|
||||||
|
}
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
/* check the final value of the bacnet read property */
|
||||||
|
value = ubasic_get_variable(&data, 'a');
|
||||||
|
zassert_equal(
|
||||||
|
fixedpt_toint(value), 42, "bacnet read property value=%d",
|
||||||
|
fixedpt_toint(value));
|
||||||
|
zassert_equal(
|
||||||
|
Test_BACnet_Object[1].object_type, 0, "bacnet object type=%d",
|
||||||
|
Test_BACnet_Object[1].object_type);
|
||||||
|
zassert_equal(
|
||||||
|
Test_BACnet_Object[1].object_instance, 1, "bacnet object instance=%d",
|
||||||
|
Test_BACnet_Object[1].object_instance);
|
||||||
|
zassert_equal(
|
||||||
|
Test_BACnet_Object[1].property_id, 85, "bacnet object property ID=%d",
|
||||||
|
Test_BACnet_Object[1].property_id);
|
||||||
|
zassert_equal(
|
||||||
|
strcmp(Test_BACnet_Object[1].object_name, "Object1"), 0,
|
||||||
|
"bacnet object name=%s", Test_BACnet_Object[1].object_name);
|
||||||
|
zassert_equal(
|
||||||
|
strcmp(Test_BACnet_Object[2].object_name, "Object2"), 0,
|
||||||
|
"bacnet object name=%s", Test_BACnet_Object[2].object_name);
|
||||||
|
zassert_equal(
|
||||||
|
strcmp(Test_BACnet_Object[3].object_name, "Object3"), 0,
|
||||||
|
"bacnet object name=%s", Test_BACnet_Object[3].object_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST(ubasic_tests, test_ubasic_math)
|
||||||
|
#else
|
||||||
|
static void test_ubasic_math(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct ubasic_data data = { 0 };
|
||||||
|
const char *program =
|
||||||
|
/* program listing with either \0, \n, or ';' at the end of each line.
|
||||||
|
note: indentation is not required */
|
||||||
|
"println 'Demo - Math';"
|
||||||
|
"for i = 1 to 2;"
|
||||||
|
" j = i + 0.25 + 1/2;"
|
||||||
|
" k = sqrt(2*j) + ln(4*i) + cos(i+j) + sin(j);"
|
||||||
|
"next i;"
|
||||||
|
"println 'j=' j;"
|
||||||
|
"println 'k=' k;"
|
||||||
|
"dim r@(5);"
|
||||||
|
"for i = 1 to 5;"
|
||||||
|
" r@(i) = ran;"
|
||||||
|
" println 'r[' i ']=' r@(i);"
|
||||||
|
"next i;"
|
||||||
|
"dim u@(5);"
|
||||||
|
"a = 0;"
|
||||||
|
"for i = 1 to 5;"
|
||||||
|
" u = uniform;"
|
||||||
|
" println 'u[' i ']=' u;"
|
||||||
|
" u@(i) = u;"
|
||||||
|
" a = avgw(u,a,5);"
|
||||||
|
"next i;"
|
||||||
|
"println 'uniform moving average = ' a;"
|
||||||
|
"x = 1000 * uniform;"
|
||||||
|
"f = floor(x);"
|
||||||
|
"c = ceil(x);"
|
||||||
|
"r = round(x);"
|
||||||
|
"w = pow(x,3);"
|
||||||
|
"println 'x=' x;"
|
||||||
|
"println 'floor(x)=' f;"
|
||||||
|
"println 'ceil(x)=' c;"
|
||||||
|
"println 'round(x)=' r;"
|
||||||
|
"println 'x^3=' w;"
|
||||||
|
"end;";
|
||||||
|
|
||||||
|
VARIABLE_TYPE value = 0, xvalue = 0, arrayvalue[5];
|
||||||
|
unsigned i;
|
||||||
|
int32_t value_int = 0;
|
||||||
|
int32_t value_frac = 0;
|
||||||
|
int32_t value_math = 0;
|
||||||
|
|
||||||
|
data.mstimer_now = tick_now;
|
||||||
|
data.serial_write = serial_write;
|
||||||
|
data.random_uint32 = random_uint32;
|
||||||
|
ubasic_load_program(&data, program);
|
||||||
|
zassert_equal(data.status.bit.isRunning, 1, NULL);
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
while (!ubasic_finished(&data)) {
|
||||||
|
ubasic_run_program(&data);
|
||||||
|
tick_increment();
|
||||||
|
}
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
/* check the final values of the math operations */
|
||||||
|
value = ubasic_get_variable(&data, 'j');
|
||||||
|
value_int = fixedpt_toint(value);
|
||||||
|
value_frac = fixedpt_fracpart_floor_toint(value, 2);
|
||||||
|
zassert_equal(value_int, 2, "int=%d", value_int);
|
||||||
|
zassert_equal(value_frac, 75, "frac=%d", value_frac);
|
||||||
|
value = ubasic_get_variable(&data, 'k');
|
||||||
|
value_int = fixedpt_toint(value);
|
||||||
|
value_frac = fixedpt_fracpart_floor_toint(value, 2);
|
||||||
|
zassert_equal(value_int, 4, "int=%d", value_int);
|
||||||
|
zassert_equal(value_frac, 83, "frac=%d", value_frac);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(arrayvalue); i++) {
|
||||||
|
arrayvalue[i] = ubasic_get_arrayvariable(&data, 'r', 1 + i);
|
||||||
|
value_int = fixedpt_toint(arrayvalue[i]);
|
||||||
|
zassert_equal(value_int, 1, "ran[%u]=%d", 1 + i, value_int);
|
||||||
|
}
|
||||||
|
/* uniform random value */
|
||||||
|
xvalue = ubasic_get_variable(&data, 'x');
|
||||||
|
/* floor */
|
||||||
|
value_math = fixedpt_floor_toint(xvalue);
|
||||||
|
value = ubasic_get_variable(&data, 'f');
|
||||||
|
value_int = fixedpt_toint(value);
|
||||||
|
zassert_equal(
|
||||||
|
value_int, value_math, "int=%d floor=%d", value_int, value_math);
|
||||||
|
/* ceiling */
|
||||||
|
value_math = fixedpt_ceil_toint(xvalue);
|
||||||
|
value = ubasic_get_variable(&data, 'c');
|
||||||
|
value_int = fixedpt_toint(value);
|
||||||
|
zassert_equal(
|
||||||
|
value_int, value_math, "int=%d ceil=%d", value_int, value_math);
|
||||||
|
/* round */
|
||||||
|
value_math = fixedpt_round_toint(xvalue);
|
||||||
|
value = ubasic_get_variable(&data, 'r');
|
||||||
|
value_int = fixedpt_toint(value);
|
||||||
|
zassert_equal(
|
||||||
|
value_int, value_math, "int=%d round=%d", value_int, value_math);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST(ubasic_tests, test_ubasic)
|
||||||
|
#else
|
||||||
|
static void test_ubasic(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct ubasic_data data = { 0 };
|
||||||
|
const char *program =
|
||||||
|
/* program listing with either \0, \n, or ';' at the end of each line.
|
||||||
|
note: indentation is not required */
|
||||||
|
"println 'Demo - Flow';"
|
||||||
|
"gosub l1;"
|
||||||
|
"for i = 1 to 8;"
|
||||||
|
" for j = 1 to 9;"
|
||||||
|
" println 'i,j=',i,j;"
|
||||||
|
" next j;"
|
||||||
|
"next i;"
|
||||||
|
"println 'Demo 1 Completed';"
|
||||||
|
"end;"
|
||||||
|
":l1 "
|
||||||
|
" println 'subroutine';"
|
||||||
|
"return;";
|
||||||
|
VARIABLE_TYPE value = 0;
|
||||||
|
int32_t value_int = 0;
|
||||||
|
|
||||||
|
ubasic_load_program(&data, program);
|
||||||
|
zassert_equal(data.status.bit.isRunning, 1, NULL);
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
while (!ubasic_finished(&data)) {
|
||||||
|
ubasic_run_program(&data);
|
||||||
|
}
|
||||||
|
zassert_equal(data.status.bit.Error, 0, NULL);
|
||||||
|
/* check the final value of i and j */
|
||||||
|
value = ubasic_get_variable(&data, 'i');
|
||||||
|
value_int = fixedpt_toint(value);
|
||||||
|
zassert_equal(value_int, 9, NULL);
|
||||||
|
value = ubasic_get_variable(&data, 'j');
|
||||||
|
value_int = fixedpt_toint(value);
|
||||||
|
zassert_equal(value_int, 10, NULL);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST_SUITE(ubasic_tests, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
#else
|
||||||
|
void test_main(void)
|
||||||
|
{
|
||||||
|
ztest_test_suite(
|
||||||
|
ubasic_tests, ztest_unit_test(test_ubasic),
|
||||||
|
ztest_unit_test(test_ubasic_math), ztest_unit_test(test_ubasic_bacnet),
|
||||||
|
ztest_unit_test(test_ubasic_gpio));
|
||||||
|
|
||||||
|
ztest_run_test_suite(ubasic_tests);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user