Files
bacnet_stack/ports/stm32f4xx/program-ubasic.c
T

148 lines
3.9 KiB
C

/**
* @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);
}