diff --git a/ChangeLog b/ChangeLog
index 53c62804..e9742c99 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2026-09-26 (12.34)
+ TEENSY: Add flash and SD card file system
+ WINDOWS: Remove __p__environ warning when building
+
2026-04-28 (12.34)
COMMON: implement plugin_refresh_id for variable lifecycle handling
COMMON: fix bug with comma in string assigned as local #283
diff --git a/src/common/system.c b/src/common/system.c
index 16d32584..7ad9357d 100644
--- a/src/common/system.c
+++ b/src/common/system.c
@@ -23,8 +23,6 @@
#include
#endif
-extern char **environ;
-
#define BUFSIZE 1024
#if defined(_Win32)
@@ -126,6 +124,8 @@ int dev_run(const char *cmd, var_t *r, int wait) {
}
#else
+extern char **environ;
+
int dev_run(const char *cmd, var_t *r, int wait) {
int result = 1;
if (r != NULL) {
diff --git a/src/platform/teensy/CMakeLists.txt b/src/platform/teensy/CMakeLists.txt
index 8304ea0a..aa259832 100644
--- a/src/platform/teensy/CMakeLists.txt
+++ b/src/platform/teensy/CMakeLists.txt
@@ -42,6 +42,7 @@ set(CMAKE_EXE_LINKER_FLAGS "-Os -Wl,--gc-sections,--relax ${SPECS} ${CPU_OPTIONS
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_SIZE arm-none-eabi-size)
+set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
# Include the module directories
add_subdirectory(libs)
@@ -58,6 +59,7 @@ include_directories(${MODULES}/USBHost_t36)
include_directories(${MODULES}/Wire)
include_directories(${MODULES}/SD/src)
include_directories(${MODULES}/SdFat/src)
+include_directories(${MODULES}/LittleFS/src)
# include config.h and common headers
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..)
@@ -71,6 +73,10 @@ set(SOURCES
src/module.cpp
src/teensy.cpp
src/ssd1306.cpp
+ src/i2c.cpp
+ src/serial.cpp
+ src/pinio.cpp
+ src/fs.cpp
)
# Add executable with the list of source files
diff --git a/src/platform/teensy/Makefile.am b/src/platform/teensy/Makefile.am
index 68b2c758..ed4091ad 100644
--- a/src/platform/teensy/Makefile.am
+++ b/src/platform/teensy/Makefile.am
@@ -25,6 +25,11 @@ build/smallbasic.elf : \
src/device.cpp \
src/teensy.cpp \
src/ssd1306.cpp \
+ src/fs.cpp \
+ src/i2c.cpp \
+ src/serial.cpp \
+ src/pinio.cpp \
+ src/module.cpp \
src/main_bas.h
@cd build && make -j 32
diff --git a/src/platform/teensy/README.md b/src/platform/teensy/README.md
index 317af58d..126acf4d 100644
--- a/src/platform/teensy/README.md
+++ b/src/platform/teensy/README.md
@@ -93,16 +93,16 @@ build/modules/teensy_loader_cli/teensy_loader_cli --mcu=TEENSY40 -w -v -s build/
SMALLBASIC for Teensy offers three ways to upload and run a program.
1. Format a SD card using FAT32. Rename your program to `MAIN.BAS` and copy it to the SD card.
-2. Include your program in the firmware. Replace `main.bas` in `src/platform/teensy` by your program and build
+2. Upload your program as `MAIN.BAS` to the flash memory file system (i.e. use `console.bas`)
+3. Include your program in the firmware. Replace `main.bas` in `src/platform/teensy` by your program and build
the firmware.
-3. Send your program via USB-serial connection to the Teensy. In Linux use ` cat YourProgram.bas > /dev/ttyACM0`
+5. Send your program via USB-serial connection to the Teensy. In Linux use ` cat YourProgram.bas > /dev/ttyACM0`
Change `/dev/ttyACM0` to the USB-serial port of your Teensy.
-4. Goto 3.
When the Teensy starts up, it will check in the above indicated order for your program. If it finds
-a SD card and the SD card contains a file `MAIN.BAS`, it will execute it. Otherwise it will check, if a program
-was included in the firmware. If no program was included, the Teensy will switch to interactive mode and waits
-for a program upload via USB-serial.
+a SD card and the SD card contains a file `MAIN.BAS`, it will execute it. Otherwise it will check flash for
+the file `MAIN.bas` and executes it. Otherwise it will check, if a program was included in the firmware. If no
+program was included, the Teensy will switch to interactive mode and waits for a program upload via USB-serial.
While your program is running, the Teensy will check continuously if data is available at the USB-serial port.
If data is available for longer than one second your running program will be terminated and the queued data of the
@@ -114,7 +114,7 @@ If an error occurred, for example a syntax error, execution will stop and you ha
the USB-serial port.
If the execution of your program comes to an end, for example when reaching the end of the program or when `STOP` is
-called, the program is terminated and the next section in the above list is performed.
+called, the program is terminated and the teensy switches to interactive mode.
# Read output from your running program
diff --git a/src/platform/teensy/libs/CMakeLists.txt b/src/platform/teensy/libs/CMakeLists.txt
index 05452b15..1439e8b1 100644
--- a/src/platform/teensy/libs/CMakeLists.txt
+++ b/src/platform/teensy/libs/CMakeLists.txt
@@ -16,6 +16,7 @@ set(USB_DIR ${MODULES_DIR}/USBHost_t36)
set(WIRE_DIR ${MODULES_DIR}/Wire)
set(SD_DIR ${MODULES_DIR}/SD/src)
set(SDFAT_DIR ${MODULES_DIR}/SdFat/src)
+set(LITTLEFS_DIR ${MODULES_DIR}/LittleFS/src)
set(SOURCES
${ADC_DIR}/ADC.cpp
@@ -162,6 +163,10 @@ set(SOURCES
${SDFAT_DIR}/common/FsUtf.cpp
${SDFAT_DIR}/common/PrintBasic.cpp
${SDFAT_DIR}/common/upcase.cpp
+ ${LITTLEFS_DIR}/LittleFS.cpp
+ ${LITTLEFS_DIR}/LittleFS_NAND.cpp
+ ${LITTLEFS_DIR}/littlefs/lfs.c
+ ${LITTLEFS_DIR}/littlefs/lfs_util.c
)
add_library(libs STATIC ${SOURCES})
@@ -176,4 +181,5 @@ target_include_directories(libs PRIVATE ${TEENSY_DIR})
target_include_directories(libs PRIVATE ${WIRE_DIR})
target_include_directories(libs PRIVATE ${SD_DIR})
target_include_directories(libs PRIVATE ${SDFAT_DIR})
+target_include_directories(libs PRIVATE ${LITTLEFS_DIR})
diff --git a/src/platform/teensy/samples/SerialTerminal.bas b/src/platform/teensy/samples/SerialTerminal.bas
index 0eee365d..cfa54078 100644
--- a/src/platform/teensy/samples/SerialTerminal.bas
+++ b/src/platform/teensy/samples/SerialTerminal.bas
@@ -3,7 +3,7 @@ option base 1
ReceiveBuffer = ""
ComPort = "/dev/ttyACM0"
ComSpeed = "115200"
-FileName = "serialUSB_receive_string.bas"
+FileName = "samples/console.bas"
SendString = ""
NumberLines = floor(YMAX / TextHeight("Qly")) - 1
NumberRows = floor(YMAX / TextWidth("W"))
@@ -33,93 +33,96 @@ const KeyF6 = ESC + Chr(0xF0 + 6)
const KeyF9 = ESC + Chr(0xF0 + 9)
const KeyF10 = ESC + Chr(0xF0 + 10)
+
+GetStartupParameter()
Connect()
PrintGUI()
while(1)
- 'CheckIsConnected()
- if(!isConnected) then Connect()
- k = inkey
- if(len(k))
- select case k
- case KeyReturn
- Send(SendString)
- SendHistory << SendString
- SendHistoryIndex = ubound(SendHistory)
- SendString = ""
- case KeyEsc
- SendString = ""
- case KeyLeft
- case KeyRight
- case KeyDown
- SendHistoryIndex = iff(SendHistoryIndex < ubound(SendHistory), SendHistoryIndex + 1, SendHistoryIndex)
- SendString = SendHistory[SendHistoryIndex]
- case KeyUp
- SendHistoryIndex = iff(SendHistoryIndex > 0, SendHistoryIndex - 1, 0)
- SendString = SendHistory[SendHistoryIndex]
- case KeyBackspace
- SendString = chop(SendString)
- case KeyF1
- color 15,0
- locate NumberLines - 1,0
- print "\e[K";
- Input "Enter COM port: ", ComPort
- if(isConnected) then close #1
- isConnected = 0
- case KeyF2
- color 15,0
- locate NumberLines - 1,0
- print "\e[K";
- Input "Enter COM speed: ", ComSpeed
- if(isConnected) then close #1
- isConnected = 0
- case KeyF3
- 'color 15,0
- 'locate NumberLines - 1,0
- 'print "\e[K";
- 'Input "Enter file name: ", FileName
- showpage(1)
- FileName = FileSelectDialog(0, 50, 50, XMAX - 100, YMAX - 100, 0)
- case KeyF4
- tsave "teensylog_" + ticks() + ".txt", ReceiveArray
- case KeyF6
- UploadFile()
- case KeyF9
- if(isConnected)
- close #1
- isConnected = 0
- endif
- ReceiveBuffer = ""
- ReceiveArray = []
- case KeyF10
- if(isConnected) then close #1
- stop
- case else
- SendString = SendString + k
- end select
- PrintGUI()
- endif
-
- if(isConnected)
- l = lof(1)
- if(l)
- ReceiveBuffer = ReceiveBuffer + INPUT(l, 1)
- split ReceiveBuffer, "\n", ReceiveArray
- if(len(ReceiveArray) > NumberLines - 1)
- n = len(ReceiveArray) - NumberLines + 1
- delete ReceiveArray, 1, n
+ if(!isConnected) then Connect()
+ k = inkey
+ if(len(k))
+ select case k
+ case KeyReturn
+ Send(SendString)
+ SendHistory << SendString
+ SendHistoryIndex = ubound(SendHistory)
+ SendString = ""
+ case KeyEsc
+ SendString = ""
+ case KeyLeft
+ case KeyRight
+ case KeyDown
+ if(SendHistoryIndex > 0)
+ SendHistoryIndex = iff(SendHistoryIndex < ubound(SendHistory), SendHistoryIndex + 1, SendHistoryIndex)
+ SendString = SendHistory[SendHistoryIndex]
+ endif
+ case KeyUp
+ if(SendHistoryIndex > 0)
+ SendString = SendHistory[SendHistoryIndex]
+ SendHistoryIndex = iff(SendHistoryIndex > 1, SendHistoryIndex - 1, 1)
endif
- PrintGUI()
+ case KeyBackspace
+ SendString = chop(SendString)
+ case KeyF1
+ color 15,0
+ locate NumberLines - 1,0
+ print "\e[K";
+ Input "Enter COM port: ", ComPort
+ Input "Enter COM speed: ", ComSpeed
+ if(isConnected) then close #1
+ isConnected = 0
+ case KeyF3
+ if(instr(sbver(), "SDL"))
+ showpage(1)
+ FileName_temp = FileSelectDialog(0, 50, 50, XMAX - 100, YMAX - 100, 0)
+ if(FileName_temp != -1) then FileName = FileName_temp
+ else
+ color 15,0
+ repeat
+ locate NumberLines - 1,0
+ print "\e[K";
+ Input "Enter file name for upload: ", FileName
+ until(exist(FileName))
+ endif
+ case KeyF4
+ tsave "teensylog_" + ticks() + ".txt", ReceiveArray
+ case KeyF6
+ UploadFile()
+ case KeyF9
+ ReceiveBuffer = ""
+ ReceiveArray = []
+ case KeyF10
+ if(isConnected) then close #1
+ stop
+ case else
+ if(asc(k) > 31 AND asc(k) < 127)
+ SendString = SendString + k
+ endif
+ end select
+ PrintGUI()
+ endif
+
+ if(isConnected)
+ l = lof(1)
+ if(l)
+ ReceiveBuffer = ReceiveBuffer + INPUT(l, 1)
+ split ReceiveBuffer, "\n", ReceiveArray
+ if(len(ReceiveArray) > NumberLines - 1)
+ n = len(ReceiveArray) - NumberLines + 1
+ delete ReceiveArray, 1, n
endif
+ PrintGUI()
endif
-
- delay(20)
- showpage
+ endif
+
+ delay(20)
+ showpage
wend
sub CheckIsConnected()
local result
-
+
if(!isConnected) then return
result = lof(1)
@@ -141,11 +144,12 @@ sub Connect()
isConnected = 0
end try
PrintGUI()
+ print #1, "PRINT SBVER"
end
sub Send(s)
- ReceiveBuffer = ReceiveBuffer + "\e[33m" + "> " + s + "\e[30m\n"
+ ' ReceiveBuffer = ReceiveBuffer + "\e[33m" + "> " + s + "\e[30m\n"
print #1, s
end
@@ -160,21 +164,17 @@ sub UploadFile()
end
sub PrintGUI()
- color 7,1
+ color 15,0
cls
-
+
for s in ReceiveArray
- print "\e[0m";
- color 14,1
- print s
+ print s + "\e[0m"
next
-
- print "\e[0m"
-
+
color 0, 7
locate 0, 0
- print "TEENSY Serial Terminal v1.0 |\e[35mF1\e[30m Port|\e[35mF2\e[30m Speed|\e[35mF3\e[30m File|\e[35mF4\e[30m Save|\e[35mF6\e[30m Upload|\e[35mF9\e[30m Reset|\e[35mF10\e[30m Quit\e[K"
-
+ print "TEENSY Terminal v1.1 |\e[35mF1\e[30m Setup|\e[35mF3\e[30m File|\e[35mF4\e[30m Save|\e[35mF6\e[30m Upload|\e[35mF9\e[30m Clear|\e[35mF10\e[30m Quit\e[K"
+
color 15, 0
locate NumberLines - 1, 0
print "Send: "; SendString; "\e[K";"\e[7m \e[27m"
@@ -189,6 +189,16 @@ sub PrintGUI()
endif
end
+sub GetStartupParameter()
+ local p
+ p = command()
+ split p, " ", parameters
+
+ if(ubound(parameters) > 0)
+ FileName = parameters[1]
+ endif
+end
+
func FileSelectDialog(Type, x, y, w, h, ButtonSize)
' Displays a file select dialog. If type is 0 (LOAD) then the function
@@ -220,29 +230,29 @@ func FileSelectDialog(Type, x, y, w, h, ButtonSize)
color 15,0
cls
color TextColor, BGColor
-
-
+
+
Directory = cwd()
-
+
if(ButtonSize == 0) then ButtonSize = 3 * Textwidth("W")
-
+
func cmpfunc_strings(x, y)
- x = lower(x)
- y = lower(y)
-
- if x == y
- return 0
- elseif x > y
- return 1
- else
- return -1
- endif
+ x = lower(x)
+ y = lower(y)
+
+ if x == y
+ return 0
+ elseif x > y
+ return 1
+ else
+ return -1
+ endif
end
-
+
func GetFileList()
local FileList
FileList = files("*")
-
+
for ii = 1 to ubound(FileList)
if(isdir(FileList[ii])) then FileList[ii] = enclose(FileList[ii], "[]")
next
@@ -413,3 +423,5 @@ func FileSelectDialog(Type, x, y, w, h, ButtonSize)
end
+
+
diff --git a/src/platform/teensy/samples/bt.bas b/src/platform/teensy/samples/bluetooth.bas
similarity index 100%
rename from src/platform/teensy/samples/bt.bas
rename to src/platform/teensy/samples/bluetooth.bas
diff --git a/src/platform/teensy/samples/hc-06.bas b/src/platform/teensy/samples/bluetooth_hc-06.bas
similarity index 100%
rename from src/platform/teensy/samples/hc-06.bas
rename to src/platform/teensy/samples/bluetooth_hc-06.bas
diff --git a/src/platform/teensy/samples/console.bas b/src/platform/teensy/samples/console.bas
new file mode 100644
index 00000000..fd986335
--- /dev/null
+++ b/src/platform/teensy/samples/console.bas
@@ -0,0 +1,493 @@
+' Console.bas provides a simple interface for
+' accessing flash (teensy 4.0 and 4.1), SD card
+' (teensy 4.1) and manipulating input and output
+' pins. After uploading this file to the teensy
+' type "help" for more information.
+
+import teensy
+
+const FS_READ = 0
+const FS_WRITE = 1
+
+const fs = teensy.fs
+const usbSerial = teensy.openSerial()
+
+teensy.SetInteractive(1)
+
+CurrentDirectory = ""
+
+print
+print "\e[1mSmallBASIC console v1.0\e[0m"
+print "Type 'help' for a list of commands"
+
+while(1)
+ if(usbSerial.ready())
+ s = usbSerial.receive()
+ if(len(s) > 0)
+ s = trim(s)
+ SPLIT s, " ", v
+ cmd = lcase(v[0])
+
+ par_error = 1
+
+ select case cmd
+ case "ls"
+ if(ubound(v) > 0)
+ cmd_ls(v[1])
+ else
+ cmd_ls(-1)
+ endif
+ par_error = 0
+ case "cd"
+ if(ubound(v) > 0)
+ cmd_cd(v[1])
+ par_error = 0
+ endif
+ case "mv"
+ if(ubound(v) > 1)
+ cmd_mv(v[1], v[2])
+ par_error = 0
+ endif
+ case "rm"
+ if(ubound(v) > 0)
+ cmd_rm(v[1])
+ par_error = 0
+ endif
+ case "cp"
+ if(ubound(v) > 1)
+ cmd_cp(v[1], v[2])
+ par_error = 0
+ endif
+ case "mkdir"
+ if(ubound(v) > 0)
+ cmd_mkdir(v[1])
+ par_error = 0
+ endif
+ case "print"
+ if(ubound(v) > 0)
+ cmd_print(v[1])
+ par_error = 0
+ endif
+ case "exit"
+ print "See you soon."
+ exit
+ case "run"
+ if(ubound(v) > 0)
+ cmd_run(v[1])
+ par_error = 0
+ endif
+ case "getfile"
+ if(ubound(v) > 0)
+ cmd_getfile(v[1])
+ par_error = 0
+ endif
+ case "help"
+ cmd_help()
+ case "setpin"
+ if(ubound(v) > 1)
+ cmd_setpin(v[1], v[2])
+ par_error = 0
+ endif
+ case "getpin"
+ if(ubound(v) > 0)
+ cmd_getpin(v[1])
+ par_error = 0
+ endif
+ case "analogwrite"
+ if(ubound(v) > 1)
+ cmd_analogwrite(v[1], v[2])
+ par_error = 0
+ endif
+ case "analogread"
+ if(ubound(v) > 0)
+ cmd_analogread(v[1])
+ par_error = 0
+ endif
+ case "info"
+ cmd_info()
+ case "format"
+ cmd_format()
+ end select
+ if(par_error) then print_error("Parameter missing")
+ endif
+ else
+ delay(10)
+ endif
+wend
+
+func GetFullFile(f)
+ local Directory
+
+ if(f == -1) then return -1
+ if(f == "/") then return ""
+ if(right(f) == "/") then f = chop(f)
+
+ ' Absolute path starting with /
+ if(left(f, 4) == "/sd/") then return("sd:" + mid(f, 4))
+ if(f == "/sd") then return("sd:")
+ if(left(f, 7) == "/flash/") then return("flash:" + mid(f, 7))
+ if(f == "/flash") then return("flash:")
+ if(left(f) == "/") then return(-1)
+
+ ' path starts with one or more ../
+ Directory = CurrentDirectory
+ if(left(f, 3) == "../")
+ while(1)
+ if(left(f, 3) == "../")
+ Directory = leftoflast(Directory, "/")
+ f = mid(f, 4)
+ else
+ return GetFullFile(Directory + "/" + f)
+ endif
+ wend
+ endif
+
+ if(f == "..")
+ if(Directory == "/sd" or Directory == "/flash") then return ""
+ return GetFullFile(leftoflast(Directory, "/"))
+ endif
+
+ ' Relative path
+ if(CurrentDirectory == "/") then return(-1)
+ if(left(f, 2) == "./") then return(GetFullFile(CurrentDirectory + "/" + mid(f, 3)))
+ return(GetFullFile(CurrentDirectory + "/" + f))
+end
+
+sub cmd_ls(dir)
+ local file, path, file2, name
+
+ if(dir == -1 or dir == "/")
+ if(CurrentDirectory == "" or dir == "/")
+ print "\n\e[32m\e[1mList directory: /\e[0m"
+ print "\e[34m[flash]\n\e[34m[sd]\e[0m"
+ exit sub
+ endif
+ path = CurrentDirectory + "/"
+ else
+ path = dir
+ endif
+
+ path = GetFullFile(path) + "/"
+ if(path == -1)
+ print_error("Path not valid")
+ exit sub
+ endif
+
+ file = fs.open(path)
+ if(!file)
+ print_error("Path not found")
+ exit sub
+ endif
+ if(!file.isDirectory())
+ file.close()
+ exit sub
+ endif
+
+ print "\n\e[32m\e[1mList directory "; path; "\e[0m"
+
+ while(1)
+ name = file.getNextFilename()
+ if(name == 0)
+ exit loop
+ endif
+
+ file2 = fs.open(path + name)
+ if(file2.isDirectory())
+ print "\e[34m[";name;"]\e[0m"
+ else
+ if(rightof(name,".") == "bas")
+ print "\e[35m\e[1m";name; "\t\t\e[0m "; file2.size(); " Bytes"
+ else
+ print name; " "; "\t\t"; file2.size(); " Bytes"
+ endif
+ endif
+ file2.close()
+ wend
+ file.close()
+end
+
+sub cmd_cd(directory)
+ local file, path
+
+ path = GetFullFile(directory)
+ if(path == -1)
+ print_error("Path not valid")
+ exit sub
+ endif
+ if(path == "")
+ CurrentDirectory = ""
+ print "\nchange to directory /"
+ exit sub
+ endif
+
+ file = fs.open(path)
+ if(!file)
+ print_error("Not a directory")
+ exit sub
+ endif
+
+ if(file.isDirectory())
+ if(left(path, 3) == "sd:")
+ CurrentDirectory = "/sd" + mid(path, 4)
+ else if(left(path, 6) == "flash:")
+ CurrentDirectory = "/flash" + mid(path, 7)
+ endif
+ if(right(CurrentDirectory) == "/") then CurrentDirectory = chop(CurrentDirectory)
+ print "\nchange to directory "; CurrentDirectory
+ else
+ print_error("Not a directory")
+ endif
+ file.close()
+end
+
+sub cmd_mv(a, b)
+ a = GetFullFile(a)
+ b = GetFullFile(b)
+
+ if(a == -1 or b == -1)
+ print_error("File not valid")
+ exit sub
+ endif
+
+ if(left(a) != left(b))
+ print_error("files can't be moved between different file systems")
+ exit sub
+ endif
+
+ print "\nmove "; a; " to "; b
+ if(!fs.rename(a,b)) then print_error("could not move file")
+end
+
+sub cmd_rm(f)
+ f = GetFullFile(f)
+ if(f == -1)
+ print_error("File not valid")
+ exit sub
+ endif
+
+ print "\nremove "; f
+ if(!fs.remove(f)) then print_error("could not remove file")
+end
+
+sub cmd_cp(f1, f2)
+ local file1, file2, s, path
+
+ f1 = GetFullFile(f1)
+ f2 = GetFullFile(f2)
+
+ if(a == -1 or b == -1)
+ print_error("File not valid")
+ exit sub
+ endif
+
+ print "\ncopy "; f1; " to "; f2
+
+ file1 = OpenFile(f1)
+ if(!file1)
+ print_error("could not open source file")
+ exit sub
+ endif
+
+ file2 = fs.open(f2, FS_WRITE)
+ if(!file2)
+ file1.close()
+ print_error("could not open destination file")
+ exit sub
+ endif
+ file2.truncate()
+
+ while(file1.available())
+ s = file1.read(1)
+ file2.write(s)
+ wend
+
+ file1.close()
+ file2.close()
+end
+
+sub cmd_mkdir(dir)
+ dir = GetFullFile(dir)
+
+ if(dir == -1)
+ print_error("Directory not valid")
+ exit sub
+ endif
+
+ print "\ncreate directoy "; dir
+ if(!fs.mkdir(dir))
+ print_error("could not create directory")
+ endif
+end
+
+sub cmd_print(f)
+ local file, s
+
+ f = GetFullFile(f)
+ if(f == -1)
+ print_error("File not valid")
+ exit sub
+ endif
+
+ file = OpenFile(f)
+ if(!file)
+ exit sub
+ endif
+
+ while(file.available())
+ s = file.read(1)
+ print chr(s);
+ wend
+
+ file.close()
+end
+
+sub print_error(s)
+ print "\e[31mERROR: ";s;"\e[0m"
+end
+
+func OpenFile(name)
+ local file
+
+ file = fs.open(name, FS_READ)
+ if(!file)
+ print_error("not a file")
+ return 0
+ endif
+ if(file.isDirectory())
+ print_error("is directory")
+ file.close()
+ return 0
+ endif
+ return file
+end
+
+sub cmd_getfile(name)
+ local file, bytes, c
+
+ name = GetFullFile(name)
+ if(name == -1)
+ print_error("File not valid")
+ exit sub
+ endif
+
+ file = fs.open(name, FS_WRITE)
+ if(!file)
+ print_error("could not write to file")
+ exit sub
+ endif
+ file.truncate()
+
+ print "\nWaiting for upload."
+ teensy.SetInteractive(0)
+
+ while(!usbSerial.ready())
+ delay(200)
+ wend
+
+ bytes = 0
+ while(usbSerial.ready())
+ c = usbSerial.receive(1)
+ file.write(c, 1)
+ bytes++
+ wend
+
+ file.close()
+ Print bytes; " Bytes received"
+ teensy.SetInteractive(1)
+end
+
+sub cmd_run(name)
+ local file, bytes, s
+
+ name = GetFullFile(name)
+ if(name == -1)
+ print_error("File not valid")
+ exit sub
+ endif
+
+ file = fs.open(name, FS_READ)
+ if(!file)
+ print_error("could not open file")
+ exit sub
+ endif
+
+ dim s
+ while(file.available())
+ s << file.read()
+ wend
+ chain s
+end
+
+sub cmd_format()
+ if(!fs.Quickformat()) then print_error("could not format flash")
+end
+
+sub cmd_help()
+ print
+ print "ls | List files: ls | ls /test | ls .."
+ print "cd | Change directory: cd / | cd /dir1 | cd .."
+ print "cp | Copy file: cp a.txt b.txt | cp a.txt /test/a.txt"
+ print "mv | Move file: mv a.txt b.txt | mv a.txt /test/a.txt"
+ print "rm | Delete file or direcrtory: rm a.txt | rm /test/a.txt"
+ print "mkdir | Create directory: mkdir dir1 | mkdir dir1/dir2"
+ print "print | Print file: print a.txt"
+ print "run | Run file: run a.bas"
+ print "getfile | Get file: getfile a.txt"
+ print "exit | Exit console"
+ print "format | Quickformat of flash file system"
+ print "info | Print system information"
+ print "setpin | Set pin to high or low: setpin 13 0 | setpin 13 1
+ print "getpin | Get pin level. Returns high or low: getpin 10
+ print "analogwrite | Set pin to 0 to 255: analogwrite 13 128
+ print "analogread | Get ADC value of pin: analogread 10
+ print
+ print "Absolute paths start with /"
+ print "Relative paths start without /"
+ print
+end
+
+sub cmd_setpin(PinNumber, level)
+ local Pin
+ PinNumber = val(PinNumber)
+ level = val(level)
+ Pin = teensy.openDigitalOutput(PinNumber)
+ Pin.write(level)
+end
+
+sub cmd_getpin(PinNumber)
+ local Pin
+ PinNumber = val(PinNumber)
+ Pin = teensy.openDigitalInput(PinNumber)
+ print Pin.read()
+end
+
+sub cmd_analogwrite(PinNumber, level)
+ local Pin
+ PinNumber = val(PinNumber)
+ level = val(level)
+ Pin = teensy.openAnalogOutput(PinNumber)
+ Pin.write(level)
+end
+
+sub cmd_analogread(PinNumber)
+ local Pin
+ PinNumber = val(PinNumber)
+ Pin = teensy.openAnalogInput(PinNumber)
+ print Pin.read()
+end
+
+sub cmd_info()
+ local RAM, FileSystem
+ RAM = teensy.free()
+ FileSystem = fs.free()
+ print "\n\e[1mMemory usage\e[0m"
+ print "STACK free : "; RAM[0]; " Bytes"
+ print "HEAP free : "; RAM[1]; " Bytes"
+ print "FLASH used : "; FileSystem[0]; " Bytes"
+ print "FLASH total: "; FileSystem[1]; " Bytes"
+ print "SD used : "; FileSystem[2]; " Bytes"
+ print "SD total: "; FileSystem[3]; " Bytes"
+ print "\e[1mCPU\e[0m"
+ print "TEMP : "; teensy.GetTemp(); " °C"
+ print "SPEED : "; teensy.GetCPUSpeed(); " MHz"
+end
\ No newline at end of file
diff --git a/src/platform/teensy/samples/fs_copy_file.bas b/src/platform/teensy/samples/fs_copy_file.bas
new file mode 100644
index 00000000..a36be04e
--- /dev/null
+++ b/src/platform/teensy/samples/fs_copy_file.bas
@@ -0,0 +1,52 @@
+' Example for copying a file from flash to SD card
+
+import teensy
+
+const FS_READ = 0
+const FS_WRITE = 1
+
+fs = teensy.fs
+
+print "1. Create a test-file"
+print " Open file for writing"
+file1 = fs.open("flash:/test.txt", FS_WRITE)
+print " Remove file content (make file empty)"
+file1.truncate()
+print " Write strings to file"
+file1.write("test1\n")
+print " "; "test1"
+file1.write("test2\n")
+print " "; "test2"
+file1.write("test3\n")
+print " "; "test3"
+print " Flush buffer (force writing)"
+file1.flush()
+print " Close test file"
+file1.close()
+
+print "2. Copy test-file from flash to sd"
+print " Open new file on sd"
+file_sd = fs.open("sd:/test.txt", FS_WRITE)
+print " Remove file content (make file empty)"
+file_sd.truncate()
+print " Open test-file on flash"
+file_flash = fs.open("flash:/test.txt", FS_READ)
+print " Read data from flash and write to sd"
+while(file_flash.available())
+ s = file_flash.read(1) ' read one byte
+ file_sd.write(s)
+wend
+print " Close files"
+file_flash.close()
+file_sd.close()
+
+print "3. Print content of copied file"
+print " Open file on sd"
+file_sd = fs.open("sd:/test.txt", FS_READ)
+print " Read data:"
+while(file_sd.available())
+ s = file_sd.read() ' read one line
+ print " "; s
+wend
+print " Close file"
+file_sd.close()
diff --git a/src/platform/teensy/samples/fs_flash_basic_io.bas b/src/platform/teensy/samples/fs_flash_basic_io.bas
new file mode 100644
index 00000000..541e8842
--- /dev/null
+++ b/src/platform/teensy/samples/fs_flash_basic_io.bas
@@ -0,0 +1,58 @@
+' Example for flash file access
+
+import teensy
+
+const FS_READ = 0
+const FS_WRITE = 1
+
+fs = teensy.fs
+
+'print "format flash"
+'fs.quickformat()
+
+print "1. Free space"
+r = fs.free()
+print " Flash used size: ", r[0]
+print " Flash total size: ", r[1]
+
+print "2. Create directory"
+fs.mkdir("flash:/TEST")
+print " flash:/Test exists: "; fs.exists("flash:/TEST")
+
+print "3. Open file for writing"
+file1 = fs.open("flash:/test.txt", FS_WRITE)
+print " Remove file content (make file empty)"
+file1.truncate()
+print " Write string to file"
+file1.write("test1\n")
+file1.write("test2\n")
+file1.write("test3\n")
+print " Flush buffer (force writing)"
+file1.flush()
+print " Close file"
+file1.close()
+
+print "4. Read from file"
+file2 = fs.open("flash:/test.txt", FS_READ)
+size = file2.size()
+print " Size of test.txt: "; size
+print " Content of test.txt: "
+while(file2.available())
+ s = file2.read()
+ print " "; s
+wend
+
+print " Goto position 1 in file"
+file2.seek(1)
+print " Get current position"
+print " "; file2.position()
+print " Read one line from current position"
+print " "; file2.read()
+
+file2.close()
+
+print "5. Move file"
+fs.rename("flash:/test.txt", "flash:/test2.txt")
+
+print "6. Remove file"
+fs.remove("flash:/test2.txt")
diff --git a/src/platform/teensy/samples/fs_flash_list_files.bas b/src/platform/teensy/samples/fs_flash_list_files.bas
new file mode 100644
index 00000000..9cd8312a
--- /dev/null
+++ b/src/platform/teensy/samples/fs_flash_list_files.bas
@@ -0,0 +1,22 @@
+' Example for listing files in a directory of flash memory
+
+import teensy
+
+const FS_READ = 0
+const FS_WRITE = 1
+
+fs = teensy.fs
+
+file = fs.open("flash:/")
+
+while(1)
+ s = ""
+ name = file.getNextFilename()
+ if(name == 0) then exit
+
+ file2 = fs.open(name)
+ if(file2.isDirectory()) then s = "/"
+ file2.close()
+ print name; s
+wend
+
diff --git a/src/platform/teensy/samples/fs_sd_basic_io.bas b/src/platform/teensy/samples/fs_sd_basic_io.bas
new file mode 100644
index 00000000..fa3d7ddd
--- /dev/null
+++ b/src/platform/teensy/samples/fs_sd_basic_io.bas
@@ -0,0 +1,55 @@
+' Example for SD card file access
+
+import teensy
+
+const FS_READ = 0
+const FS_WRITE = 1
+
+fs = teensy.fs
+
+print "1. Free space"
+r = fs.free()
+print " SD used size: ", r[2]
+print " SD total size: ", r[3]
+
+print "2. Create directory"
+fs.mkdir("sd:/TEST")
+print " sd:/Test exists: "; fs.exists("sd:/TEST")
+
+print "3. Open file for writing"
+file1 = fs.open("sd:/test.txt", FS_WRITE)
+print " Remove file content (make file empty)"
+file1.truncate()
+print " Write string to file"
+file1.write("sdtest1\n")
+file1.write("sdtest2\n")
+file1.write("sdtest3\n")
+print " Flush buffer (force writing)"
+file1.flush()
+print " Close file"
+file1.close()
+
+print "4. Read from file"
+file2 = fs.open("sd:/test.txt", FS_READ)
+size = file2.size()
+print " Size of test.txt: "; size
+print " Content of test.txt: "
+while(file2.available())
+ s = file2.read()
+ print " "; s
+wend
+
+print " Goto position 1 in file"
+file2.seek(1)
+print " Get current position"
+print " "; file2.position()
+print " Read one line from current position"
+print " "; file2.read()
+
+file2.close()
+
+print "5. Move file"
+fs.rename("sd:/test.txt", "sd:/test2.txt")
+
+print "6. Remove file"
+fs.remove("sd:/test2.txt")
diff --git a/src/platform/teensy/samples/hd44780.bas b/src/platform/teensy/samples/hd44780.bas
new file mode 100644
index 00000000..e4bb8965
--- /dev/null
+++ b/src/platform/teensy/samples/hd44780.bas
@@ -0,0 +1,218 @@
+' HD44780 - Text LCD
+' ==================
+'
+' This example demonstrates how to use the alphanumeric
+' dot matrix liquid crystal display HD44780.
+'
+' Connect the LCD to the Teensy board:
+'
+' -------- -------- 1 (GND)
+' TEENSY | |HD44780 |
+' 5 |-------|11 (DB4) ---
+' 4 |-------|12 (DB5) | |
+' 3 |-------|13 (DB6) |10K|<---3 (VEE)
+' 2 |-------|14 (DB7) | |
+' GND |-------| 5 (RW) ---
+' 1 |-------| 6 (E) |
+' 0 |-------| 4 (RS) 2 (VIN)
+' Vin |-------| 2 (VIN)
+' GND |-------| 1 (GND)
+' -------- --------
+'
+' A potentiometer needs to be connected to the display
+' to control the contrast of the display. If the display
+' has a background light, connect power according to the
+' data sheet to the pins 15 and 16.
+'
+' Edit Init() according to your display. Initial setting are:
+' - Display with 2 lines
+' - Cursor off
+' - Blinking off
+' - 5x7 font
+'
+' Code based on https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
+
+'#########################################################
+'# Constant definition #
+'#########################################################
+
+const LCD_CLEAR_DISPLAY = 0x01
+const LCD_CURSOR_HOME = 0x02
+
+const LCD_SET_ENTRY = 0x04
+const LCD_ENTRY_DECREASE = 0x00
+const LCD_ENTRY_INCREASE = 0x02
+const LCD_ENTRY_NOSHIFT = 0x00
+const LCD_ENTRY_SHIFT = 0x01
+
+const LCD_SET_DISPLAY = 0x08
+const LCD_DISPLAY_OFF = 0x00
+const LCD_DISPLAY_ON = 0x04
+const LCD_CURSOR_OFF = 0x00
+const LCD_CURSOR_ON = 0x02
+const LCD_BLINKING_OFF = 0x00
+const LCD_BLINKING_ON = 0x01
+
+const LCD_SET_SHIFT = 0x10
+const LCD_CURSOR_MOVE = 0x00
+const LCD_DISPLAY_SHIFT = 0x08
+const LCD_SHIFT_LEFT = 0x00
+const LCD_SHIFT_RIGHT = 0x04
+
+const LCD_SET_FUNCTION = 0x20
+const LCD_FUNCTION_4BIT = 0x00
+const LCD_FUNCTION_8BIT = 0x10
+const LCD_FUNCTION_1LINE = 0x00
+const LCD_FUNCTION_2LINE = 0x08
+const LCD_FUNCTION_5X7 = 0x00
+const LCD_FUNCTION_5X10 = 0x04
+
+const LCD_SOFT_RESET = 0x30
+
+const LCD_SET_CGADR = 0x40
+const LCD_SET_DDADR = 0x80
+const LCD_DDADR_LINE1 = 0x00
+const LCD_DDADR_LINE2 = 0x40
+const LCD_DDADR_LINE3 = 0x10
+const LCD_DDADR_LINE4 = 0x50
+
+'#########################################################
+'# Main program #
+'#########################################################
+
+import teensy
+
+LCD_Init(0,1,2,3,4,5)
+
+LCD_Write(" Hello World")
+LCD_Locate(1,2)
+LCD_Write("-= SmallBASIC =-")
+print "Done"
+
+end
+
+
+'#########################################################
+'# Functions and subs #
+'#########################################################
+
+sub LCD_Init(PinRS, PinE, PinDB4, PinDB5, PinDB6, PinDB7)
+ Print "Connect to HD44780"
+ RS = teensy.openDigitalOutput(PinRS)
+ E = teensy.openDigitalOutput(PinE)
+ DB4 = teensy.openDigitalOutput(PinDB4)
+ DB5 = teensy.openDigitalOutput(PinDB5)
+ DB6 = teensy.openDigitalOutput(PinDB6)
+ DB7 = teensy.openDigitalOutput(PinDB7)
+ Print "Connection established"
+
+ RS.write(0)
+ E.write(0)
+ DB4.write(0)
+ DB5.write(0)
+ DB6.write(0)
+ DB7.write(0)
+
+ delay(50)
+
+ ' Send soft-reset 3 time to initialize LCD
+ Send4Bit(LCD_SOFT_RESET)
+ delay(5)
+ SendEnable()
+ delay(1)
+ SendEnable()
+ delay(1)
+
+ ' Set 4-bit mode
+ Send4Bit(LCD_SET_FUNCTION BOR LCD_FUNCTION_4BIT)
+ delay(5)
+
+ ' 2 lines and 5x7 pixel in 4 bit mode
+ SendCommand(LCD_SET_FUNCTION BOR LCD_FUNCTION_4BIT BOR LCD_FUNCTION_2LINE BOR LCD_FUNCTION_5X7)
+ ' Display on, cursor off and blinking off
+ SendCommand(LCD_SET_DISPLAY BOR LCD_DISPLAY_ON BOR LCD_CURSOR_OFF BOR LCD_BLINKING_OFF)
+ ' Cursor increment no scrolling
+ SendCommand(LCD_SET_ENTRY BOR LCD_ENTRY_INCREASE BOR LCD_ENTRY_NOSHIFT)
+
+ LCD_Cls()
+end
+
+sub LCD_Write(Text)
+ ' Write characters to lcd
+ local length, t
+ length = len(Text)
+
+ for i = 1 to length
+ t = asc(mid(text, i, 1))
+ SendData(t)
+ next
+end
+
+sub LCD_Cls()
+ SendCommand(LCD_CLEAR_DISPLAY)
+ SendCommand(LCD_CURSOR_HOME)
+end
+
+sub LCD_Off()
+ SendCommand(LCD_SET_DISPLAY BOR LCD_DISPLAY_OFF)
+end
+
+sub LCD_On()
+ ' Display on, cursor off and blinking off
+ SendCommand(LCD_SET_DISPLAY BOR LCD_DISPLAY_ON BOR LCD_CURSOR_OFF BOR LCD_BLINKING_OFF)
+end
+
+sub LCD_Locate(x, y)
+ local dat
+
+ if(x < 1) then x == 1
+
+ select case y
+ case 1 ' 1. line
+ dat = LCD_SET_DDADR + LCD_DDADR_LINE1 + x - 1
+ case 2 ' 2. line
+ dat = LCD_SET_DDADR + LCD_DDADR_LINE2 + x - 1
+ case 3 ' 3. line
+ dat = LCD_SET_DDADR + LCD_DDADR_LINE3 + x - 1
+ case 4 ' 4. line
+ dat = LCD_SET_DDADR + LCD_DDADR_LINE4 + x - 1
+ case else
+ return
+ end select
+
+ SendCommand(dat)
+end
+
+sub SendCommand(cmd)
+ RS.write(0)
+ SendByte(cmd)
+end
+
+sub SendData(dat)
+ RS.write(1)
+ SendByte(dat)
+end
+
+sub SendEnable()
+ E.write(1)
+ delay(1)
+ E.write(0)
+ delay(1)
+end
+
+sub SendByte(byte)
+ Send4Bit(byte) ' Send high bits first
+ Send4Bit(byte lshift 4) ' Send low bits
+end
+
+sub Send4Bit(byte)
+ DB7.write(GetBit(byte, 7))
+ DB6.write(GetBit(byte, 6))
+ DB5.write(GetBit(byte, 5))
+ DB4.write(GetBit(byte, 4))
+ SendEnable()
+end
+
+func GetBit(value, bit)
+ return (value rshift bit) BAND 1
+end
\ No newline at end of file
diff --git a/src/platform/teensy/samples/i2c_bh1750.bas b/src/platform/teensy/samples/i2c_bh1750.bas
index 5dd2d24d..ffa23590 100644
--- a/src/platform/teensy/samples/i2c_bh1750.bas
+++ b/src/platform/teensy/samples/i2c_bh1750.bas
@@ -1,3 +1,17 @@
+' I2C: BH1750 - Ambient Light Sensor
+' =====================================================
+'
+' This example demonstrates how to use a BH1750 ambient
+' light sensor with the I2C interface.
+'
+' --------------- ----------
+' Teensy | | BH1750
+' 3.3V |-------| VCC
+' PIN 17 (SDA1) |-------| SDA
+' PIN 16 (SCL1) |-------| SCL
+' GND |-------| GND
+'---------------- ---------
+
import teensy
const ADDRESS = 0x23
diff --git a/src/platform/teensy/samples/i2c_bmp180.bas b/src/platform/teensy/samples/i2c_bmp180.bas
index 095a5c93..67ffc80d 100644
--- a/src/platform/teensy/samples/i2c_bmp180.bas
+++ b/src/platform/teensy/samples/i2c_bmp180.bas
@@ -1,3 +1,17 @@
+' I2C: BMP180 - Pressure and temperature sensor
+' =====================================================
+'
+' This example demonstrates how to use a BMP180
+' pressure and temperature sensor with the I2C interface.
+'
+' --------------- ----------
+' Teensy | | BMP180
+' 3.3V |-------| VIN
+' PIN 17 (SDA1) |-------| SDA
+' PIN 16 (SCL1) |-------| SCL
+' GND |-------| GND
+'---------------- ---------
+
import teensy
const ADDRESS = 0x77
diff --git a/src/platform/teensy/samples/i2c_mpu6050.bas b/src/platform/teensy/samples/i2c_mpu6050.bas
new file mode 100644
index 00000000..aaaa79ca
--- /dev/null
+++ b/src/platform/teensy/samples/i2c_mpu6050.bas
@@ -0,0 +1,201 @@
+' MPU6050 - I2C accelerometer and gyroscope
+'
+' Pins:
+' TEENSY MPU6050
+' 16 SCL1 --> SCL
+' 17 SDA1 --> SDA
+' 3.3V --> VCC
+' GND --> GND
+
+import teensy
+
+const ADDRESS = 0x68
+
+Init()
+
+currentTime = ticks()
+lastUpdate = ticks()
+
+while(1)
+ ' Read accelerometer data
+ Accel = GetAcceleration()
+ AccX = Accel[0]
+ AccY = Accel[1]
+ AccZ = Accel[2]
+
+ ' Get delta time
+ previousTime = currentTime
+ currentTime = ticks()
+ dt = (currentTime - previousTime) / 1000
+
+ ' Read gyroscope data
+ Gyro = GetGyroscope()
+ GyroX = Gyro[0]
+ GyroY = Gyro[1]
+ GyroZ = Gyro[2]
+
+ ' Calc roll and pitch using acceleration sensor
+ AccRoll = atan2(AccY, AccZ) * 180 / PI
+ AccPitch = atan2(-AccX, sqr(AccY^2 + AccZ^2)) * 180/PI
+
+ ' Calc roll and pitch unsing gyroscope and accelerometer to reduce noise and cancel drift
+ roll = 0.98 * (roll + GyroX * dt) + 0.02 * AccRoll
+ pitch = 0.98 * (pitch + GyroY * dt) + 0.02 * AccPitch
+
+ ' Display every 500ms
+ if(ticks() - lastUpdate > 500)
+ print "Roll : "; round(roll, 2), " Pitch : "; round(pitch, 2), " Temperature: "; round(GetTemperature(),1); "°C"
+ ' uncomment to see roll and pitch measured with accelerometer only
+ ' print "AccRoll : "; round(AccRoll, 2), " AccPitch: "; round(AccPitch, 2)
+ lastUpdate = ticks()
+ endif
+wend
+
+' #### Functions #############################################
+
+sub Init()
+ local buffer, Who_am_I
+
+ Print "Open I2C...";
+ const I2C = teensy.OpenI2C(1) ' use I2C pins 16 and 17
+ Print "Opened"
+
+ ' Test if sensor is present
+ I2C.write(ADDRESS, 0x75)
+ Who_am_I = I2C.read(ADDRESS, 1)
+ if(Who_am_I != 0x68 AND Who_am_I != 0x69)
+ print "Error: MPU6050 WHO_AM_I value wrong"
+ stop
+ endif
+
+ ' Set SMPLRT_DIV to 0
+ ' Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV)
+ buffer = [0x19, 0]
+ I2C.write(ADDRESS, buffer)
+
+ ' MPU config
+ ' external Frame Synchronization disabled
+ buffer = [0x1A, 0]
+ I2C.write(ADDRESS, buffer)
+
+ GyroscopeConfig(250)
+ AccelerationConfig(2)
+
+ ' Turn on
+ buffer = [0x6B, 0x01]
+ I2C.write(ADDRESS, buffer)
+end
+
+func short(dat)
+ if dat > 32767 then
+ return dat - 65536
+ else
+ return dat
+ endif
+end
+
+func GetAcceleration()
+ local buffer, AccX, AccY, AccZ
+ dim buffer[5]
+
+ I2C.write(ADDRESS, 0x3B)
+ buffer = I2C.read(ADDRESS, 6)
+
+ AccX = short((buffer[0] lshift 8) BOR buffer[1]) / AccelerationLSBSensitivity
+ AccY = short((buffer[2] lshift 8) BOR buffer[3]) / AccelerationLSBSensitivity
+ AccZ = short((buffer[4] lshift 8) BOR buffer[5]) / AccelerationLSBSensitivity
+
+ return [AccX, AccY, AccZ]
+end
+
+func GetGyroscope()
+ local buffer, GyroX, GyroY, GyroZ
+ dim buffer[5]
+
+ I2C.write(ADDRESS, 0x43)
+ buffer = I2C.read(ADDRESS, 6)
+
+ ' Correct the outputs with the error values
+ GyroX = short((buffer[0] lshift 8) BOR buffer[1]) / GyroscopeLSBSensitivity
+ GyroY = short((buffer[2] lshift 8) BOR buffer[3]) / GyroscopeLSBSensitivity
+ GyroZ = short((buffer[4] lshift 8) BOR buffer[5]) / GyroscopeLSBSensitivity
+
+ return [GyroX, GyroY, GyroZ]
+end
+
+func GetTemperature()
+ local buffer, Temp
+ dim buffer[1]
+
+ I2C.write(ADDRESS, 0x41)
+ buffer = I2C.read(ADDRESS, 2)
+
+ Temp = short((buffer[0] lshift 8) BOR buffer[1]) / 340.0 + 36.53
+
+ return Temp
+end
+
+' GyroscopeConfig(range)
+' Sets the full scale range of the Gyroscope. Range can have the
+' values 250, 500, 1000, or 2000 in °/s.
+sub GyroscopeConfig(range)
+ local Setting, buffer
+ dim buffer[1]
+
+ select case range
+ case 250
+ Setting = 0x00
+ GyroscopeLSBSensitivity = 131.0
+ case 500
+ Setting = 0x08
+ GyroscopeLSBSensitivity = 65.5
+ case 1000
+ Setting = 0x10
+ GyroscopeLSBSensitivity = 32.8
+ case 2000
+ Setting = 0x18
+ GyroscopeLSBSensitivity = 16.4
+ case else
+ Setting = 0x00
+ GyroscopeLSBSensitivity = 131.0
+ end select
+
+ buffer[0] = 0x1B
+ buffer[1] = Setting
+ I2C.write(ADDRESS, buffer)
+end
+
+' Accelerometer Configuration
+' AccelerationConfig(range)
+' Sets the full scale range of the Accelerometer. Range can have the
+' values 2, 4, 8, or 16, which corresponds to the following g-force
+' 2 -> 2g
+' 4 -> 4g
+' 8 -> 8g
+' 16 -> 16g
+sub AccelerationConfig(range)
+ local setting, buffer
+ dim buffer[1]
+
+ select case range
+ case 2
+ Setting = 0x00
+ AccelerationLSBSensitivity = 16384
+ case 4
+ Setting = 0x08
+ AccelerationLSBSensitivity = 8192
+ case 8
+ Setting = 0x10
+ AccelerationLSBSensitivity = 4096
+ case 16
+ Setting = 0x18
+ AccelerationLSBSensitivity = 2048
+ case else
+ Setting = 0x00
+ AccelerationLSBSensitivity = 16384
+ end select
+
+ buffer[0] = 0x1C
+ buffer[1] = Setting
+ I2C.write(ADDRESS, buffer)
+end
\ No newline at end of file
diff --git a/src/platform/teensy/samples/pwm_led.bas b/src/platform/teensy/samples/io_analog_pwm_led.bas
similarity index 100%
rename from src/platform/teensy/samples/pwm_led.bas
rename to src/platform/teensy/samples/io_analog_pwm_led.bas
diff --git a/src/platform/teensy/samples/pwm_led_2.bas b/src/platform/teensy/samples/io_analog_pwm_led_2.bas
similarity index 100%
rename from src/platform/teensy/samples/pwm_led_2.bas
rename to src/platform/teensy/samples/io_analog_pwm_led_2.bas
diff --git a/src/platform/teensy/samples/io_analog_read.bas b/src/platform/teensy/samples/io_analog_read.bas
new file mode 100644
index 00000000..616bcbd6
--- /dev/null
+++ b/src/platform/teensy/samples/io_analog_read.bas
@@ -0,0 +1,23 @@
+' Analog IO - Potentiometer
+' =====================================================
+'
+' This example demonstrates how to read an analog
+' voltage using a potentiometer.
+'
+' ----------
+' TEENSY |
+' 3.3V |-------- 1 ---/\/\/\--- 3 --
+' | | |
+' PIN 23 |---------------- 2 |
+' | |
+' GND |----------------------------
+' ----------
+
+import teensy
+
+const Potentiometer = teensy.openAnalogInput(23)
+
+for ii = 1 to 50
+ print ii, Potentiometer.read()
+ delay(500)
+next
\ No newline at end of file
diff --git a/src/platform/teensy/samples/led.bas b/src/platform/teensy/samples/io_digital_led.bas
similarity index 100%
rename from src/platform/teensy/samples/led.bas
rename to src/platform/teensy/samples/io_digital_led.bas
diff --git a/src/platform/teensy/samples/io_digital_read.bas b/src/platform/teensy/samples/io_digital_read.bas
new file mode 100644
index 00000000..a4efe246
--- /dev/null
+++ b/src/platform/teensy/samples/io_digital_read.bas
@@ -0,0 +1,19 @@
+' Digital IO - Push Button
+' =====================================================
+'
+' This example demonstrates how to use a push button.
+'
+' ---------- ----------
+' TEENSY | | Button
+' PIN 0 |-------| Pin 1
+' GND |-------| Pin 2
+' ---------- ---------
+
+import teensy
+
+const Pushbutton = teensy.openDigitalInput(0)
+
+for ii = 1 to 20
+ print ii, Pushbutton.read()
+ delay(500)
+next
diff --git a/src/platform/teensy/samples/serialprint.bas b/src/platform/teensy/samples/serial_print.bas
similarity index 100%
rename from src/platform/teensy/samples/serialprint.bas
rename to src/platform/teensy/samples/serial_print.bas
diff --git a/src/platform/teensy/samples/serialUSB_receive_bytes.bas b/src/platform/teensy/samples/serial_receive_bytes.bas
similarity index 69%
rename from src/platform/teensy/samples/serialUSB_receive_bytes.bas
rename to src/platform/teensy/samples/serial_receive_bytes.bas
index 783dd860..9851daf0 100644
--- a/src/platform/teensy/samples/serialUSB_receive_bytes.bas
+++ b/src/platform/teensy/samples/serial_receive_bytes.bas
@@ -2,18 +2,22 @@ import teensy
const usbSerial = teensy.openSerial()
const BuiltInLED = teensy.openDigitalOutput(13)
-value = 0
teensy.SetInteractive(1)
+print
+print "Receive two bytes over serial connection"
+print "Send Q1 to exit program"
+print
+
while(1)
if(usbSerial.ready()) then
- s = usbSerial.read(2)
+ s = usbSerial.receive(2)
print s
if(len(s) == 2) then
if(s[0] == 81) then ' if first Byte is a Q
- print "Quit program."
- stop
+ print "Quit program."
+ stop
endif
endif
else
@@ -25,5 +29,3 @@ while(1)
BuiltInLED.write(0)
delay(25)
wend
-
-
diff --git a/src/platform/teensy/samples/serialUSB_receive_string.bas b/src/platform/teensy/samples/serial_receive_string.bas
similarity index 75%
rename from src/platform/teensy/samples/serialUSB_receive_string.bas
rename to src/platform/teensy/samples/serial_receive_string.bas
index 11e9e906..5e76f772 100644
--- a/src/platform/teensy/samples/serialUSB_receive_string.bas
+++ b/src/platform/teensy/samples/serial_receive_string.bas
@@ -6,6 +6,13 @@ value = 0
teensy.SetInteractive(1)
+print
+print "Receive a string over serial connection"
+print "Send following strings: "
+print "led -> turn onboard LED on or off"
+print "quit -> exit program"
+print
+
while(1)
if(usbSerial.ready()) then
s = usbSerial.receive()
diff --git a/src/platform/teensy/setup.sh b/src/platform/teensy/setup.sh
index 294867ff..87f772d8 100755
--- a/src/platform/teensy/setup.sh
+++ b/src/platform/teensy/setup.sh
@@ -3,25 +3,26 @@
DIR=`pwd`
(mkdir -p build/modules && cd build/modules && \
- git clone https://github.com/PaulStoffregen/cores.git && \
- git clone https://github.com/PaulStoffregen/SPI.git && \
- git clone https://github.com/PaulStoffregen/Wire.git && \
- git clone https://github.com/PaulStoffregen/USBHost_t36.git && \
+ git clone https://github.com/PaulStoffregen/cores.git && \
+ git clone https://github.com/PaulStoffregen/SPI.git && \
+ git clone https://github.com/PaulStoffregen/Wire.git && \
+ git clone https://github.com/PaulStoffregen/USBHost_t36.git && \
git clone https://github.com/PaulStoffregen/SD.git && \
- git clone https://github.com/PaulStoffregen/SdFat.git && \
- git clone https://github.com/PaulStoffregen/teensy_loader_cli.git && \
- git clone https://github.com/pedvide/ADC && \
- git clone https://github.com/ARM-software/CMSIS_5.git && \
- git clone https://github.com/ARM-software/CMSIS-DSP.git && \
- git clone https://github.com/adafruit/Adafruit_SSD1306.git && \
- git clone https://github.com/adafruit/Adafruit-GFX-Library && \
- git clone https://github.com/adafruit/Adafruit_BusIO)
+ git clone https://github.com/PaulStoffregen/SdFat.git && \
+ git clone https://github.com/PaulStoffregen/teensy_loader_cli.git && \
+ git clone https://github.com/pedvide/ADC && \
+ git clone https://github.com/ARM-software/CMSIS_5.git && \
+ git clone https://github.com/ARM-software/CMSIS-DSP.git && \
+ git clone https://github.com/adafruit/Adafruit_SSD1306.git && \
+ git clone https://github.com/adafruit/Adafruit-GFX-Library && \
+ git clone https://github.com/adafruit/Adafruit_BusIO && \
+ git clone https://github.com/PaulStoffregen/LittleFS)
(cd build/modules/CMSIS-DSP && \
- mkdir -p build && \
- cd build && \
- cmake .. -Wno-dev -DARM_CPU=cortex-m7 -DUSE_FPU=ON -DFLOAT_ABI=hard -DCMAKE_C_FLAGS="-I${DIR}/build/modules/CMSIS_5/CMSIS/Core/Include" && \
- cmake --build .)
+ mkdir -p build && \
+ cd build && \
+ cmake .. -Wno-dev -DARM_CPU=cortex-m7 -DUSE_FPU=ON -DFLOAT_ABI=hard -DCMAKE_C_FLAGS="-I${DIR}/build/modules/CMSIS_5/CMSIS/Core/Include" && \
+ cmake --build .)
(cd build/modules/teensy_loader_cli && make)
diff --git a/src/platform/teensy/src/fs.cpp b/src/platform/teensy/src/fs.cpp
new file mode 100644
index 00000000..99f59523
--- /dev/null
+++ b/src/platform/teensy/src/fs.cpp
@@ -0,0 +1,370 @@
+// This file is part of SmallBASIC
+//
+// Copyright(C) 2026 Joerg Siebenmorgen
+//
+// This program is distributed under the terms of the GPL v2.0 or later
+// Download the GNU Public License (GPL) from www.gnu.org
+//
+
+#include
+#include "common/device.h"
+#include "common/pproc.h"
+#include "config.h"
+#include "languages/messages.en.h"
+#include "include/var_map.h"
+#include "module.h"
+#include
+#include
+#include
+
+extern LittleFS_Program flashfs;
+
+std::vector fileStack;
+
+/*
+ * close file
+ */
+static int cmd_close(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ fileStack[self->v.m.id].flush();
+ fileStack[self->v.m.id].close();
+ return 1;
+}
+
+/*
+ * if current file is a directory, getNextFilename() returns
+ * the next filename in the directory
+ */
+static int cmd_getNextFilename(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ File file = fileStack[self->v.m.id].openNextFile();
+ if (!file) {
+ v_setint(retval, 0);
+ return 1;
+ }
+
+ v_setstr(retval, file.name());
+
+ file.close();
+ return 1;
+}
+
+/*
+ * check if file is a directory
+ * isDirectory() returns true or false
+ */
+static int cmd_isDirectory(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ v_setint(retval, fileStack[self->v.m.id].isDirectory());
+ return 1;
+}
+
+/*
+ * return file size
+ */
+static int cmd_size(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ v_setint(retval, fileStack[self->v.m.id].size());
+ return 1;
+}
+
+/*
+ * return current read/write position
+ */
+static int cmd_position(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ v_setint(retval, fileStack[self->v.m.id].position());
+ return 1;
+}
+
+/*
+ * set read/write position
+ * seek(pos) -> 'pos' psition in file
+ */
+static int cmd_seek(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ uint64_t pos = get_param_int(argc, args, 0, 0);
+ fileStack[self->v.m.id].seek(pos);
+ return 1;
+}
+
+/*
+ * read from file
+ * 1. read() or read(0) -> read until '\n' and return as string
+ * 2. read(1) -> read one byte and return as integer
+ * 2. read(n) -> read n bytes and return as integer array
+ */
+static int cmd_read(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ uint32_t bytes = get_param_int(argc, args, 0, 0);
+ int size;
+
+ if (bytes == 0) {
+ // Read until '\n' and return as string
+ bytes = CDC_RX_SIZE_480;
+ char buffer[bytes];
+ size = fileStack[self->v.m.id].readBytesUntil('\n', buffer, bytes - 1);
+ buffer[size] = '\0';
+ v_setstr(retval, buffer);
+ } else if (bytes > 1) {
+ // Read number of bytes and return as array
+ v_toarray1(retval, bytes);
+ for (uint32_t ii = 0; ii < bytes; ii++) {
+ v_setint(v_elem(retval, ii), fileStack[self->v.m.id].read());
+ }
+ } else {
+ v_setint(retval, fileStack[self->v.m.id].read());
+ }
+ return 1;
+}
+
+/*
+ * write to file
+ * wrtie(buffer) -> 'buffer' can be integer, string or array
+ */
+static int cmd_write(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ switch (args[0].var_p->type) {
+ case V_INT:{
+ uint8_t value = get_param_int(argc, args, 0, 0);
+ fileStack[self->v.m.id].write(value);
+ }
+ break;
+ case V_STR:{
+ const char *buffer = get_param_str(argc, args, 0, "");
+ fileStack[self->v.m.id].print(buffer);
+ }
+ break;
+ case V_ARRAY:{
+ var_p_t array = args[1].var_p; // Get array
+ if (array->maxdim > 1) {
+ v_setstr(retval, "ERROR: FS: Write requires 1D-array");
+ return 0;
+ }
+ uint32_t bytes = v_ubound(array, 0) - v_lbound(array, 0) + 1;
+ uint8_t *buffer = new uint8_t[bytes];
+ for (uint32_t ii = 0; ii < bytes; ii++) {
+ buffer[ii] = get_array_elem_int(array, ii);
+ }
+ fileStack[self->v.m.id].write(buffer, bytes);
+ delete[]buffer;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+/*
+ * flush buffer and sync file
+ */
+static int cmd_flush(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ fileStack[self->v.m.id].flush();
+ return 1;
+}
+
+/*
+ * convert current file, which might contain data, to an empty file
+ */
+static int cmd_truncate(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ fileStack[self->v.m.id].truncate();
+ fileStack[self->v.m.id].seek(0);
+ return 1;
+}
+
+/*
+ * returns bytes available for reading
+ */
+static int cmd_available(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ v_setint(retval, fileStack[self->v.m.id].available());
+ return 1;
+}
+
+/*
+ * open a file or directory
+ * open(name, mode) -> open file 'name' with rwmode 'mode'; mode = 0 -> read; mode = 1 -> write
+ * open() returns a map
+ */
+static int cmd_open(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ const char *name = get_param_str(argc, args, 0, "flash:");
+ uint8_t mode = get_param_int(argc, args, 1, FILE_READ);
+
+ File file;
+ char *namePtr;
+
+ if (strncmp(name, "flash:", 6) == 0) {
+ namePtr = (char *)name + 6;
+ file = flashfs.open(namePtr, mode);
+ } else if (strncmp(name, "sd:", 3) == 0) {
+ // root directory of SD must be "/", "" will crash
+ if (strlen(name) == 3) {
+ file = SD.open("/", mode);
+ } else {
+ namePtr = (char *)name + 3;
+ file = SD.open(namePtr, mode);
+ }
+ } else {
+ file = flashfs.open(name, mode);
+ }
+
+ if (!file) {
+ v_setint(retval, 0);
+ return 1;
+ }
+
+ fileStack.push_back(file);
+
+ map_init(retval);
+ retval->v.m.id = fileStack.size() - 1;
+ if (file.isDirectory()) {
+ v_create_callback(retval, "getNextFilename", cmd_getNextFilename);
+ } else {
+ if (mode == FILE_READ) {
+ v_create_callback(retval, "read", cmd_read);
+ v_create_callback(retval, "available", cmd_available);
+ } else if (mode == FILE_WRITE) {
+ v_create_callback(retval, "write", cmd_write);
+ v_create_callback(retval, "truncate", cmd_truncate);
+ v_create_callback(retval, "flush", cmd_flush);
+ }
+ v_create_callback(retval, "size", cmd_size);
+ v_create_callback(retval, "position", cmd_position);
+ v_create_callback(retval, "seek", cmd_seek);
+ }
+ v_create_callback(retval, "isDirectory", cmd_isDirectory);
+ v_create_callback(retval, "close", cmd_close);
+
+ return 1;
+}
+
+/*
+ * create directory
+ * mkdir(name) -> 'name' directory name
+ */
+
+static int cmd_mkdir(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ const char *name = get_param_str(argc, args, 0, "");
+ char *namePtr;
+
+ if (strncmp(name, "flash:", 6) == 0) {
+ namePtr = (char *)name + 6;
+ v_setint(retval, flashfs.mkdir(namePtr));
+ return 1;
+ }
+ if (strncmp(name, "sd:", 3) == 0) {
+ namePtr = (char *)name + 3;
+ v_setint(retval, SD.mkdir(namePtr));
+ return 1;
+ }
+
+ v_setint(retval, flashfs.mkdir(name));
+ return 1;
+}
+
+/*
+ * Quickformate flash memory
+ */
+static int cmd_quickFormat(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ v_setint(retval, flashfs.quickFormat());
+ return 1;
+}
+
+/*
+ * check if file or directory exists
+ * returns true or false
+ */
+static int cmd_exists(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ const char *name = get_param_str(argc, args, 0, "");
+ char *namePtr;
+
+ if (strncmp(name, "flash:", 6) == 0) {
+ namePtr = (char *)name + 6;
+ v_setint(retval, flashfs.exists(namePtr));
+ return 1;
+ }
+ if (strncmp(name, "sd:", 3) == 0) {
+ namePtr = (char *)name + 3;
+ v_setint(retval, SD.exists(namePtr));
+ return 1;
+ }
+
+ v_setint(retval, flashfs.exists(name));
+ return 1;
+}
+
+/*
+ * rename a file or directory
+ * rename(name_old, name_new) -> 'name_old' current name; 'name_new' new name
+ */
+static int cmd_rename(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ const char *nameOld = get_param_str(argc, args, 0, "");
+ const char *nameNew = get_param_str(argc, args, 1, "");
+ char *nameOldPtr;
+ char *nameNewPtr;
+
+ if (strncmp(nameOld, "flash:", 6) == 0 && strncmp(nameNew, "flash:", 6) == 0) {
+ nameOldPtr = (char *)nameOld + 6;
+ nameNewPtr = (char *)nameNew + 6;
+ v_setint(retval, flashfs.rename(nameOldPtr, nameNewPtr));
+ return 1;
+ }
+ if (strncmp(nameOld, "sd:", 3) == 0 && strncmp(nameNew, "sd:", 3) == 0) {
+ nameOldPtr = (char *)nameOld + 3;
+ nameNewPtr = (char *)nameNew + 3;
+ v_setint(retval, SD.rename(nameOldPtr, nameNewPtr));
+ return 1;
+ }
+
+ v_setint(retval, flashfs.rename(nameOld, nameNew));
+ return 1;
+}
+
+/*
+ * remove file or directory
+ * remove(name) -> 'name' file or directory
+ */
+static int cmd_remove(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ const char *name = get_param_str(argc, args, 0, "");
+ char *namePtr;
+
+ if (strncmp(name, "flash:", 6) == 0) {
+ namePtr = (char *)name + 6;
+ v_setint(retval, flashfs.remove(namePtr));
+ return 1;
+ }
+ if (strncmp(name, "sd:", 3) == 0) {
+ namePtr = (char *)name + 3;
+ v_setint(retval, SD.remove(namePtr));
+ return 1;
+ }
+
+ v_setint(retval, flashfs.remove(name));
+ return 1;
+}
+
+/*
+ * show file system usage
+ * returns an array [FlashUsedSize, FlashTotalSize, SDUsedSize, SDTotalSize]
+ */
+static int cmd_free(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ v_toarray1(retval, 4);
+ v_setint(v_elem(retval, 0), flashfs.usedSize());
+ v_setint(v_elem(retval, 1), flashfs.totalSize());
+ v_setint(v_elem(retval, 2), SD.usedSize());
+ v_setint(v_elem(retval, 3), SD.totalSize());
+ return 1;
+}
+
+int cmd_fs(int argc, slib_par_t *args, var_t *retval) {
+ map_init(retval);
+ v_create_callback(retval, "OPEN", cmd_open);
+ v_create_callback(retval, "QUICKFORMAT", cmd_quickFormat);
+ v_create_callback(retval, "EXISTS", cmd_exists);
+ v_create_callback(retval, "MKDIR", cmd_mkdir);
+ v_create_callback(retval, "RENAME", cmd_rename);
+ v_create_callback(retval, "REMOVE", cmd_remove);
+ v_create_callback(retval, "FREE", cmd_free);
+
+ return 1;
+}
+
+int fs_close(void) {
+ for(File& f : fileStack) {
+ if (f) {
+ f.close();
+ }
+ }
+ return 1;
+}
diff --git a/src/platform/teensy/src/fs.h b/src/platform/teensy/src/fs.h
new file mode 100644
index 00000000..86245fd1
--- /dev/null
+++ b/src/platform/teensy/src/fs.h
@@ -0,0 +1,15 @@
+// This file is part of SmallBASIC
+//
+// Copyright(C) 2001-2025 Chris Warren-Smith.
+// Copyright(C) 2000 Nicholas Christopoulos
+//
+// This program is distributed under the terms of the GPL v2.0 or later
+// Download the GNU Public License (GPL) from www.gnu.org
+//
+
+#pragma once
+
+#include "common/var.h"
+
+int cmd_fs(int argc, slib_par_t *args, var_t *retval);
+int fs_close(void);
diff --git a/src/platform/teensy/src/i2c.cpp b/src/platform/teensy/src/i2c.cpp
new file mode 100644
index 00000000..5bea6242
--- /dev/null
+++ b/src/platform/teensy/src/i2c.cpp
@@ -0,0 +1,154 @@
+// This file is part of SmallBASIC
+//
+// Copyright(C) 2026 Joerg Siebenmorgen
+//
+// This program is distributed under the terms of the GPL v2.0 or later
+// Download the GNU Public License (GPL) from www.gnu.org
+//
+
+#include
+#include "config.h"
+#include "languages/messages.en.h"
+#include "include/var_map.h"
+#include "module.h"
+#include
+
+static TwoWire *getI2C(int interfaceNumber) {
+ TwoWire *result;
+ switch (interfaceNumber) {
+ case 0:
+ result = &Wire;
+ break;
+ case 1:
+ result = &Wire1;
+ break;
+ case 2:
+ result = &Wire2;
+ break;
+ default:
+ result = &Wire;
+ break;
+ }
+ return result;
+}
+
+static int cmd_i2c_write(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ uint8_t address = get_param_int(argc, args, 0, 0);
+ uint8_t stop = get_param_int(argc, args, 2, 1);
+
+ if (address == 0 || argc < 2) {
+ v_setstr(retval, ERR_PARAM);
+ return 0;
+ }
+
+ int interfaceNumber = self->v.m.id;
+ TwoWire *ptrWire;
+ ptrWire = getI2C(interfaceNumber);
+
+ ptrWire->beginTransmission(address);
+
+ switch (args[1].var_p->type) {
+ case V_INT:{
+ int value = get_param_int(argc, args, 1, 0);
+ ptrWire->write(value);
+ }
+ break;
+ case V_STR:{
+ const char *buffer = v_getstr(args[1].var_p);
+ int length = v_strlen(args[1].var_p);
+ ptrWire->write(buffer, length);
+ }
+ break;
+ case V_ARRAY:{
+ var_p_t array = args[1].var_p; // Get array
+ if (array->maxdim > 1) {
+ v_setstr(retval, "ERROR: I2C: Write requires 1D-array");
+ return 0;
+ }
+ uint32_t bytes = v_ubound(array, 0) - v_lbound(array, 0) + 1;
+ uint8_t *buffer = new uint8_t[bytes];
+ for (uint32_t ii = 0; ii < bytes; ii++) {
+ buffer[ii] = get_array_elem_int(array, ii);
+ }
+ ptrWire->write(buffer, bytes);
+ delete[]buffer;
+ }
+ break;
+ }
+
+ if (ptrWire->endTransmission(stop)) {
+ v_setstr(retval, "ERROR I2C: Transmission failed");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int cmd_i2c_read(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ uint8_t address = get_param_int(argc, args, 0, 0);
+ uint32_t bytes = get_param_int(argc, args, 1, 1);
+ uint8_t stop = get_param_int(argc, args, 2, 1);
+
+ if (address == 0) {
+ v_setstr(retval, ERR_PARAM);
+ return 0;
+ }
+
+ int interfaceNumber = self->v.m.id;
+ TwoWire *ptrWire;
+ ptrWire = getI2C(interfaceNumber);
+ ptrWire->requestFrom(address, bytes, stop);
+
+ if (bytes > 1) {
+ v_toarray1(retval, bytes);
+ for (uint32_t ii = 0; ii < bytes; ii++) {
+ v_setint(v_elem(retval, ii), ptrWire->read());
+ }
+ } else {
+ v_setint(retval, ptrWire->read());
+ }
+ return 1;
+}
+
+static int cmd_i2c_setClock(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ uint32_t clockFrequency = get_param_int(argc, args, 0, 100000);
+
+ if (clockFrequency != 100000 && clockFrequency != 400000 && clockFrequency != 1000000) {
+ v_setstr(retval, "ERROR I2C: Clock freuqency not supported");
+ return 0;
+ }
+
+ int interfaceNumber = self->v.m.id;
+ getI2C(interfaceNumber)->setClock(clockFrequency);
+
+ return 1;
+}
+
+int cmd_openi2c(int argc, slib_par_t *args, var_t *retval) {
+ uint8_t interfaceNumber = get_param_int(argc, args, 0, 0);
+ uint8_t pinSDA = get_param_int(argc, args, 1, 0);
+ uint8_t pinSCL = get_param_int(argc, args, 2, 0);
+
+ if (interfaceNumber > 2) {
+ v_setstr(retval, ERR_PARAM);
+ return 0;
+ }
+
+ map_init(retval);
+ v_create_callback(retval, "write", cmd_i2c_write);
+ v_create_callback(retval, "read", cmd_i2c_read);
+ v_create_callback(retval, "setClock", cmd_i2c_setClock);
+ retval->v.m.id = interfaceNumber;
+
+ TwoWire *ptrWire;
+ ptrWire = getI2C(interfaceNumber);
+
+ if (pinSDA > 0 && pinSCL > 0) {
+ ptrWire->setSDA(pinSDA);
+ ptrWire->setSCL(pinSCL);
+ }
+
+ ptrWire->begin();
+
+ return 1;
+}
diff --git a/src/platform/teensy/src/i2c.h b/src/platform/teensy/src/i2c.h
new file mode 100644
index 00000000..64734cfc
--- /dev/null
+++ b/src/platform/teensy/src/i2c.h
@@ -0,0 +1,14 @@
+// This file is part of SmallBASIC
+//
+// Copyright(C) 2001-2025 Chris Warren-Smith.
+// Copyright(C) 2000 Nicholas Christopoulos
+//
+// This program is distributed under the terms of the GPL v2.0 or later
+// Download the GNU Public License (GPL) from www.gnu.org
+//
+
+#pragma once
+
+#include "common/var.h"
+
+int cmd_openi2c(int argc, slib_par_t *args, var_t *retval);
diff --git a/src/platform/teensy/src/main.cpp b/src/platform/teensy/src/main.cpp
index dbc86413..30f5ae1e 100644
--- a/src/platform/teensy/src/main.cpp
+++ b/src/platform/teensy/src/main.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include "common/device.h"
#include "config.h"
#include "common/sbapp.h"
@@ -19,8 +20,10 @@
#define MAIN_BAS "__main_bas__"
#define SERIAL_SD_BAS "__serial_sd_bas__"
+#define PROG_FLASH_SIZE 65536*16
strlib::String buffer;
+LittleFS_Program flashfs;
void *plugin_lib_open(const char *name) {
void *result = nullptr;
@@ -50,6 +53,8 @@ void *plugin_lib_address(void *handle, const char *name) {
result = (void *)pModule->_func_count;
} else if (strcmp(name, "sblib_func_getname") == 0) {
result = (void *)pModule->_func_getname;
+ } else if (strcmp(name, "sblib_close") == 0) {
+ result = (void *)pModule->_close;
}
return result;
}
@@ -93,6 +98,13 @@ void setup() {
opt_verbose = 0;
opt_graphics = 0;
dev_init(0, 0);
+
+ if (!flashfs.begin(PROG_FLASH_SIZE)) {
+ while (1) {
+ dev_print("Error initializing FLASH file system\n");
+ delay(1000);
+ }
+ }
}
void serial_read() {
@@ -171,7 +183,7 @@ void print_error(char *source) {
void interactive_main() {
while (true) {
- dev_print("\r\n\033[30;47mInteractive mode - waiting for data...\033[0m\r\n");
+ dev_print("\r\nWaiting for upload... ");
serial_read();
if (!sbasic_main(SERIAL_SD_BAS)) {
print_error((char *)buffer.c_str());
@@ -179,34 +191,53 @@ void interactive_main() {
}
}
+void executeFile(File *f) {
+ uint32_t fileSize = f->available();
+ char *fileBuffer = new char[fileSize + 1];
+
+ f->read(fileBuffer, fileSize);
+ fileBuffer[fileSize] = '\0';
+ buffer.clear();
+ buffer.append(fileBuffer);
+
+ delete[]fileBuffer;
+
+ if (!sbasic_main(SERIAL_SD_BAS)) {
+ while (!Serial) {
+ delay(250);
+ }
+ dev_print("Error executing MAIN.BAS:\n");
+ print_error((char *)buffer.c_str());
+ } else {
+ dev_print("MAIN.BAS ended\n");
+ }
+}
+
extern "C" int main(void) {
setup();
+ // Start from SD card
if (SD.begin(BUILTIN_SDCARD)) {
File sdFile = SD.open("/MAIN.BAS", FILE_READ);
if (sdFile) {
- uint32_t fileSize = sdFile.available();
- char *bufferSD = new char[fileSize + 1];
-
- sdFile.read(bufferSD, fileSize);
- bufferSD[fileSize] = '\0';
- buffer.clear();
- buffer.append(bufferSD);
-
- delete[]bufferSD;
+ executeFile(&sdFile);
sdFile.close();
+ goto interactive;
+ }
+ }
- if (!sbasic_main(SERIAL_SD_BAS)) {
- while (!Serial) {
- delay(250);
- }
- dev_print("Error executing main.bas from SD card:\n");
- print_error((char *)buffer.c_str());
- } else {
- dev_print("main.bas from SD card ended\n");
- }
+ // Start from LittleFS
+ if (flashfs.exists("/MAIN.BAS")) {
+ File flashFile = flashfs.open("/MAIN.BAS", FILE_READ);
+ if (flashFile) {
+ executeFile(&flashFile);
+ flashFile.close();
+ goto interactive;
}
- } else if (main_bas_len > 0) {
+ }
+
+ // Start from memory
+ if (main_bas_len > 0) {
if (!sbasic_main(MAIN_BAS)) {
while (!Serial) {
delay(250);
@@ -216,7 +247,8 @@ extern "C" int main(void) {
} else {
dev_print("main.bas ended");
}
- } else {
- interactive_main();
}
+
+interactive:
+ interactive_main();
}
diff --git a/src/platform/teensy/src/module.h b/src/platform/teensy/src/module.h
index 07812fa7..f5a95f40 100644
--- a/src/platform/teensy/src/module.h
+++ b/src/platform/teensy/src/module.h
@@ -45,6 +45,7 @@ typedef struct {
sblib_count_fn _proc_count;
sblib_getname_fn _proc_getname;
sblib_free_fn _free;
+ sblib_close_fn _close;
} ModuleConfig;
ModuleConfig *get_teensy_module();
diff --git a/src/platform/teensy/src/pinio.cpp b/src/platform/teensy/src/pinio.cpp
new file mode 100644
index 00000000..1135bee7
--- /dev/null
+++ b/src/platform/teensy/src/pinio.cpp
@@ -0,0 +1,158 @@
+// This file is part of SmallBASIC
+//
+// Copyright(C) 2026 Joerg Siebenmorgen
+//
+// This program is distributed under the terms of the GPL v2.0 or later
+// Download the GNU Public License (GPL) from www.gnu.org
+//
+
+#include
+#include "config.h"
+#include "languages/messages.en.h"
+#include "include/var_map.h"
+#include "module.h"
+
+static void set_pin(var_p_t var, uint8_t pin, uint8_t mode) {
+ map_init(var);
+ var->v.m.id = pin;
+ pinMode(pin, mode);
+}
+
+static bool is_pin(int id) {
+ return id >= 0 && id < CORE_NUM_TOTAL_PINS;
+}
+
+static bool is_pin_object(var_p_t var) {
+ return var != nullptr && v_is_type(var, V_MAP) && is_pin(var->v.m.id);
+}
+
+static int cmd_analoginput_read(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
+ int result = 0;
+ if (argc != 0 || !is_pin_object(self)) {
+ error(retval, "AnalogInput.read", 0);
+ } else {
+ int pin = self->v.m.id;
+ v_setint(retval, analogRead(pin));
+ result = 1;
+ }
+ return result;
+}
+
+int cmd_openanaloginput(int argc, slib_par_t *args, var_t *retval) {
+ int result = 1;
+ int pin = get_param_int(argc, args, 0, -1);
+ if (is_pin(pin)) {
+ set_pin(retval, pin, INPUT);
+ v_create_callback(retval, "read", cmd_analoginput_read);
+ } else {
+ result = 0;
+ }
+ return result;
+}
+
+static int cmd_digitalinput_read(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
+ int result = 0;
+ if (argc != 0 || !is_pin_object(self)) {
+ error(retval, "DigitalInput.read", 0);
+ } else {
+ int pin = self->v.m.id;
+ v_setint(retval, digitalRead(pin));
+ result = 1;
+ }
+ return result;
+}
+
+int cmd_opendigitalinput(int argc, slib_par_t *args, var_t *retval) {
+ int result = 1;
+ int pin = get_param_int(argc, args, 0, -1);
+ uint8_t mode = get_param_int(argc, args, 1, 1);
+ if (mode) {
+ mode = INPUT_PULLUP;
+ } else {
+ mode = INPUT;
+ }
+ if (is_pin(pin)) {
+ set_pin(retval, pin, mode);
+ v_create_callback(retval, "read", cmd_digitalinput_read);
+ result = 1;
+ } else {
+ result = 0;
+ }
+ return result;
+}
+
+static int cmd_digitaloutput_write(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
+ int result = 0;
+ if (argc != 1 || !is_pin_object(self)) {
+ error(retval, "DigitalOutput.write", 1);
+ } else {
+ int pin = self->v.m.id;
+ int value = get_param_int(argc, arg, 0, 0);
+ digitalWrite(pin, value);
+ result = 1;
+ }
+ return result;
+}
+
+int cmd_opendigitaloutput(int argc, slib_par_t *args, var_t *retval) {
+ int result;
+ int pin = get_param_int(argc, args, 0, -1);
+ if (is_pin(pin)) {
+ set_pin(retval, pin, OUTPUT);
+ v_create_callback(retval, "write", cmd_digitaloutput_write);
+ result = 1;
+ } else {
+ result = 0;
+ }
+ return result;
+}
+
+static int cmd_analogoutput_write(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
+ if (argc != 1 || !is_pin_object(self)) {
+ error(retval, "AnalogOutput.write", 1);
+ return 0;
+ } else {
+ int pin = self->v.m.id;
+ int value = get_param_int(argc, arg, 0, 0);
+ analogWrite(pin, value);
+ }
+ return 1;
+}
+
+static int cmd_analogoutput_frequency(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
+ if (argc != 1 || !is_pin_object(self)) {
+ error(retval, "AnalogOutput.frequency", 1);
+ return 0;
+ } else {
+ int pin = self->v.m.id;
+ double value = get_param_num(argc, arg, 0, 0.0);
+ analogWriteFrequency(pin, value);
+ }
+ return 1;
+}
+
+static int cmd_analogoutput_resolution(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
+ if (argc != 1 || !is_pin_object(self)) {
+ error(retval, "AnalogOutput.resolution", 1);
+ return 0;
+ } else {
+ int value = get_param_int(argc, arg, 0, 0);
+ analogWriteResolution(value);
+ }
+ return 1;
+}
+
+int cmd_openanalogoutput(int argc, slib_par_t *args, var_t *retval) {
+ int result;
+ int pin = get_param_int(argc, args, 0, -1);
+ if (is_pin(pin)) {
+ set_pin(retval, pin, OUTPUT);
+ v_create_callback(retval, "write", cmd_analogoutput_write);
+ v_create_callback(retval, "frequency", cmd_analogoutput_frequency);
+ v_create_callback(retval, "resolution", cmd_analogoutput_resolution);
+ result = 1;
+ } else {
+ result = 0;
+ }
+ return result;
+}
diff --git a/src/platform/teensy/src/pinio.h b/src/platform/teensy/src/pinio.h
new file mode 100644
index 00000000..882607d2
--- /dev/null
+++ b/src/platform/teensy/src/pinio.h
@@ -0,0 +1,17 @@
+// This file is part of SmallBASIC
+//
+// Copyright(C) 2001-2025 Chris Warren-Smith.
+// Copyright(C) 2000 Nicholas Christopoulos
+//
+// This program is distributed under the terms of the GPL v2.0 or later
+// Download the GNU Public License (GPL) from www.gnu.org
+//
+
+#pragma once
+
+#include "common/var.h"
+
+int cmd_opendigitalinput(int argc, slib_par_t *args, var_t *retval);
+int cmd_opendigitaloutput(int argc, slib_par_t *args, var_t *retval);
+int cmd_openanaloginput(int argc, slib_par_t *args, var_t *retval);
+int cmd_openanalogoutput(int argc, slib_par_t *args, var_t *retval);
diff --git a/src/platform/teensy/src/serial.cpp b/src/platform/teensy/src/serial.cpp
new file mode 100644
index 00000000..277738ee
--- /dev/null
+++ b/src/platform/teensy/src/serial.cpp
@@ -0,0 +1,172 @@
+// This file is part of SmallBASIC
+//
+// Copyright(C) 2026 Joerg Siebenmorgen
+//
+// This program is distributed under the terms of the GPL v2.0 or later
+// Download the GNU Public License (GPL) from www.gnu.org
+//
+
+#include
+#include "config.h"
+#include "languages/messages.en.h"
+#include "include/var_map.h"
+#include "module.h"
+#include "serial.h"
+
+#define USB_CLASS_ID 1002
+#define MAX_HW_SERIAL 7
+#define SERIAL_DEFAULT_BAUD 9600
+
+static HardwareSerialIMXRT *getSerial(int serialNo) {
+ HardwareSerialIMXRT *result;
+ switch (serialNo) {
+ case 1:
+ result = &Serial1;
+ break;
+ case 2:
+ result = &Serial2;
+ break;
+ case 3:
+ result = &Serial3;
+ break;
+ case 4:
+ result = &Serial4;
+ break;
+ case 5:
+ result = &Serial5;
+ break;
+ case 6:
+ result = &Serial6;
+ break;
+ case 7:
+ result = &Serial7;
+ break;
+ default:
+ result = &Serial1;
+ break;
+ }
+ return result;
+}
+
+static bool is_serial(int id) {
+ return id >= 0 && id <= MAX_HW_SERIAL;
+}
+
+static bool is_serial_var(var_p_t var) {
+ return var != nullptr && v_is_type(var, V_INT) && is_serial(var->v.i);
+}
+
+static bool is_serial_object(var_p_t var) {
+ return var != nullptr && v_is_type(var, V_MAP) && is_serial(var->v.m.id);
+}
+
+static int cmd_serial_ready(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ int result;
+ if (argc != 0 || !is_serial_object(self)) {
+ v_setstr(retval, ERR_PARAM);
+ result = 0;
+ } else {
+ int serialNo = self->v.m.id;
+ if (serialNo == 0) {
+ v_setint(retval, Serial.available());
+ } else {
+ v_setint(retval, getSerial(serialNo)->available());
+ }
+ result = 1;
+ }
+ return result;
+}
+
+static int cmd_serial_receive(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ int result;
+ if (argc > 1 || !is_serial_object(self)) {
+ v_setstr(retval, ERR_PARAM);
+ result = 0;
+ } else {
+ int bufferSize = get_param_int(argc, args, 0, 0);
+ int size;
+ int serialNo = self->v.m.id;
+
+ if (bufferSize == 0) {
+ // Read until '\n' and return as string
+ bufferSize = CDC_RX_SIZE_480;
+ char buffer[bufferSize];
+
+ if (serialNo == 0) {
+ size = Serial.readBytesUntil('\n', buffer, bufferSize - 1);
+ } else {
+ size = getSerial(serialNo)->readBytesUntil('\n', buffer, bufferSize - 1);
+ }
+ buffer[size] = '\0';
+ v_setstr(retval, buffer);
+ result = 1;
+ } else {
+ // Read number of bytes and return as array
+ char buffer[bufferSize];
+ if (serialNo == 0) {
+ size = Serial.readBytes(buffer, bufferSize);
+ } else {
+ size = getSerial(serialNo)->readBytes(buffer, bufferSize);
+ }
+ if (bufferSize > 1) {
+ v_toarray1(retval, bufferSize);
+ for (int32_t ii = 0; ii < size; ii++) {
+ v_setint(v_elem(retval, ii), buffer[ii]);
+ }
+ } else {
+ v_setint(retval, buffer[0]);
+ }
+ result = 1;
+ }
+ }
+ return result;
+}
+
+static int cmd_serial_send(var_s *self, int argc, slib_par_t *args, var_s *retval) {
+ int result;
+ if (argc != 1 || !is_serial_object(self) || !v_is_type(args[0].var_p, V_STR)) {
+ v_setstr(retval, ERR_PARAM);
+ result = 0;
+ } else {
+ const char *buffer = v_getstr(args[0].var_p);
+ int length = v_strlen(args[0].var_p);
+ int serialNo = self->v.m.id;
+ switch (serialNo) {
+ case 0:
+ Serial.write(buffer, length);
+ break;
+ default:
+ getSerial(serialNo)->write(buffer, length);
+ break;
+ }
+ result = 1;
+ }
+ return result;
+}
+
+int cmd_openserial(int argc, slib_par_t *args, var_t *retval) {
+ int result;
+ if (!(argc == 0 || (argc == 1 && is_serial_var(args[0].var_p)))) {
+ v_setstr(retval, ERR_PARAM);
+ result = 0;
+ } else {
+ int serialNo = argc == 0 ? 0 : args[0].var_p->v.i;
+ map_init(retval);
+ retval->v.m.id = serialNo;
+ retval->v.m.cls_id = USB_CLASS_ID;
+ v_create_callback(retval, "ready", cmd_serial_ready);
+ v_create_callback(retval, "receive", cmd_serial_receive);
+ v_create_callback(retval, "send", cmd_serial_send);
+ switch (serialNo) {
+ case 0:
+ serial_init();
+ break;
+ default:
+ int serialSpeed = get_param_int(argc, args, 1, SERIAL_DEFAULT_BAUD);
+ getSerial(serialNo)->begin(serialSpeed);
+ break;
+ }
+ result = 1;
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/src/platform/teensy/src/serial.h b/src/platform/teensy/src/serial.h
index 0c854b87..d887ab01 100644
--- a/src/platform/teensy/src/serial.h
+++ b/src/platform/teensy/src/serial.h
@@ -9,4 +9,7 @@
#pragma once
+#include "common/var.h"
+
void serial_init();
+int cmd_openserial(int argc, slib_par_t *args, var_t *retval);
diff --git a/src/platform/teensy/src/ssd1306.cpp b/src/platform/teensy/src/ssd1306.cpp
index 28639418..4c21f335 100644
--- a/src/platform/teensy/src/ssd1306.cpp
+++ b/src/platform/teensy/src/ssd1306.cpp
@@ -393,7 +393,8 @@ static ModuleConfig ssd1306Module = {
._proc_exec = ssd1306_proc_exec,
._proc_count = ssd1306_proc_count,
._proc_getname = ssd1306_proc_getname,
- ._free = nullptr
+ ._free = nullptr,
+ ._close = nullptr
};
ModuleConfig *get_ssd1306_module() {
diff --git a/src/platform/teensy/src/teensy.cpp b/src/platform/teensy/src/teensy.cpp
index 72b0d13b..5a026a68 100644
--- a/src/platform/teensy/src/teensy.cpp
+++ b/src/platform/teensy/src/teensy.cpp
@@ -16,220 +16,12 @@
#include "device.h"
#include "module.h"
#include "serial.h"
+#include "i2c.h"
+#include "pinio.h"
+#include "fs.h"
#include
#include
-#define USB_CLASS_ID 1002
-#define MAX_HW_SERIAL 7
-#define BT_BAUD 9600
-
-static HardwareSerialIMXRT *getSerial(int serialNo) {
- HardwareSerialIMXRT *result;
- switch (serialNo) {
- case 1:
- result = &Serial1;
- break;
- case 2:
- result = &Serial2;
- break;
- case 3:
- result = &Serial3;
- break;
- case 4:
- result = &Serial4;
- break;
- case 5:
- result = &Serial5;
- break;
- case 6:
- result = &Serial6;
- break;
- case 7:
- result = &Serial7;
- break;
- default:
- result = &Serial1;
- break;
- }
- return result;
-}
-
-static TwoWire *getI2C(int interfaceNumber) {
- TwoWire *result;
- switch (interfaceNumber) {
- case 0:
- result = &Wire;
- break;
- case 1:
- result = &Wire1;
- break;
- case 2:
- result = &Wire2;
- break;
- default:
- result = &Wire;
- break;
- }
- return result;
-}
-
-static void set_pin(var_p_t var, uint8_t pin, uint8_t mode) {
- map_init(var);
- var->v.m.id = pin;
- pinMode(pin, mode);
-}
-
-static bool is_pin(int id) {
- return id >= 0 && id < CORE_NUM_TOTAL_PINS;
-}
-
-static bool is_pin_object(var_p_t var) {
- return var != nullptr && v_is_type(var, V_MAP) && is_pin(var->v.m.id);
-}
-
-static bool is_serial(int id) {
- return id >= 0 && id <= MAX_HW_SERIAL;
-}
-
-static bool is_serial_var(var_p_t var) {
- return var != nullptr && v_is_type(var, V_INT) && is_serial(var->v.i);
-}
-
-static bool is_serial_object(var_p_t var) {
- return var != nullptr && v_is_type(var, V_MAP) && is_serial(var->v.m.id);
-}
-
-static int cmd_analoginput_read(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
- int result = 0;
- if (argc != 0 || !is_pin_object(self)) {
- error(retval, "AnalogInput.read", 0);
- } else {
- int pin = self->v.m.id;
- v_setint(retval, analogRead(pin));
- result = 1;
- }
- return result;
-}
-
-static int cmd_openanaloginput(int argc, slib_par_t *args, var_t *retval) {
- int result = 1;
- int pin = get_param_int(argc, args, 0, -1);
- if (is_pin(pin)) {
- set_pin(retval, pin, INPUT);
- v_create_callback(retval, "read", cmd_analoginput_read);
- } else {
- result = 0;
- }
- return result;
-}
-
-static int cmd_digitalinput_read(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
- int result = 0;
- if (argc != 0 || !is_pin_object(self)) {
- error(retval, "DigitalInput.read", 0);
- } else {
- int pin = self->v.m.id;
- v_setint(retval, digitalRead(pin));
- result = 1;
- }
- return result;
-}
-
-static int cmd_opendigitalinput(int argc, slib_par_t *args, var_t *retval) {
- int result = 1;
- int pin = get_param_int(argc, args, 0, -1);
- uint8_t mode = get_param_int(argc, args, 1, 1);
- if (mode) {
- mode = INPUT_PULLUP;
- } else {
- mode = INPUT;
- }
- if (is_pin(pin)) {
- set_pin(retval, pin, mode);
- v_create_callback(retval, "read", cmd_digitalinput_read);
- result = 1;
- } else {
- result = 0;
- }
- return result;
-}
-
-static int cmd_digitaloutput_write(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
- int result = 0;
- if (argc != 1 || !is_pin_object(self)) {
- error(retval, "DigitalOutput.write", 1);
- } else {
- int pin = self->v.m.id;
- int value = get_param_int(argc, arg, 0, 0);
- digitalWrite(pin, value);
- result = 1;
- }
- return result;
-}
-
-static int cmd_opendigitaloutput(int argc, slib_par_t *args, var_t *retval) {
- int result;
- int pin = get_param_int(argc, args, 0, -1);
- if (is_pin(pin)) {
- set_pin(retval, pin, OUTPUT);
- v_create_callback(retval, "write", cmd_digitaloutput_write);
- result = 1;
- } else {
- result = 0;
- }
- return result;
-}
-
-static int cmd_analogoutput_write(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
- if (argc != 1 || !is_pin_object(self)) {
- error(retval, "AnalogOutput.write", 1);
- return 0;
- } else {
- int pin = self->v.m.id;
- int value = get_param_int(argc, arg, 0, 0);
- analogWrite(pin, value);
- }
- return 1;
-}
-
-static int cmd_analogoutput_frequency(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
- if (argc != 1 || !is_pin_object(self)) {
- error(retval, "AnalogOutput.frequency", 1);
- return 0;
- } else {
- int pin = self->v.m.id;
- double value = get_param_num(argc, arg, 0, 0.0);
- analogWriteFrequency(pin, value);
- }
- return 1;
-}
-
-static int cmd_analogoutput_resolution(var_s *self, int argc, slib_par_t *arg, var_s *retval) {
- if (argc != 1 || !is_pin_object(self)) {
- error(retval, "AnalogOutput.resolution", 1);
- return 0;
- } else {
- int value = get_param_int(argc, arg, 0, 0);
- analogWriteResolution(value);
- }
- return 1;
-}
-
-static int cmd_openanalogoutput(int argc, slib_par_t *args, var_t *retval) {
- int result;
- int pin = get_param_int(argc, args, 0, -1);
- if (is_pin(pin)) {
- set_pin(retval, pin, OUTPUT);
- v_create_callback(retval, "write", cmd_analogoutput_write);
- v_create_callback(retval, "frequency", cmd_analogoutput_frequency);
- v_create_callback(retval, "resolution", cmd_analogoutput_resolution);
- result = 1;
- } else {
- result = 0;
- }
- return result;
-}
-
static int cmd_get_temperature(int argc, slib_par_t *args, var_t *retval) {
v_setint(retval, tempmonGetTemp());
return 1;
@@ -240,238 +32,6 @@ static int cmd_get_cpu_speed(int argc, slib_par_t *args, var_t *retval) {
return 1;
}
-static int cmd_serial_ready(var_s *self, int argc, slib_par_t *args, var_s *retval) {
- int result;
- if (argc != 0 || !is_serial_object(self)) {
- v_setstr(retval, ERR_PARAM);
- result = 0;
- } else {
- int serialNo = self->v.m.id;
- if (serialNo == 0) {
- v_setint(retval, Serial.available());
- } else {
- v_setint(retval, getSerial(serialNo)->available());
- }
- result = 1;
- }
- return result;
-}
-
-static int cmd_serial_receive(var_s *self, int argc, slib_par_t *args, var_s *retval) {
- int result;
- if (argc > 1 || !is_serial_object(self)) {
- v_setstr(retval, ERR_PARAM);
- result = 0;
- } else {
- int bufferSize = get_param_int(argc, args, 0, 0);
- int size;
- int serialNo = self->v.m.id;
-
- if (bufferSize == 0) {
- // Read until '\n' and return as string
- bufferSize = CDC_RX_SIZE_480;
- char buffer[bufferSize];
-
- if (serialNo == 0) {
- size = Serial.readBytesUntil('\n', buffer, bufferSize - 1);
- } else {
- size = getSerial(serialNo)->readBytesUntil('\n', buffer, bufferSize - 1);
- }
- buffer[size] = '\0';
- v_setstr(retval, buffer);
- result = 1;
- } else {
- // Read number of bytes and return as array
- char buffer[bufferSize];
- if (serialNo == 0) {
- size = Serial.readBytes(buffer, bufferSize);
- } else {
- size = getSerial(serialNo)->readBytes(buffer, bufferSize);
- }
- if (bufferSize > 1) {
- v_toarray1(retval, bufferSize);
- for (int32_t ii = 0; ii < size; ii++) {
- v_setint(v_elem(retval, ii), buffer[ii]);
- }
- } else {
- v_setint(retval, buffer[0]);
- }
- result = 1;
- }
- }
- return result;
-}
-
-static int cmd_serial_send(var_s *self, int argc, slib_par_t *args, var_s *retval) {
- int result;
- if (argc != 1 || !is_serial_object(self) || !v_is_type(args[0].var_p, V_STR)) {
- v_setstr(retval, ERR_PARAM);
- result = 0;
- } else {
- const char *buffer = v_getstr(args[0].var_p);
- int length = v_strlen(args[0].var_p);
- int serialNo = self->v.m.id;
- switch (serialNo) {
- case 0:
- Serial.write(buffer, length);
- break;
- default:
- getSerial(serialNo)->write(buffer, length);
- break;
- }
- result = 1;
- }
- return result;
-}
-
-static int cmd_openserial(int argc, slib_par_t *args, var_t *retval) {
- int result;
- if (!(argc == 0 || (argc == 1 && is_serial_var(args[0].var_p)))) {
- v_setstr(retval, ERR_PARAM);
- result = 0;
- } else {
- int serialNo = argc == 0 ? 0 : args[0].var_p->v.i;
- map_init(retval);
- retval->v.m.id = serialNo;
- retval->v.m.cls_id = USB_CLASS_ID;
- v_create_callback(retval, "ready", cmd_serial_ready);
- v_create_callback(retval, "receive", cmd_serial_receive);
- v_create_callback(retval, "send", cmd_serial_send);
- switch (serialNo) {
- case 0:
- serial_init();
- break;
- default:
- int serialSpeed = get_param_int(argc, args, 1, BT_BAUD);
- getSerial(serialNo)->begin(serialSpeed);
- break;
- }
- result = 1;
- }
- return result;
-}
-
-static int cmd_i2c_write(var_s *self, int argc, slib_par_t *args, var_s *retval) {
- uint8_t address = get_param_int(argc, args, 0, 0);
- uint8_t stop = get_param_int(argc, args, 2, 1);
-
- if (address == 0 || argc < 2) {
- v_setstr(retval, ERR_PARAM);
- return 0;
- }
-
- int interfaceNumber = self->v.m.id;
- TwoWire *ptrWire;
- ptrWire = getI2C(interfaceNumber);
-
- ptrWire->beginTransmission(address);
-
- switch (args[1].var_p->type) {
- case V_INT:{
- int value = get_param_int(argc, args, 1, 0);
- ptrWire->write(value);
- }
- break;
- case V_STR:{
- const char *buffer = v_getstr(args[1].var_p);
- int length = v_strlen(args[1].var_p);
- ptrWire->write(buffer, length);
- }
- break;
- case V_ARRAY:{
- var_p_t array = args[1].var_p; // Get array
- if (array->maxdim > 1) {
- v_setstr(retval, "ERROR: I2C: Write requires 1D-array");
- return 0;
- }
- uint32_t bytes = v_ubound(array, 0) - v_lbound(array, 0) + 1;
- uint8_t *buffer = new uint8_t[bytes];
- for (uint32_t ii = 0; ii < bytes; ii++) {
- buffer[ii] = get_array_elem_int(array, ii);
- }
- ptrWire->write(buffer, bytes);
- delete[]buffer;
- }
- break;
- }
-
- if (ptrWire->endTransmission(stop)) {
- v_setstr(retval, "ERROR I2C: Transmission failed");
- return 0;
- }
-
- return 1;
-}
-
-static int cmd_i2c_read(var_s *self, int argc, slib_par_t *args, var_s *retval) {
- uint8_t address = get_param_int(argc, args, 0, 0);
- uint32_t bytes = get_param_int(argc, args, 1, 1);
- uint8_t stop = get_param_int(argc, args, 2, 1);
-
- if (address == 0) {
- v_setstr(retval, ERR_PARAM);
- return 0;
- }
-
- int interfaceNumber = self->v.m.id;
- TwoWire *ptrWire;
- ptrWire = getI2C(interfaceNumber);
- ptrWire->requestFrom(address, bytes, stop);
-
- if (bytes > 1) {
- v_toarray1(retval, bytes);
- for (uint32_t ii = 0; ii < bytes; ii++) {
- v_setint(v_elem(retval, ii), ptrWire->read());
- }
- } else {
- v_setint(retval, ptrWire->read());
- }
- return 1;
-}
-
-static int cmd_i2c_setClock(var_s *self, int argc, slib_par_t *args, var_s *retval) {
- uint32_t clockFrequency = get_param_int(argc, args, 0, 100000);
-
- if (clockFrequency != 100000 && clockFrequency != 400000 && clockFrequency != 1000000) {
- v_setstr(retval, "ERROR I2C: Clock freuqency not supported");
- return 0;
- }
-
- int interfaceNumber = self->v.m.id;
- getI2C(interfaceNumber)->setClock(clockFrequency);
-
- return 1;
-}
-
-static int cmd_openi2c(int argc, slib_par_t *args, var_t *retval) {
- uint8_t interfaceNumber = get_param_int(argc, args, 0, 0);
- uint8_t pinSDA = get_param_int(argc, args, 1, 0);
- uint8_t pinSCL = get_param_int(argc, args, 2, 0);
-
- if (interfaceNumber > 2) {
- v_setstr(retval, ERR_PARAM);
- return 0;
- }
-
- map_init(retval);
- v_create_callback(retval, "write", cmd_i2c_write);
- v_create_callback(retval, "read", cmd_i2c_read);
- v_create_callback(retval, "setClock", cmd_i2c_setClock);
- retval->v.m.id = interfaceNumber;
-
- TwoWire *ptrWire;
- ptrWire = getI2C(interfaceNumber);
-
- if (pinSDA > 0 && pinSCL > 0) {
- ptrWire->setSDA(pinSDA);
- ptrWire->setSCL(pinSCL);
- }
-
- ptrWire->begin();
-
- return 1;
-}
-
static int cmd_set_interactive(int argc, slib_par_t *args, var_t *retval) {
uint8_t mode = get_param_int(argc, args, 0, 1);
@@ -505,6 +65,7 @@ static FuncSpec lib_func[] = {
{1, 1, "OPENDIGITALOUTPUT", cmd_opendigitaloutput},
{0, 1, "OPENSERIAL", cmd_openserial},
{0, 3, "OPENI2C", cmd_openi2c},
+ {0, 0, "FS", cmd_fs},
{0, 0, "FREE", cmd_free}
};
@@ -582,6 +143,10 @@ static int teensy_proc_exec(int index, int argc, slib_par_t *args, var_t *retval
return result;
}
+void teensy_close(void) {
+ fs_close();
+}
+
static ModuleConfig teensyModule = {
._func_exec = teensy_func_exec,
._func_count = teensy_func_count,
@@ -589,7 +154,8 @@ static ModuleConfig teensyModule = {
._proc_exec = teensy_proc_exec,
._proc_count = teensy_proc_count,
._proc_getname = teensy_proc_getname,
- ._free = nullptr
+ ._free = nullptr,
+ ._close = teensy_close
};
ModuleConfig *get_teensy_module() {