ANNEX32 WI-FI RDS
User Manual
Version beta
1.44.2
© ciccioCB
2022
COPYRIGHT
The Annex firmware, including the AnnexToolKit
and this manual, are Copyright 2017-2020 by Francesco Ceccarella
(ciccioCB).
The compiled object code (the .bin file) for
the Annex firmware is free software: you can use or redistribute it
as you please except for commercial purposes. It is not allowed to distribute or embed it into
products that are sold or for any other activity making or intended
to make a profit.
The compiled object code (the .exe file) for
the AnnexToolKit utility is free software: you can use or
redistribute it as you please except for commercial purposes.
It is not allowed to distribute or
embed it into products that are sold or for any other activity
making or intended to make a profit.
This program is distributed in the hope that
it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
This manual is distributed under a Creative
Commons Attribution-NonCommercial-ShareAlike 3.0 France license
(CC BY-NC-SA 3.0)
The above copyright notice and this permission
notice shall be included in all copies or redistributions of the
Software in any form.
License and
credits
The base of the interpreter
comes from the original project "MiniBasic" by Malcom
Mclean.
Adafruit BNO055 Orientation
Sensor library is written by KTOWN is Copyright © Adafruit
Industries. It is released under MIT license.
TFT_eSPI display Library is
Copyright © 2017 Bodmer. It is released under FreeBSD
license.
Adafruit PWM Servo Driver
Library is Copyright © Adafruit. It is released under MIT
license.
Arduino Library for Dallas
Temperature ICs is Copyright © Miles Burton
<miles@mnetcs.com>. It is released under LGPL
license.
OneWire Library is Copyright
1999-2006 Dallas Semiconductor Corporation and Copyright © 2007,
Jim Studt.
Adafruit DHT Humidity &
Temperature Sensor Library is Copyright © Adafruit. It is released
under MIT license.
ESP8266 and ESP32 Oled Driver
for SSD1306 display is Copyright © 2016 by Daniel Eichhorn and
Copyright © 2016 by Fabrice Weinberg
NeoPixelBus library is
Copyright © Michael C. Miller. It is released under LGPL
license.
ESP AsyncTCP library is
Copyright © 2016 Hristo Gochkov. It is released under LGPL
license.
ESP AsyncWebServer library is
Copyright © 2016 Hristo Gochkov. It is released under LGPL
license.
IRremote library is Copyright ©
Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran. It is
released under LGPL license.
uRTCLib is is Copyright © 2015
Naguissa (naguissa.com@gmail.com). It is released under LGPL
license.
BME280 library is written by
Limor Fried/Ladyada for Adafruit Industries. It is released under
BSD license,
APDS9960 library is written by
Shawn Hymel for Sparkfun Electronics. It is released under Beerware
license.
PID Library is written by Brett
Beauregard (br3ttb@gmail.com). It is released under MIT
license.
The Javascript Editor
EditArea is Copyright © 2008 Christophe Dolivet. It is
released under LGPL license.
The M5Stack library is
copyright © 2017 by M5Stack. It is released under MIT
license.
The MPU9250 driver is part of
the M5Stack Library.
The VL53L0X driver is Copyright
© 2017 Pololu. It contains code © 2016
STMicroelectronics.
Some GUI objects come from the
library GUIslice Copyright © Calvin Hass that is released under MIT
license.
The MFRD522 library is written
by Miguel Balboa and is released as free and unencumbered software
released into the public domain.
Contributions
A very big thank you to Robin Baker
(Electroguard) for his great involvement in the project by
supporting all the tests on the real hardware (bought with his
money), and all the advices that allowed me to add a lot of
functionality, not to mention the Huge work he did while
documenting the project on the website.
Content :
Introduction:
20
Interpreter:
22
Branch
labels
22
Variables:
23
Arrays:
24
Scope of the
variables:
25
Bases of the
language
26
OPERATORS AND
PRECEDENCE
26
Basic internal
keywords:
28
IF command
:
28
FOR loop
29
WHILE WEND
loop
30
DO LOOP
loop
30
SELECT
CASE
31
GOTO
32
GOSUB
33
DATA
33
END
34
EXIT
34
SUB
34
Logical / boolean
Operations
36
ERRORS
HANDLING
37
ONERROR
ABORT
38
ONERROR
IGNORE
38
ONERROR SKIP
[nn]
38
ONERROR
CLEAR
38
ONERROR GOTO [label |
OFF]
38
BAS.ERRLINE
38
BAS.ERRNUM
38
BAS.ERRMSG$
38
HOW the interpreter works with
the HTML code and Objects :
39
HTML
Objects
43
TIMERS
48
EVENTS
48
Button
Event
49
OnHtmlChange
Event
49
OnHtmlReloadEvent
49
OnInfrared
Event
50
OnSerial
Event
50
OnSerial2
Event
50
OnTouch
Event
51
OnUDP
Event
51
OnWgetAsync
Event
51
OnUrlMessage
Event
52
OnEspNowMsg
Event
55
OnEspNowError
Event
56
OnMQTT
Event
56
OnPlay
Event
56
WiFI
CONNECTIONS
56
PROGRAM
AUTORUN
58
RECOVERY
MODE
59
SLEEP mode (low energy) and RTC
memory
59
DATE - TIME
timekeeper
60
Unix Time
functions
61
FAT32 File
System
61
Ret = FILE.COPY(filename$,
newfile$)
63
Ret =
FILE.DELETE(filename$)
63
Ret =
FILE.EXISTS(filename$)
63
Ret = FILE.RENAME(oldname$,
newname$)
63
Ret =
FILE.SIZE(filename$)
63
Ret =
FILE.MKDIR(dirname$)
63
Ret =
FILE.RMDIR(dirname$)
63
Ret$ =
FILE.DIR$(path$)
63
Ret$ = FILE.READ$(filename$,
[line_num] | [start, length])
63
FILE.APPEND filename$,
content$
63
FILE.SAVE filename$,
content$
63
FILE.WRITE filename$,
content$
64
FILE.SAVE_IOBUFF
64
FILE.WRITE_IOBUFF
64
FILE.APPEND_IOBUFF
64
FILE.READ_IOBUFF
64
I/O
BUFFERS
64
Read
Operations
66
Write
Operations
67
Special
operations
68
Advanced
operations
68
Bit
operations
69
Buffer
copy
69
Code examples
:
69
WIRING
71
DIGITAL
I/O
73
PIN
INTERRUPTS
74
Analog
inputs
74
TOUCH
inputs
75
Analog
outputs
75
Hardware
interfaces:
75
PWM
75
PWM.SETUP pin, channel,
default_value, [,frequency]
[,resolution]
76
PWM.OUT channel,
value
77
SERVO
77
I2S BUS
78
SPEAKER
OUTPUT
80
I2C BUS
80
PCF8574
Module
82
ADS1115
Module
83
MCP23017
Module
86
SPI BUS
87
74HC595
Module
89
MCP23S17
Module
90
CAN BUS
92
CAN.SETUP
93
CAN.INIT
94
CAN.STOP
94
CAN.WRITE
94
CAN.WRITE_IOBUFF
95
ONCANBUS
95
CANBUS
BUFFERS
97
COUNTERS
99
PID
controllers
100
SOUND
PLAYER
101
Metadata Decoding from Mp3 and
streaming
104
SPEECH SYNTHESIS with vintage
C64 SAM speaker
104
SPEECH SYNTHESIS using google
translate
105
SPEECH SYNTHESIS using voiceRSS
free service
106
LCD DISPLAY USING
I2C
107
OLED
DISPLAY
111
ST7920 LCD
DISPLAY
113
RTC
module
115
PCA9685 (PWM / Servo)
Module
117
TM1637 display
module
118
TM1638 display
module
120
MAX7219 8-Digits 7-segment
display
122
MAX7219 Dot Matrix
Display
123
NeoPixel WS2812B led
strips
125
NeoPixel based WS2812b Dot
Matrix DIsplay
127
SD CARD
ADAPTER
131
TFT DISPLAY
ILI9341
133
TFT DISPLAY
ILI9163
137
TFT DISPLAY
ILI9486
138
TFT DISPLAY
ILI9481
141
TFT DISPLAY
ILI9488
142
TFT DISPLAY
ST7735
143
TFT DISPLAY
ST7796
144
TouchScreen
146
TFT
FONTS
146
QR
CODES
150
GRAPHIC GUI for
TFT
151
GUI
Objects
152
gui.TextLine
152
gui.Button
152
gui.Image
153
gui.ButtonImage
153
gui.CheckBox
154
gui.Slider
155
gui.ProgressBar
155
gui.Ramp
155
gui.Gauge
156
gui.Box
156
gui.Circle
157
gui.Rect
157
gui.Line
158
GUI
Functions
158
gui.GetValue
158
gui.Target
158
GUI
Commands
158
gui.INIT
158
gui.REDRAW
159
gui.REFRESH
159
gui.AUTOREFRESH
159
gui.SETVALUE
159
gui.SETTEXT
159
gui.SETIMAGE
159
gui.SETCOLOR
159
gui.SETRANGE
160
gui.SETEVENT
160
gui.SETSTYLE
161
INFRARED
INTERFACE
161
ULTRASONIC DISTANCE SENSOR
HC-SR04
165
DHT xx Temperature / Humidity
Sensors
166
DS18B20 Temperature
Sensors
168
BNO055 Absolute Orientation
Sensor
169
BME280 Combined humidity and
pressure sensor
171
HDC1080 High Accuracy Digital
Humidity Sensor with Temperature
Sensor
173
CCS811 Air Quality
Sensor
174
APDS9960 Digital Proximity,
Ambient Light, RGB and Gesture Sensor
177
RFID MFRC522 RFID cards
reader
180
Writing NUID for UID changeable
card (4 byte UID version)
184
VL53L0X TOF (Time Of Flight)
Distance Sensor
184
MPU9250
186
MPU6500 /
MPU6050
189
MPU6886 (For M5
Atom)
191
IMU FUSION
FUNCTIONS
193
ETHERNET Module
W5500
194
FTP
198
BAS.FTP$
198
Server data requests (GET
and POST)
199
WGET$(server$, port, [,header]
[,content_type$])
200
WGET$(url$ [,header]
[,content_type$])
200
WPOST$(server$, body$, port
[,header] [,content_type$] )
200
WPOST$(url$, body$ [,header]
[,content_type$])
200
WGETASYNC[(] server$, port,
[,header] [)]
200
WGETASYNC[(] url$,[,header]
[)]
200
MQTT
201
Ret = MQTT.Setup(server$,
[debug])
230
Ret = MQTT.Certif(cert_pem$
[,client_cert_pem$] [,client_key_pem$])
203
Ret =
MQTT.PSK(psk_hint_key$)
203
Ret = MQTT.Connect(login$, pass$
[id$])
203
Ret = MQTT.Connect("", "",
[id$])
230
Ret =
MQTT.Disconnect[()]
230
Ret = MQTT.Publish(topic$,
message$ [Qos], [retain])
230
Ret = MQTT.Subscribe(topic$
[,Qos])
230
Ret =
MQTT.UnSubscribe(topic$)
230
Ret =
MQTT.Connected[()]
230
Ret =
MQTT.Status[()]
203
ESP-NOW
206
BLUETOOTH low Energy
(BLE)
216
TELEGRAM (messenger)
support
220
LORA
222
LoRa.Setup ss, reset,
dio0
225
LoRa.Begin(freq)
225
LoRa.End
225
LoRa.BeginPacket
225
LoRa.Print
225
LoRa.EndPacket
225
LoRa.Receive
225
LoRa.RSSI
225
LoRa.SNR
225
LoRa.Idle
225
LoRa.Sleep
225
LoRa.TXpower
pow
225
LoRa.SyncWord
word
226
LoRa.EnableCRC
enable
226
OnLora
226
LoRa.Message$
226
M5
Tough
228
M5Tough.BatLevel
230
M5Tough.BatVoltage
230
M5Tough.BatCurrent
230
M5Tough.VinVoltage
230
M5Tough.VinCurrent
230
M5Tough.VBusVoltage
230
M5Tough.VBusCurrent
230
M5Tough.BatChgCurrent
230
M5Tough.BatPower
230
M5Tough.AxpTemp
230
M5Tough.ApsVoltage
230
M5Tough.AxpState
230
M5Tough.TftPower
power
230
M5Tough.SpeakerPower
power
230
M5Tough.SetBusPowerMode
mode
230
M5Tough.PowerOff
sec
231
M5Tough.LightSleep
sec
231
M5Tough.DeepSleep
sec
231
ANNEXCAM
231
Functionalities enabled in the
ANNEXCAM version
234
Camera Functions /
commands
235
Using AnnexCam in output
page
238
Control of the camera using
URL
239
Face
Recognition
240
Image / video reception from
Annex
241
ANNEXEPAPER for LILYGO T5 4.7”
E-paper module
243
GRAPHIC GUI for
E-PAPER
246
Functionalities enabled in the
E-PAPER version
253
CONVERSION
FUNCTIONS
255
CONVERT.DEGC_TO_F(degC)
255
CONVERT.F_TO_DEGC(degF)
255
CONVERT.TO_IEEE754(num)
255
CONVERT.FROM_IEEE754(iee754_bin)
255
CONVERT.MAP(number, fromLow,
fromHigh, toLow, toHigh)
255
BAS
CONSTANTS
255
BAS.VER
256
BAS.VER$
256
BAS.ERRLINE
256
BAS.ERRNUM
256
BAS.ERRMSG$
256
BAS.FILENAME$
256
BAS.RTCMEM$
256
BAS.SSID$
256
BAS.PASSWORD$
256
BAS.LOAD
258
BAS.RESETREASON
258
BAS.DEVICE
258
BAS.TFT
258
OPTION
COMMANDS
258
OPTION.CPUFREQ
80|160|240
259
OPTION.MAC
mac$
259
OPTION.LOWRAM
value
259
OPTION.NTPSYNC
259
OPTION.WDT
time
259
OPTION.WDTRESET
259
OPTION.WLOG
value
259
HALL Sensor
(Internal):
259
BAS.HALL
259
FUNCTIONS:
260
NUMERICAL
FUNCTIONS
260
ABS(number)
275
ACOS(number)
275
ADC(pin)
275
APDS9960.SETUP
(mode)
275
APDS9960.READGESTURE
275
APDS9960.AMBIENT
275
APDS9960.RED
275
APDS9960.GREEN
275
APDS9960.BLUE
275
APDS9960.PROXIMITY
275
APDS9960.GESTUREGAIN
(gain)
275
APDS9960.GESTURELED
(intensity)
275
ASC(string$)
275
ASIN(number)
275
ATAN(number)
275
ATAN2(x,
y)
275
BAS.VER
275
BAS.ERRLINE
275
BAS.ERRNUM
275
BME280.SETUP(address)
275
BME280.ALT(qnh)
275
BME280.HUM
275
BME280.QFE
275
BME280.QNH(altitude)
275
BME280.TEMP
275
BNO055.SETUP(
address)
275
BNO055.HEADING
275
BNO055.PITCH
275
BNO055.ROLL
275
BNO055.VECTOR ( param,
axis)
275
BNO055.CALIB
[(param)]
275
CINT(number)
275
CONVERT.DEGC_TO_F(degC)
275
CONVERT.F_TO_DEGC(degF)
275
CONVERT.TO_IEEE754(num)
275
CONVERT.FROM_IEEE754(ieee754_bin)
275
CONVERT.MAP(number, fromLow,
fromHigh, toLow, toHigh)
275
COS(number)
275
COUNTER.COUNT
(cnt)
275
COUNTER.PERIOD
(cnt)
275
DATEUNIX(date$)
275
DHT.TEMP
275
DHT.HUM
275
DHT.HEATINDEX
275
DISTANCE(pin_trig,
pin_echo)
275
EMAIL from$, to$, subject$,
message$
275
ESPNOW.ADD_PEER(MAC_add$)
275
ESPNOW.BEGIN
275
ESPNOW.DEL_PEER(MAC_add$)
275
ESPNOW.STOP
275
ESPNOW.WRITE(
msg$)
275
ESPNOW.WRITE(
msg$,MAC_add$)
275
EXP(number)
275
FIX(number)
275
FILE.DELETE(filename$)
275
FILE.EXISTS(filename$)
275
FILE.SIZE(filename$)
275
FLASHFREE
275
FUSION.ANGLE(axis)
275
INSTR([start], string$,
pattern$)
275
I2C.LEN
275
I2C.READ
275
I2C.READREGBYTE (i2c_address,
register)
275
I2C.END
275
INT(number)
275
LEN(string$)
275
LOG(number)
275
MILLIS
275
MQTT.Setup(server$
[,debug])
275
MQTT.Certif(cert_pem$
[,client_cert_pem$] [,client_key_pem$])
269
MQTT.PSK(psk_hint_key$)
269
MQTT.Connect(login$, pass$,
[id$])
269
MQTT.Connect("", "",
[id$])
269
MQTT.Disconnect[()]
275
Ret = MQTT.Publish(topic$,
message$ [Qos], [retain])
269
MQTT.Subscribe(topic$
[,Qos])
275
MQTT.UnSubscribe(topic$)
275
MQTT.Connected[()]
275
Ret =
MQTT.Status[()]
269
NEO.GETPIXEL(pos)
269
NEO.RGB(R, G,
B)
275
PI
275
PID1.COMPUTE( current_value,
target_value)
275
PIN(pin_number)
275
PIN.TOUCH(pin_number)
275
PING(host$)
275
POW(x, y)
275
RAMFREE
275
RFID.SETUP(CS_pin,
RST_pin)
275
RFID.SETGAIN(gain)
275
RFID.SETKEY(key$)
275
RFID.RESET
275
RFID.AWAKE
275
RFID.SETNUID(NUID$)
275
RFID.WRITE(block,
data$)
275
RND(number)
275
SERIAL.LEN
275
SERIAL2.LEN
275
SGN(number)
275
SIN(number)
275
SPI.BYTE(byte)
275
SQR(number)
275
TAN(number)
275
TFT.RGB(r,g,b)
275
TIMEUNIX(time$)
275
TM1638.BUTTONS
275
TOUCH.X
275
TOUCH.Y
275
VAL(string$)
275
WIFI.CHANNEL
275
WIFI.MODE
275
WIFI.NETWORKS ( network$
)
275
WIFI.RSSI
275
WIFI.STATUS
275
WORD.COUNT( string$
[,delimiter$])
275
WORD.FIND( string$, find$
[,delimiter$])
275
STRING
FUNCTIONS
277
BAS.ERRMSG$
289
BAS.FILENAME$
289
BAS.FTP$( host$, login$,
password$, file$, folder$)
289
BAS.PASSWORD$
289
BAS.RTCMEM$
289
BAS.SSID$
289
BAS.VER$
289
BIN$(number)
289
BUTTON$(name$, label [, id]
)
289
CHECKBOX$( variable
[,id])
289
CHR$(number)
289
CSSID$(object_id,
object_style)
289
DATE$[(format)]
289
ESPNOW.ERROR$
289
ESPNOW.READ$
289
ESPNOW.REMOTE$
289
FILE.DIR$[(path$)]
289
FILE.READ$(filename$,[line_num]
| [start, length])
289
HEX$(number)
289
HtmlEventButton$
289
HtmlEventVar$
289
IMAGE$(path
[,id])
289
IMAGEBUTTON$(path, label
[,id])
289
IP$
289
IR.GET$[ (param)
]
289
JSON$(string$,
field$)
289
LCASE$(string$)
289
LED$(variable
[,id])
289
LEFT$(string$,
num)
289
LISTBOX$(variable$, "option1,
option2, option3, ..." [, height]
[,id])
289
MAC$[ (id)
]
289
METER$(variable, min, max
[,id])
289
MID$(string$, start
[,num])
289
MQTT.Message$
289
MQTT.Topic$
289
OCT$(number)
289
PASSWORD$(variable [, id]
)
289
REPLACE$(expression$, find$,
replacewith$)
289
RFID.NUID$
289
RFID.TYPE$
289
RFID.READ$(block
[,key_b])
289
RIGHT$(string$,
num)
289
RTC.DATE$[(format)]
289
RTC.TIME$
289
SERIAL.CHR$
289
SERIAL.INPUT$
289
SERIAL2.CHR$
289
SERIAL2.INPUT$
289
SLIDER$(variable, min, max
[,step] [,id])
289
SPACE$(number)
289
SPI.STRING$(data$,
len)
289
SPI.HEX$(datahex$,
len)
289
STR$ (number [,format$
[,toint]])
289
STRING$(num,
char$)
289
TEMPR$(pin_number
[,ID])
289
TEXTAREA$(variable [, id]
)
289
TEXTBOX$(variable [, id]
)
289
TRIM$(string$)
289
TIME$
289
UCASE$(string$)
289
UDP.READ$
289
UDP.REMOTE$
289
UNIXDATE$(value
[,format])
289
UNIXTIME$(value)
289
URLMSGGET$
([arg$])
289
WGET$( http_server$, port
[,header] )
289
WGET$( url$, [,header]
)
288
WGETRESULT$
288
WORD$(string$, position
[,delimiter$])
289
WORD.DELETE$(string$, position
[delimiter$])
289
WORD.EXTRACT$(string$, lead$,
trail$)
289
WORD.GETPARAM$( setting$,
parameter$ [,separator$])
289
WPOST$(server$, body$, port
[,header])
289
WPOST$(url$, body$,
[,header])
289
COMMANDS:
290
AUTOREFRESH
interval
322
BAS.LOAD
filename$
322
BAS.RTCMEM$ =
val$
322
CLS
322
CSS
style_code$
322
COMMAND
cmd$
322
COUNTER.RESET
cnt
322
COUNTER.SETUP cnt, pin
[,mode]
322
CSSEXTERNAL
file$
322
DATA const1 [,const2]
...
322
DHT.SETUP pin,
model
322
EMAIL.SETUP server$, port,
user_name$, password$ [, debug]
322
EMAILASYNC from$, to$, subject$,
message$
322
FILE.SAVE filename$,
content$
322
FUSION.INIT
322
FUSION.MADGWICK ax, ay, az, gx,
gy, gz
322
FUSION.MADGWICK ax, ay, az, gx,
gy, gz, mx, my, mz
322
FUSION.MAHONY ax, ay, az, gx,
gy, gz, mx, my, mz
322
FUSION.BETA
=
322
FUSION.ZETA
=
322
FUSION.KI
=
322
FUSION.KP
=
322
HTML
code$
322
I2C.SETUP sda_pin, scl_pin
[,freq ]
322
I2C.BEGIN
address
322
I2C.END
322
I2C.REQFROM address,
length
322
I2C.READREGARRAY i2c_address,
register, nb_of_bytes, Array()
322
I2C.WRITE
value
322
I2C.WRITEREGBYTE
i2c_address,register, value
322
I2C.WRITEREGARRAY i2c_address,
register, nb_of_bytes, Array()
322
INPUT.TIMEOUT
timeout
322
INPUT["prompt$";]
variable
322
INTERRUPT pin_no, {OFF |
label}
322
IR.INIT pin_rx | OFF [,
pin_tx]
322
IR.SEND type, code$,
bits
322
JSCALL
javaCode$
322
JSCRIPT
script$
322
JSEXTERNAL
file$
322
LCD.INIT address, cols,
rows
322
LCD.CLS
322
LCD.PRINT x, y,
text$
322
LOCAL var1 [,var2],
...
322
MAXDISPLAY.SETUP
CS_pin
322
MAXDISPLAY.PRINT msg$
[,‘brightness]
322
MAXSCROLL.SETUP nb_devices,
CS_pin
322
MAXSCROLL.PRINT
msg$
322
MAXSCROLL.NEXT
msg$
322
MAXSCROLL.TEXT
msg$
322
MAXSCROLL.SHOW pos [,
brightness]
322
MAXSCROLL.SCROLL
[brightness]
322
MAXSCROLL.OSCILLATE
[brightness]
322
NEO.PIXEL led_pos, R, G, B [,
disable]
322
NEO.PIXEL led_pos, COLOR [,
disable]
322
NEO.SETUP pin
[,nb_led]
322
NEO.STRIP led_start_pos,
led_end_pos, R, G, B [, disable]
322
NEO.STRIP led_start_pos,
led_end_pos, COLOR [, disable]
322
NEOSCROLL.SETUP nb_devices, pin
[,serpentine]
322
NEOSCROLL.PRINT
msg$
322
NEOSCROLL.NEXT
msg$
322
NEOSCROLL.COLORS
col$
322
NEOSCROLL. NEXTCOLORS
col$
322
NEOSCROLL.SHOW pos [,
brightness]
322
NEOSCROLL.TEXT
msg$
322
NEOSCROLL.SCROLL
[‘brightness]
322
NEOSCROLL.OSCILLATE
[‘brightness]
322
OLED.CLS
322
OLED.INIT
orientation
322
OLED.REFRESH
fmt
322
OLED.COLOR
color
322
OLED.PIXEL x,
y
322
OLED.LINE x1, y1, x2,
y2
322
OLED.RECT x,y, width, height
[,fill]
322
OLED.CIRCLE x, y, radius [,
fill]
322
OLED.FONT
font_num
322
OLED.PRINT x, y, text$
[background]
322
OLED.IMAGE x, y,
image$
322
ONERROR ABORT or ONERROR IGNORE
or ONERROR SKIP [nn] or ONERROR CLEAR or ONERROR GOTO
label
322
ONESPNOWERROR [label |
OFF]
322
ONESPNOWMSG [label |
OFF]
322
ONGESTURE [label |
OFF]
322
ONHTMLCHANGE [label |
OFF]
322
ONHTMLRELOAD [label |
OFF]
322
ONINFRARED
label
322
ONMQTT
label
322
ONRFID
label
322
ONSERIAL [label |
OFF]
322
ONSERIAL2 [label |
OFF]
322
ONTOUCH [label |
OFF]
322
ONUDP [label |
OFF]
322
ONURLMESSAGE [label |
OFF]
322
ONWGETASYNC [label |
OFF]
322
OPTION.CPUFREQ
80|160|240
322
OPTION.LOWRAM
value
322
PAUSE
delay
322
PCA9685.SETUP
addr
322
PCA9685.SETFREQ
freq
322
PCA9685.PWM pin,
value
322
PID1.INIT Kp, Ki,
Kd
322
PID1.LIMITS min,
max
322
PID1.PERIOD
msec
322
PID1.PARAMS Kp, Ki,
Kd
322
PID1.SETMODE
mode
322
PIN(pin_number) =
val
322
PIN.DAC pin_number,
value
307
PIN.MODE pin_number, mode
[,PULLUP | PULLDOWN ]
307
PLAY.MP3
mp3$
322
PLAY.STREAM stream$
[,buffer]
322
PLAY.SETUP dest
[,buffer]
322
PLAY.SPEAK message$ [,
phonetic]
322
PLAY.STOP
322
PLAY.VOICE "message", "language"
[, "filename"] [, action]
322
PLAY.VOLUME
volume
322
PLAY.WAV
322
PRINT expression[[,;
]expression] ...
322
PRINT2 expression [[,;
]expression] ...
322
PWM.SETUP pin, chan,
default, [,freq] [,resol]
322
PWM.SETUP pin,
OFF
322
PWM.OUT chan,
value
322
READ var1 [,var2]
...
322
REBOOT
322
REFRESH
322
RESTORE
322
RTC.SETTIME Year, Month, Day,
Hours, Minutes, Seconds
322
SERIAL.BYTE ch1 [,ch2] . .
.
322
SERIAL2.BYTE ch1 [,ch2] . .
.
322
SERIAL.MODE baudrate [, bits,
parity, stop]
322
SERIAL2.MODE baudrate, pin_tx,
pin rx [, bits, parity, stop]
322
SERVO id,
value
322
SERVO.SETUP id, pin_number |
OFF
322
SETTIME Year, Month, Day, Hours,
Minutes, Seconds
322
SLEEP value [,pin,
level]
322
SOCKET client,
msg$
322
SPI.CSPIN pin [,
polarity]
312
SPI.SETUP speed [,data_mode [,
bit_order]]
312
SPI.STOP
322
ST7920.INIT
CS_pin
312
ST7920.CLS
322
ST7920.REFRESH
fmt
322
ST7920.COLOR
color
322
ST7920.PIXEL x,
y
322
ST7920.LINE x1, y1, x2,
y2
322
ST7920.RECT x,y, width, height
[,fill]
322
ST7920.CIRCLE x, y, radius [,
fill]
322
ST7920.FONT
font_num
322
ST7920.PRINT x, y, text$
[background]
322
ST7920.IMAGE x, y,
image$
322
TM1637.PRINT msg$ [, brightness
]
322
TM1637.SETUP data_pin, clock_pin
[, bit_delay] [, display_type]
322
TM1638.PRINT msg$ [, brightness
]]
322
TM1638.SETUP data_pin,
clock_pin, strobe_pin
322
TM1638.LEDS
val
322
TFT.BMP filename$, [x, y [,
back_color] ]
322
TFT.BRIGHTNESS
val
322
TFT.CIRCLE x, y, radius,color [,
fill]
322
TFT.FILL
color
322
TFT.IMAGE filename$, [x, y [,
back_color] ]
322
TFT.INIT
orientation
322
TFT.JPG filename$, [x, y [,
scale] ]
322
TFT.LINE x1, y1, x2, y2,
col
322
TFT.PRINT expression [[,;
]expression] ...
322
TFT.RECT x, y, width, height,
color [ [,fill] ,[round_radius] ]
322
TFT.TEXT.COLOR color
[,backcolor]
322
TFT.TEXT.POS x,
y
322
TFT.TEXT.SIZE
size
322
TIMER0 interval,
label
322
TIMER1 interval,
label
322
TOUCH.CALIB
322
UDP.BEGIN
port
322
UDP.REPLY msg$
[,port]
322
UDP.STOP
322
UDP.WRITE ip, port,
msg$
322
URLMSGRETURN msg$
[,content_type$]
322
WAIT
322
WGETASYNC server$, port
[,header]
322
WGETASYNC url$, port
[,header]
319
WIFI.APMODE SSID$, password$ [,
channel] [, IP$ , MASK$]
321
WIFI.AWAKE
321
WIFI.CONNECT SSID$, password$ [,
BSSID$] [, IP$ , MASK$ [, GATEWAY$]]
321
WIFI.POWER
pow
322
WIFI.SCAN
322
WIFI.SLEEP
322
WLOG [text$ |
num]
322
WORD.DELPARAM setting$,
parameter$, [,separator$]
322
WORD.SETPARAM setting$,
parameter$, value$ [,separator$]
322
BASIC
KEYWORDS
322
CASE
324
DIM array(size) [,
…]
324
DO
324
ELSE
324
END [IF | SELECT |
SUB]
324
ENDIF
324
EXIT {DO | FOR |
SUB}
324
FOR
324
GOSUB [label |
lab$]
324
GOTO [label |
lab$]
324
IF
324
LET var =
expression
324
LOOP
324
NEXT
324
OFF
324
OUTPUT
324
PULLUP
324
PULLDOWN
324
REM
324
RETURN
324
SELECT
324
SPECIAL
324
STEP
324
SUB
324
THEN
324
TO
324
UNTIL
324
WEND
324
WHILE
324
Introduction:
Annex32 WI-Fi RDS (Rapid Development Suite) is
a version of the "BASIC" language developed to run on low cost
ESP-32 WIFI devices.
Annex32 is specifically for the ESP32 range of
devices, whose implemented features can vary greatly.
To offer some standardisation, Annex32 caters
in particular to M5stack devices, which include a micro-SD card
slot, TFT display, speaker, 3 user buttons plus a reset button, and
a lipo battery, all self-contained in a plastic case offering
expansion pin access and designed to accept ‘stackable’ expansion
modules.
All drivers needed for the M5stack features
are already included in the Annex32 firmware, and pre-configured
for the M5stack so that features such as TFT display and SDcard
work by default.
Similar functionality could be built using
alternative TFT display and SD card reader etc, if preferred.
Please refer to the original
M5Stack schematics for more details.
However, M5stack and its hardware features
merely offer a convenient standardised feature set, they are not
mandatory - Annex32 works with any ESP32 devices, with or without
hardware expansion modules.
Obviously appropriate hardware is needed for
any required features - eg: an OLED display could be used, but
scripts written for TFT displays will need modifying for the
different display.
Annex32 can use the internal flash disk space,
or an external SD card.
The internal and the external (SDcard) space
are mutually exclusive and cannot be accessed at the same time.
By default Annex32 will use the SD, if
available, otherwise it will use the internal flash disk space
(FATFS).
Both use the same type file system (FAT32),
enabling the use of long file names and directories.
Depending on the module flash memory size (4,
8 or 16MB), the internal disk space can be from ~1MB to 13MB.
Using the ESP32 partition scheme it is
possible to freely define this space, but modifying it will wipe
out all existing files already stored.
Annex32 Wi-Fi RDS takes from the original
concept of Annex WI-FI RDS for ESP8266 from which it shares
essentially the IDE interface and the same command syntax as much
as possible.
It should be straightforward switching to
Annex32 if coming from Annex, and the same programs should run
without (or with minimum) modifications (eg: pin numbers).
Annex32 Wi-Fi RDS benefits from the powerful
H/W architecture of the ESP32 using both cores and the RAM memory
available. In addition, for modules equipped with PSRAM memory
extension, Annex32 can make available to the users this additional
RAM space (up to 4MBytes).
Functionalities:
-
Includes an internal IDE so can be programmed directly using your
web browser (even from your phone/tablet) without any additional
utility.
-
Syntax highlighting with context-sensitive Help
-
A programmable web server which includes a file server
-
Supports OTA (over the air) update.
-
Support async events (interrupts, timers, web access, UDP, ….)
-
Breakpoints, immediate execution of commands, display of variables,
single step.
-
A basic interpreter with floating point variables (double
precision) and string variables, multi-dimensional arrays (float
and string), user defined subroutines.
-
Access to any available I/O pin for input/output, PWM and
Servo.
-
Errors Handling .
-
Support TCP (HTTP) GET and POST for communications
-
Support for UDP for communications.
-
Support for sending Emails using SMTP SSL servers
-
Support for AJAX communications
-
Support for ESP-NOW communications
-
Support for MQTT communications
-
Support for FTP communications
-
Support for RJ45 wired ethernet using W5500 module
-
Accompanying utility suite includes Flasher, File Manager, HTML
Converter, Backup/Restore to bin or zip, integrated Serial Port
Monitor, OTA (over the air) update server and UDP Console.
-
IMU / AHRS Fusion algorithms 6 DOF and 9 DOF (Madgwick and
Mahony)
-
Play MP3 or WAV sound files or streaming using a speaker or an
external I2S DAC
-
Text to Speech using a speaker or an external I2S DAC
The following
devices are supported directly with dedicated commands / functions
:
-
DHT11, DHT21 or DHT22 Temperature / Humidity Sensors
-
DS18B20 Temperature sensor
-
LCD HD44780 with I2C interface module (1, 2 or 4 lines with 16 or
20 chars per line)
-
LCD Display based on chipset ST7920 with 128x64 pixels
monochrome
-
OLED Display based on chipset SSD1306 or SH1106 with 128x64 pixels
monochrome
-
TFT Display at 16 bits colors based on the following chipset:
-
ILI9341 with 320x240 pixels
-
ILI9163 with several resolutions
-
ST7735 with several resolutions
-
ST7796 with 480x320 pixels
-
ILI9481 with 480x320 pixels
-
ILI9486 with 480x320 pixels
-
ILI9488 with 480x320 pixels
-
TM1637 4 digits 7-segments display
-
TM1638 8 digits 7-segments display including 8 leds and 8
buttons
-
MAX7219 8 digits 7-segments display
-
MAX7219 8x8 dot matrix display modules
-
Neopixel WS2812 led strips
-
Neopixel WS2812 8x8 dot matrix display
-
PCA9685 PWM/SERVO module
-
Infrared interface with many RC protocols (transmission and
reception)
-
RTC module (DS1307 or DS3231)
-
HC-SR04 ultrasonic sensor for distance measurement
-
BNO055 Absolute Orientation Sensor
-
MPU9250 / MPU6500 IMU units
-
MPU6886 IMU unit
-
BME280 Combined humidity and pressure sensor
-
APDS9960 Digital Proximity, Ambient Light, RGB and Gesture
Sensor
-
W5500 RJ45 wired Ethernet interface
-
VL53L0X TOF (Time Of Flight) Distance Sensor
-
RFID MFRC522 cards reader
-
Any compatible I2S DAC
-
Lora SX127x modules
Many ESP32 modules
/ units are supported and can be configured using the
“CONFIG” menu:
-
Almost all the ESP32 modules including ESP32 devkit, ESP32 wemos
mini, ESP32 lolin lite, ...
-
M5Stack
-
M5 Atom
-
M5 Atom matrix
-
M5 Atom Echo
-
ESP32-CAM
-
M5CAMERA
-
ODROID GO
-
M5Tough
-
WIFI LORA 32
Interpreter:
The basic interpreter works by reading a
script file saved to the esp local disk filing system.
This is the default mode if no external
SDcard(s) are connected to the ESP32.
In addition, Annex32 can use an external
SDcard as file system permitting up to 16Gbytes of disk space.
During the startup, if an external SDcard is
detected it will be automatically connected and used as the default
file system, in which case the internal filing system will not be
used.
Because the ESP32 contains a good quantity of
RAM, the user script is copied from the disk into a dedicated
area in the RAM memory where it is executed, together with the list
of the program lines, the branch labels and the list of the user
defined subroutines..
This uses more RAM compared to other
approaches, but allows faster program execution.
Another performance consideration is that the
ESP32 must be capable of executing several activities in the
background (web server, file server, etc..) so needs sufficient
free memory for running such tasks, and those parallel tasks will
obviously have an impact on script performance..
So performance-wise, the interpreter is not
particularly fast, but it should be fast enough for most tasks you
may require. In particular it is around 2 times faster than Annex
for ESP8266, considering that many tasks can run in parallel
without any appreciable performance impact (such as playing music
in the background).
Basic program lines :
A typical script line should comply with the
following syntax :
[label:]
command [argument1 [,argument2 …..]]
Script lines may contain several commands on
the same line if separated by the colon character ":".
[label:]
command1 [argument1 [,argument2 …..]]: command2 [argument1
[,argument2 …..]]
It must be noted that use of several commands on the same line is
not recommended and will cause program errors if the line contains
GOSUB or user defined subroutine calls.
All program jumps (eg: GOTO, GOSUB) are
referenced by their branch label names - line numbers are not
referenced in scripts, they are merely available in the editor as a
programming convenience if wished, and for error references.
NOTE : The gosub and the call to user
defined subroutines must be used alone on the script line.
Branch labels
Branch labels should not be named the same as
a command name, and must follow the same format as variables (see
below).
A branch label definition must begin the line,
and a colon (":") must terminate the label definition.
Any references to the defined label (GOTOs and
GOSUBs etc) do not use a colon.
Example :
b
= 10
a
= 20 : c = 30
GOSUB LABEL1
END
LABEL1:
print "Label1"
RETURN
|
Variables:
The interpreter has 2 types of variables:
-
Floating Point (double precision)
-
String
Floating point variables can store numbers
with decimal points; they can also store integer numbers with a
precision equivalent to 32bits.
Strings contain sequences of characters
(example "my program") and must be terminated by "$".
The strings are not limited in size, they are
only limited by the amount of memory available.
NOTE: The string variables cannot contain
the character with ASCII code 0 (zero) because it is used
internally as an end of string delimiter.
The variables are defined as any name starting
with an alpha character (a, b, ..z) followed by any alphanumeric
character (a..z, 0..9); it can also include the "_"
(underscore).
The case is don’t care, so ‘’Num"
is equivalent to "nuM".
The variable name length is limited to 31
characters maximum, including the "$" for the strings.
There are no limits in terms of number of
variables; the only limit is the RAM memory available.
Example:
NUM = 10.56
myString$ = "this is My
String"
this_is_my_value$
= "ESP8266"
number = 8826621
|
Numeric variables and string variables are
managed separately so the same name can be used; this means that
A and A$ are different variables that can coexist at
the same time (even if this could lead to confusion).
Constants:
The numeric constants can have the following
format :
A =
5 : Z = 1.5
B =
1.23456E5 -> same as 123456
C =
1.23456E+5 -> same as 123456
D =
1.23456E-3 -> same as 0.00123456
The string constants are simply defined as a
text between quotes:
A$
= "This
is my string" : B$ =
"another string"
The strings can include the character "
(quote) simply typing it two times :
A$
= "this
is ""MY"" string"
The | (vertical bar) can also be used
as a string literal.
This permit to include the " (quote) easily
inside a string constant :
A$
= |this
is a "string" constant|
The hexadecimal constants can be defined
simply prefixing it with &h :
E
= &hABCD -> equivalent of decimal
43981 (hexadecimal constant)
F
= &hA0 -> equivalent of decimal
160
The binary constants can be defined simply
prefixing it with &b :
E
= &b00000101 -> equivalent of decimal
5 (binary constant)
F
= &b10000001 -> equivalent of
decimal 129
The octal constants can be defined simply
prefixing it with &o :
E
= &o377 -> equivalent of decimal 255
(octal constant)
F
= &o17 -> equivalent of decimal
15
Arrays:
Arrays are defined using the DIM
command.
Their names follow the same rules as the
regular variables and are followed by parenthesis (brackets)
containing the index. The subscript always starts from 0.
The scope of the Arrays is always global (see
next paragraph).
Example:
DIM
A(100)
define a floating point array with 101 elements (index
from 0 to 100)
DIM
ABC$(50)
define a string array with 51 elements
(index from 0 to 50)
A(15) = 1234.5678
ABC$(49) = "Hi friend!"
The arrays can have up to 5 subscripts
(dimensions), examples:
DIM
A(50,50) -> create a floating point array with
51*51 elements (2601)
DIM
J$(4, 4, 4) -> create a string array with 5 * 5
* 5 elements (125)
Notice that declaring a multi-dimensional
array with multiple subscripts uses elements for every
possible[1] [2] [3] combination of
subscripts, whereas in practice it may be preferable to declare
multiple arrays with the same subscript, eg:
users=4
DIM Name$(users)
DIM Address$(users)
DIM Tel$(users)
Which only uses 5 + 5 + 5 elements
(15)
NOTE:
The numerical Arrays are always
initialised at 0 with the command DIM.
The string Arrays are always initialised
as null string with the command DIM.
There are no limits to the number of
arrays or their size, the only restriction is the RAM memory
available.
The arrays can be re-dimensioned using the
same command DIM.
In this case all the existing elements will
maintain the previous value except the new elements that will be
initialised at 0 or null string.
Example :
DIM A(5)
' all the elements are initialised at
0
A(0)
= 123
Print A(0)
' print 123
Dim A(10)
Print A(0)
' print the same value
123
Print A(10)
' print 0
|
In addition the elements of the arrays can be
initialised with a given value during the command DIM.
Example :
DIM
A(5) = 0, 1, 2,
3, 4, 5 ' set A(0)= 0,
A(1)= 1, A(2)=2, ….
The same can be done with string arrays.
Example :
DIM
A$(5) =
"zero", "one", "two", "three", "four", "five"
Scope of the variables:
Variables and arrays defined in the main code
are global, therefore any variable is accessible from any part of
the code after it has been previously defined there.
Variables and arrays defined inside
“user defined” subroutine (SUB) are visible only inside that sub
and inside all the code called by that subroutine; their content
(and their memory space) is removed at the end of the SUB
The LOCAL command permits defining local
variables inside of "user defined" subroutines; this permits to use
the same name of an “already existing” variable locally without
modifying the original.
As for all the variables defined inside SUB,
they will disappear at the end of the subroutine.
Example:
A
= 10
B
= 20
C
= 30
mysub
"Hello"
PRINT A,B,
C
END
SUB mysub(a$)
LOCAL A,B
A
= 123
B
= 456
C
= 789
D
= 8888
PRINT A$, D
END
SUB
|
In this example, calling the user-defined
subroutine "mysub" will not modify the content of the global
variables A and B (defined locally) but will modify the content of
the variable C (not defined locally) and the variable D will
disappear at the end of the SUB.
Bases of the language
The keywords recognized by the interpreter can
be defined into 3 classes:
●
Operators
●
Commands
●
Functions
The Operators are symbols that tell the
compiler to perform specific mathematical or logical
manipulations.
Commands and Functions both execute an action,
but functions also return a data value.
For example
PRINTis a command and
SIN()
is a function whereas the ‘+’ in a = b
+ 5 is an operator.
The string functions are always followed by
the "$" symbol if they return a string value.
In addition to commands and functions there
are all the internal interpreter internal commands that are part of
the language itself.
OPERATORS AND PRECEDENCE
The following operators are available. These
are listed in the following tables by order of precedence.
Operators on the same line are processed with a left to right
precedence.
Arithmetic operators:
^
|
Power
|
* / \ MOD
|
Multiplication,
division, integer division and modulo (remainder of the
division)
|
+ -
|
Addition and
subtraction
|
Shift operators:
x <<
y
x >> y
|
These operate in a
special way. << means that the value returned will be the
value of x shifted by y bits to the left while >> means the
same only right shifted. They are integer functions and any bits
shifted off are discarded and any bits introduced are set to
zero.
For more
information about the kinds of bitwise shifts, see Bitwise shifts.
|
Logical operators:
<> <
> <=
=>
=
|
Not Equal, less
than, greater than, less than or equal to,
greater than or
equal to, equal
|
AND OR NOT XOR
|
Conjunction,
disjunction, negation, Exclusive OR
|
String operators:
<> <
> <=
>=
=
|
Not Equal, less
than, greater than, less than or equal to,
greater than or
equal to, equal
|
+ &
|
Add strings
together
|
Bitwise operators:
AND OR XOR NOT
|
Binary AND, binary
OR, binary exclusive OR, binary negation
For more
information about the bitwise operators, see
Bitwise Operators
|
The operators AND, OR and XOR are integer
bitwise operators. For example PRINT (3 AND 6) will output 2.
Expressions beginning with open parenthesis
‘(‘ are always considered numerical but the parser is able to
determine if an expression is true or false even if the expression
represents a string.
Each expression representing a comparison,
returns a numerical value of 1 if the expression is true or 0 if
false.
For example 10 = 10 represents a value of 1
whereas 10 = 5
represents a value of 0.
The same logic is applied for string
expressions where "abc" =
"abc" represents a value of 1 and "abc" = "def" represents a
value of 0.
This is very useful in the IF command and also
in other expressions.
For example the following code :
A$ = "on"
If
A$ = "on"
then
pin(4)
= 1
Else
pin(4)
= 0
End
if
|
Can be replaced by
pin(4)
= (a$ =
"on")
The strings can also be compared to determine
the alphabetical order.
To see whether a string is greater than
another, Annex uses the so-called “ASCII” order.
In other words, strings are compared
letter-by-letter.
For example:
("Z"
> "A") is true
("Glow"
> "Glee") is true
("Bee"
> "Be") is true
("Bas"
> "Bat") is false
The algorithm to compare two strings is
simple:
Compare the first character of both
strings.
If the first character from the first string
is greater (or less) than the other string, then the first string
is greater (or less) than the second. We’re done.
Otherwise, if both strings’ first characters
are the same, compare the second characters the same way.
Repeat until the end of either string.
If both strings end at the same length, then
they are equal. Otherwise, the longer string is greater.
In the examples above, the comparison
"Z" > "A" gets
to a result at the first step while the strings"Glow" and "Glee" are compared
character-by-character:
-
G is the same as G.
-
l is the same as l.
-
o is greater than e. Stop here. The first string is greater.
The comparison algorithm given above is
roughly equivalent to the one used in dictionaries or phone books,
but it’s not exactly the same.
For instance, case matters. A capital letter
"A" is not equal to the lowercase "a". Which one is greater?
The lowercase "a". Why? Because the lowercase
character has a greater index in the ASCII table.
Basic internal keywords:
IF command :
The IF can have the following syntax :
1) IF
expression THEN statement
2) IF
expression THEN statement1 ELSE statement 2
3) IF
expression THEN
Statements
ELSE
Statements
END IF
Example:
IF a
> 100 THEN print
"a"
IF b
<a THEN print
"b" ELSE print
"a"
IF c
> d THEN
print "C"
print "is greater"
ELSE
print "D"
print "is greater"
END
IF ' (can also be ENDIF
without space between END and IF)
|
When the conditional is all on one line it
does not need terminating with an END IF
Example
IFa=2
THEN
PRINT "ok"
ELSE PRINT "not
ok"
The AND ,
OR keywords can be used
between the expressions as long as they are in
parenthesis.
Example:
IF
(a=1)
AND (b=2)
THEN PRINT "ok"
Or
IF
((a=2)
AND (b=3)
AND (c =
3)) OR (d=4)
THEN PRINT "ok"
The IF can be nested
Example:
IF
a=2 THEN
IF b = 2
THEN
IF c = 3 THEN
PRINT "ok"
END IF
END IF
END
IF
|
The “THEN” keyword can eventually be removed,
even if this is not recommended.
Example:
IF
a > 100 print
"a" else print
"b"
FOR loop
The FOR loop can
have the following syntax :
FOR
variable=init_value to end_value [step
value]
Statements
NEXT
variable
The ‘step’ value can be positive or
negative
Example:
FOR
i=1 to
5
Print i
NEXT
i
Will print 1, 2, 3, 4, 5
FOR
i=1 to 3
step 0.5
Print i
NEXT
i
Will print 1, 1.5, 2, 2.5, 3
FOR
i=3 to 1
step -0.5
Print i
NEXT
i
Will print 3, 2.5, 2, 1.5, 1
The command
EXIT
FOR can be
used to exit from the loop at any time:
FOR
i=1 to
50
IF
i=10 THEN
EXIT FOR
Print i
NEXT
i
Print
"end of loop"
Optionally, the variable in the
NEXT statement
can be omitted.
This means that this program is valid :
FOR
i=1 to
5
Print i
NEXT
WHILE WEND loop
The WHILE
WEND loop can have the following
syntax :
WHILE
expression
Statements
WEND
The loop is iterated as long as the expression
is true
Example:
i
= 0
WHILE
i < 3
Print i
i = i +
1
WEND
Will print 0, 1, 2
DO LOOP loop
The DOLOOP
can have one of the following 4 syntax :
DO
WHILE expression
Statements
LOOP
DO
UNTIL expression
Statements
LOOP
DO
Statements
LOOP
WHILE expression
DO
Statements
LOOP
UNTIL expression
The command
EXIT
DO can be used to exit from the
loop at any time
Example
i
= 0
DO
Print
i
i = i
+ 0.5
LOOP
UNTIL i >3
Will print 0, 0.5, 1, 1.5, 2, 2.5, 3
i
= 0
DO
Print
i
i = i
+ 0.5
IF
i > 2 THEN
EXIT DO
LOOP
UNTIL i >3
Will print 0, 0.5,
1, 1.5, 2
SELECT CASE
The SELECTcan
have the following syntax:
SELECT
CASE expression
CASE exp1 [: Statements]
Statements
CASE exp2 TO exp3 [: Statements]
Statements
CASE exp4 [,exp5],
... [: Statements]
Statements
CASE ELSE
Statements
END
SELECT
Example:
a =
4
SELECT
CASE a
CASE 1
PRINT "case
1"
CASE 2 :
PRINT "case 2"
CASE 3 :
PRINT "case 3" : PRINT "can continue
on same line"
CASE 4 :
PRINT "case 4"
PRINT "can continue
also on next line"
CASE ELSE:
PRINT "case
else"
END
SELECT
Multiple cases:
a =
4
SELECT
CASE a
CASE1 :
PRINT "case 1"
CASE 2, 3, 5
: PRINT "case 2 or 3 or 5"
CASE4 :
PRINT "case 4"
CASE 6 TO
8 : PRINT "case 6 to 8"
CASE 9 TO 20
: PRINT "case 9 to 20"
CASE ELSE:
PRINT "case
else"
END
SELECT
GOTO
The GOTOcan have
the following syntax :
GOTO
[LABEL | LAB$]
Example
a =
5
IF a
> 5 THEN GOTO
LABEL1
END
....
LABEL1:
PRINT
"This is label1"
....
The goto must be
considered as an obsolete command and is provided just for backward
compatibility with old style Basic programs.
GOSUB
The GOSUBcan have
the following syntax :
GOSUB
[LABEL | LAB$]
The called function
must terminate with the command RETURN
Example
a =
5
IF a
> 5 THEN GOSUB LABEL1
END
....
LABEL1:
PRINT
"This is label1"
RETURN
DATA
The command DATA is used to store constant
information in the program code, and is associated with the command
READ. Each
DATA-line can contain one or more constants separated by commas.
Expressions containing variables will be also evaluated
here.
The goal of the DATA is to avoid repetitive
variable assignation lines, in particular for arrays.
The DATA values will be read from left to right, beginning with the
first line containing a DATA statement. Each time a READ
instruction is executed the saved DATA position of the last READ is
advanced to the next value. Strings must be written in quotes like
string constants. The command RESTORE
resets the pointer of the current DATA position, so the next READ
will read from the first DATA found from the beginning of the
program.
In case READ uses the wrong variable type the error message
"Type mismatch" appears while referring to the line number
containing the READ statement that triggered the condition.
DATA lines may be scattered throughout the
whole program code, but for the sake of clarity they would be
better kept together at the beginning of the program.
The DATA can have
the following syntax :
DATA const1
[,const2] …..
The constants can
be Numerical or String.
Example :
DATA 1, 55.88,
"constant", 99
READ A, B, C$,
D
PRINT A, B, C$,
D
Example without
DATA:
dim colors$(5)
colors$(1)
= "Red"
colors$(2)
= "Green"
colors$(3)
= "Blue"
colors$(4)
= "Yellow"
colors$(5)
= "Magenta"
Same example but
using DATA:
DATA
"Red", "Green",
"Blue", "Yellow", "Magenta"
dim colors$(5)
For i=1
to 5
Read colors$(i)
Next i
END
Define the end of
the program. With this command the program stops.
It can also be
:
END IF -> close the IF command
END SELECT -> closes the SELECT CASE command
END SUB -> closes the user defined SUB
EXIT
Permit to exit from
a loop or a user defined SUB.
The syntax is :
EXIT
DO -> exit from a DO loop
EXIT
FOR
-> exit from a FOR loop
EXIT
SUB
-> exit from a user defined SUB.
SUB
Define a
user-defined subroutine, which the script can use like a command or
function.
User-defined
subroutines are effectively additional commands, so cannot be used
as branch labels.
Permit to create a
user defined command with optional parameters.
The syntax is SUB
subname[(arg1 [,arg2] …)]
The variables are
passed by reference; this means that the arguments, if modified
inside the subroutine, will modify the original variable. This can
be useful to return values from the subroutine (acting like a
function).
It is possible to
pass arrays using the syntax array_name().
Using the
LOCAL command will permit to define local variables (useful
to avoid to modify existing global variables).
Example 1 :
routine cube
SUB
cube(x)
PRINT X ^3
END
SUB
cube 3 ' will print 27
|
Example 2:
routine cube with returning argument
SUB
cube(x,y)
y = x ^3 ' the value is returned using the 2nd
argument
END
SUB
ret
= 0
cube 5,
ret
PRINT
ret
' will print 125
|
Example 3:
routine with local variables and returning argument
SUB left_trim(s$,
ret$)
LOCAL i
i
= 1
DO UNTIL i =
len(s$)
IF
mid$(s$, i, 1) <>
" " THEN EXIT
DO
i = i + 1
LOOP
ret$ = mid$(s$,
i)
END
SUB
z$
= ""
FOR i
= 1 to 3
left_trim " remove space from
left ", z$
PRINT z$ + "--"
NEXT i
|
Will print
remove space from
left --
remove space from
left --
remove space from
left --
As you can see in
this example, the variable i in the FOR loop is not modified by the
LOCAL variable i in the subroutine.
Example 4:
pass arrays
SUB pass_array(f(),
c$())
Dim myArray(10)
myArray(0)
= 456
Print f(0),
c$(0), myArray(0)
f(1) =
123
c$(1) =
"myText"
END
SUB
Dim alpha(10)
Dim beta$(10)
alpha(0)
= 456
beta$(0)
= "testme"
Pass_array
alpha(), beta$()
Print alpha(1),
beta$(1)
|
In this example,
the array alfa() is passed locally to the array f()
and the array beta$() is passed locally to the array
c$().
Modifying locally
these arrays change the value of the original one as their content
is passed by reference.
The array
“myArray” will disappear at the end of the SUB
Logical
/ boolean Operations
As the numerical
variables are stored internally as double precision floating
numbers, it is possible to store numbers with a precision
equivalent to 32 bits.
Several boolean
operators are available to manipulate these numbers..
The first operator
is the bit shift; it can be shift left
<< or shift right >>
This operator
permits to shift the number of a specified number of positions to
left or right.
Example
A
= 1
Print A
<< 3 ' will print 8
A
= 16
Print A
>> 2 ' will print 4
The operators
AND
,
OR ,
XOR are also available :
A
= 24
A
= 15
Print A
AND B '
will print 8
A
= 24
A
= 15
Print A
OR B '
will print 31
A
= 24
A
= 15
Print A
XOR B '
will print 23
The unary operator
NOT
is also available. It inverts all the bits from 0 to 1:
A
= 0
Print
Hex$(NOT A)
' will print
FFFFFFFF
For a 32 bits
number, assuming 4 bytes ABCD where A is the MSB and D the LSB, the
bytes can be extracted as follows :
VAR
= &h12345678 ' this is a 32 bits variable
D = VAR
AND &hFF
C = (VAR
>> 8) AND
&hFF
B = (VAR
>> 16) AND
&hFF
A = (VAR
>> 24) AND
&hFF
For more
information, see
Bitwise
Operators
ERRORS
HANDLING
Annex allows to control and manage errors that
occur during the execution of the code.
This is managed with the command ONERROR.
This command defines what action is taken when
an error occurs, and applies to all errors, including syntax
errors.
It can be used in different ways, as specified
in the table below:
FUNCTIONS / COMMANDS
|
DESCRIPTION
|
ONERROR
ABORT
|
Displays the error message then aborts the
program.
This is the normal behaviour and is the
default when a program starts running.
|
ONERROR
IGNORE
|
Any error will be simply ignored.
As this can make it very difficult to debug a
program it should be used wisely.
|
ONERROR
SKIP
[nn]
|
Ignore an error in the next command(s)
executed after the current command (the number of skipped commands
depends on whether the number ‘nn’ is specified).
'nn' is optional, the default is 1
if not specified.
After the number of skipped commands has
completed (with an error or not) the behaviour will revert to
ONERROR ABORT.
|
ONERROR
CLEAR
|
Reset the eventual pending error
|
ONERROR
GOTO [label
| OFF]
|
Jumps to the error handling routine defined by
the label.
It can be removed (hence reverting to ONERROR
ABORT) replacing the label with OFF.
Using RETURN inside the error handling routine
will continue the execution on the line following the error.
|
When an error occurs, the following constants
are available :
CONSTANT
|
DESCRIPTION
|
BAS.ERRLINE
|
Returns the line
number where the error happened. Value of 0 means no error.
It is reset to 0
with the command ONERROR CLEAR or running the program or with
the command ONERROR IGNORE or ONERROR SKIP.
|
BAS.ERRNUM
|
Returns a number
where non zero means that there was an error.
It is reset to 0
with the command ONERROR CLEAR or running the program or with
the command ONERROR IGNORE or ONERROR SKIP.
|
BAS.ERRMSG$
|
Return a string
representing the error message that would have normally been
displayed on the console. It is reset to “No Error” running the
program or with the command ONERROR CLEAR or ONERROR IGNORE or
ONERROR SKIP.
|
Example of error handling using the command
ONERROR GOTO :
ONERROR
GOTO
Error_Handler
Print
"start"
Print
3/0
' this generates a divide by zero
error
Print
space$(60000)
' this generates an out of memory
error
End
Error_Handler:
Print
"Error text
"; BAS.ErrMsg$
Print
"Error
num "; BAS.ErrNum
Print
"Error line
"; BAS.ErrLine
Return
' returns to
the line following the error
|
HOW the
interpreter works with the HTML code and Objects :
When a client
connects to the module using its IP address, the module will
redirect automatically to the url ‘/output?menu’, which sends an
empty html page present on the module.
That page contains
a bunch of javascript code permitting to interface the page with
the module using javascript.

This page will
automatically open a websocket connection with the module; the
"squared led" indicates if the connection was successful (green) or
not (red).
A mechanism of ping
- pong has been implemented into the javascript in order to hold
the connection alive all the time. If the connection is lost, the
page will try to reconnect automatically without any manual
action.
The button
"reconnect" permits to force the reconnection if the automatic
reconnection fails.
As soon as the
connection is done with the module, the html page is ready to send
and receive messages to / from the module.
Initially the page
is empty but its content can be easily filled.
To send HTML code
to the page, the command HTML is used.
The syntax is :
HTML HTML code.
For example the
line
HTML
"Hello, world <br>This is my first html
content<br>"
Will give this
result :

Continuing with the
HTML command, the content can be improved :
HTML
"Textbox: <input
type='text'><br>"

Continuing
again:
HTML
"Button: <button type='button'>Click
Here</button>"

All the html code
can be combined and sent with just one HTML command; this is much
faster:
a$ =
"Hello, world <br>This is my
first html content<br>"
a$ = a$
+ "Textbox: <input
type='text'><br>"
a$ = a$
+ "Button: <button type='button'>Click
Here</button>"
HTML
a$
|
To clear the
content of the page, the command is:
CLS

Now we can try
another example
CLS
a$ =
"Now style me,
please<br>"
a$ = a$
+ "Button1: <button id='but1'
type='button'>ON</button> "
a$ = a$
+ "Button2: <button id='but2'
type='button'>OFF</button>"
HTML
a$

Now we will try to
style the buttons using css.
This can be done
using command CSS CSSID$()
For example the
line
CSS
CSSID$("but1",
"background-color:
red;")
Will give this
result :

Combining with the
style for the other button:
a$ = a$
+ cssid$("but1",
"background-color:
red;")
a$ = a$
+ cssid$("but2",
"background-color:
green;")
CSS
a$

A set of functions
is included to simplify the creation of HTML pages as we will see
later, so no need to worry if you are not familiar with writing
HTML code.
Now we will mention
an important ‘event’ that can be used to automatically fill the
content of the page each time a client connects to the module :
OnHtmlReload.
This ‘event’
defines a place where the program will jump to as soon as a
Websocket connection request is accepted.
Let’s clarify with
an example :
OnHtmlReload
Fill_Page
‘will jump to Fill_Page when the
page is reloaded
gosub
Fill_Page
'load the page for the first
time
Wait
‘pause waiting for the event
Fill_Page:
‘place where the page begins to
be created
CLS
a$ = "Now style me,
please<br>"
a$ = a$ +
"Button1: <button id='but1'
type='button'>ON</button> "
a$ = a$ +
"Button2: <button id='but2'
type='button'>OFF</button>"
HTML
a$
a$ = cssid$("but1",
"background-color:
red;")
a$ = a$ +
cssid$("but2",
"background-color:
green;")
HTML
a$
RETURN
|
The result will
be:

Now try to play
with the button "Reconnect"; you’ll see that, at each time the page
reconnects to the module, the HTML content is built and sent again.
This ensures that each time a client connects to the module it will
receive the correct content. At the same time, if other clients are
already connected, the content of all the pages will be refreshed
simultaneously. This ensures a synchronized content between all the
clients.
HTML Objects
As said previously,
in order to simplify the creation of HTML pages there are several
functions available which can generate the html code
automatically.
Let’s start with
the button.
A button is an
object that is used to trigger an action each time it is pressed on
the web page.
The function is
BUTTON$.
Let’s explain with
an example:
CLS
HTML
BUTTON$("Button1", jump1)
Wait
'pause waiting for the
event
Jump1:
PRINT
"Clicked on Button1"
Return
|
The result will
be:

Try clicking on the
button then checking the result in the terminal console; the
message "Clicked on Button1" will be shown at each click.

To style the
button, we need to modify the syntax of the BUTTON$
command slightly; in fact we need to add another parameter to give
the button an ID:
CLS
HTML
BUTTON$("Button1", jump1, "but1") '
"but1" is the ID
Wait
'pause waiting for the
event
Jump1:
PRINT
"Clicked on Button1"
CSS
cssid$("but1",
"background-color:
red;") 'the same ID is used here
Return
|
Clicking on the
button now will change its color to red

Now we can now
introduce the LED object. The LED object is a circle that can be
filled in red or green depending on the content of a variable. The
function is LED$
As usual, let’s
start with an example:
CLS
led = 1 ‘this is the variable
associated with the LED. With 0 the led is red, with 1 the led is
green
HTML
LED$(led)
|
The result will
be:

Let’s also add a
button :
CLS
led
= 0
a$
= BUTTON$("Button1", jump1, "but1") '
"but1" is the ID
a$
= a$ + LED$(led)
HTML
a$
Wait
'pause waiting for the
event
Jump1:
PRINT
"Clicked on Button1"
led
= 1 -
led ' invert the
variable
REFRESH
' refresh (update) the variables between the code
and the html
Return
|
The result will
be:

Clicking on the
button will toggle the led between red and green colors.
The command
REFRESH
permits to update (synchronize) the variables in the code with the
corresponding objects variables on the web page. It should be run
each time a variable is modified.
As a simpler
alternative, the command AUTOREFRESH
will regularly sync the variables.
The command must be
run with the desired refresh timing.
Example
AutoRefresh
500 will refresh the variables each 500
milliseconds.
The interval
should not be less than 300 milliseconds (otherwise the module will
be too busy).
The example :
CLS
led = 0
a$ = BUTTON$("Button1", jump1, "but1") '
"but1" is the ID
a$ = a$ +
LED$(led)
HTML
a$
AutoRefresh
300
'sync each 300
milliseconds
Wait
'pause waiting for the
event
Jump1:
PRINT
"Clicked on Button1"
led = 1 - led
' invert the
variable
Return
|
The result will be
the same as the previous example.
Now it’s time to
introduce another object; the TEXTBOX with the corresponding
function TEXTBOX$.
The TEXTBOX will
display a ‘text box’ on the web page which is linked with a
variable. When the variable is modified in the code, the TEXTBOX
content will be updated on the web page, and vice-versa.
This lets us
introduce another ‘event’, the OnHtmlChange
command.
This ‘event’
defines a branch for the program to jump to whenever a variable is
modified inside the web page.
As usual, let’s
start with an example:
CLS
text$ = "Change me,
please"
HTML
TEXTBOX$(text$)
OnHtmlChange
Jump1
'will jump to Jump1 when a variable
changes on the web page
Wait
'pause waiting for the
event
Jump1:
Print
text$
'print the content of the variable
inside the terminal console
Return
|

Try now to change
the content of the textbox and press "Enter" on the keyboard.
Let’s see the
result in the terminal console:


With the concepts
already learned you’ll be able to use the other objects using the
similar logic.
Refer to the pages
below to understand the syntax of each object.
TIMERS
A timer is an "object" that permits the
execution of a particular action at regular intervals.
When the given time expires, the normal
execution of the program is interrupted while control is passed to
the "timer interrupt routine" until after the execution of the
return command.
Then the program continues from the point
where it was interrupted.
Let’s explain with an example :
timer0
1000,
mytimer
wait
mytimer:
wlog "mytimer " +
time$
return
|
Annex WI-Fi Basic
implements 2 timers, Timer0 and Timer1.
The Timer0 has a
higher priority against Timer1.
Many of the actions
are not executed directly by basic commands but can be executed as
asynchronous events.
An "event" is
simply an action that can be executed when something happens.
For example, pin
change interrupts are asynchronous events which can happen at any
time without user control.
In order to manage
the events, a list of commands "ONxxxx" is provided. These commands
define the place where the normal execution of the program will
branch to when the event occurs.
So, when the
"event" happens, the basic interpreter interrupts the normal
execution of the code and "jumps" to the location defined by the
corresponding command "ONxxx". As soon as the code associated with
the "event" is terminated with the command "return", the basic
interpreter continues from the previous interrupted location.
Button Event
This is a special event that happens every
time aBUTTON$
object is clicked in the HTML pages.
When this happens,
a special variable
HtmlEventButton$ is created containing the name of the
button that was clicked.
This is useful to
determine the button within a group of buttons.
Let’s see an
example:
CLS
HTML
Button$("ON",
buttonEvent) +
" " + Button$("OFF",
buttonEvent)
wait
buttonEvent:
print
"You clicked
on ";
HtmlEventButton$
return
|
OnHtmlChange Event
This event is triggered when an object present
in the HTML output page changes its value.
It is useful to make actions when something
changes in the HTML Pages.
When this event
happens, a special variable
HtmlEventVar$ is created containing the name of the
variable that changed its value.
This is useful to
determine the object that generated the event.
Let’s see an example :
CLS
text$ = "Change me,
please"
HTML
TEXTBOX$(text$)
OnHtmlChange
Jump1
'will jump to Jump1 when a variable
changes on the web page
Wait
'pause waiting for the
event
Jump1:
Print
text$
'print the content of the variable
inside the terminal console
Return
|
Note that the
special variable
HtmlEventVar$ is only created when the OnHtmlChange
event populates it due to a html object change, therefore it will
cause an error if tested for before an object is changed unless
specifically defined beforehand, eg: HtmlEventVar$ =
“”
OnHtmlReloadEvent
This event is triggered when a Websocket
connection request is accepted.
This can be used to automatically fill the
content of the WEB page each time a client connects to the
module.
Let’s see an example :
CLS
OnHtmlReload
Fill_Page
'will jump to Fill_Page when the page
is reloaded
gosub
Fill_Page
'load the page for the first
time
Wait
'pause waiting for the
event
Fill_Page:
'place where the page begins to be
created
CLS
a$ = "Now style me,
please<br>"
a$ = a$ +
"Button1: <button id='but1'
type='button'>ON</button> "
a$ = a$ +
"Button2: <button id='but2'
type='button'>OFF</button>"
HTML
a$
a$ = cssid$("but1",
"background-color:
red;")
a$ = a$ +
cssid$("but2",
"background-color:
green;")
HTML
a$
Return
|
OnInfrared Event
This event is
triggered when a code is received by the infrared receiver.
Refer to chapter
INFRARED INTERFACE for more details.
OnSerial Event
This event is
triggered when a message is received on the serial port.
Example:
print
"Ram Available "; ramfree
onserial rec1
wait
rec1:
'print serial.input$
print serial.chr$;
return
|
OnSerial2 Event
This event is
triggered when a message is received on the serial port #2.
Example
serial2.mode 9600, 2, 5
' set serial port #2 to 9600 pin 2 TX,
pin 5 RX
print2 "Ram Available "; ramfree
onserial2 rec2
wait
rec2:
print serial2.input$
return
|
OnTouch Event
This event is
triggered when the TFT screen is touched.
Refer to the
chapter TouchScreen for more details.
OnUDP Event
This event is
triggered when a UDP message is received.
Example:
udp.begin
5001
'set the UDP commmunication using port
5001
onudp
goudp
'Write several messages to the port
for i
=
0 to 100
udp.write
"192.168.1.44",
5001,
"Hello "
+
str$(i)
next i
wait
goudp:
v$
=
udp.read$
'receive the UDP data
print
v$
return
|
OnWgetAsync Event
This event is
triggered when a WgetAsync message is received.
This is associated
with the command
WGETASYNC.
The goal of the
WGETASYNC command is to start a html get request without
the module having to wait for the answer.
Because the
response is async, this command specifies the location where the
program should branch to when a message is received.
Example:
ONWGETASYNC
answer_done
WGETASYNC("www.fakeresponse.com/api/?sleep=5",
80)
For
i =
0 to
10000
' a
kind of sleep just to demonstrate that the code continue to
run
Print i
Next
i
Wait
answer_done:
Print
WGETRESULT$
Return
|
OnUrlMessage Event
This event is
triggered as soon as a web client requests for a web page with the
url composed with http://local_ip/msg?param=value.
This kind of request is typically called an AJAX request as it
permits to exchange in both directions between the client (the web
browser) and the server (the ESP module).
In fact, in the url
request, the client can send parameters in the form of couples of
"param=value" separated by the character "&". For example, if
the client wants to send 2 parameters, it can send the following
request :
http://local_ip/msg?param1=value1¶m2=value2.
As soon as this
message is received by the ESP module, the event OnUrlMessage is
triggered; this means that the program will continue from the
location defined by the command OnUrlMessage.
As soon as the
message is received, the parameters sent by the client can be got
with the function UrlMsgGet$ and a message can be sent back to the
client with the command UrlMsgReturn.
Let’s see an
example :
onUrlMessage
urlAjax
wait
urlAjax:
wlog
"message received " + UrlMsgGet$("a")
+ "
" + UrlMsgGet$("b")
UrlMsgReturn
"Message sent back " + time$
print
UrlMsgGet$("b"),
ramfree
return
|
Now using another
web browser window, let’s type the following url :
http://esp_local_ip/msg?a=10&b=20
As you can see in
the following picture, the message is received by the ESP
module

At the same time,
the client receives the message sent back from the ESP module

If the program is
stopped, the module will answer with the message "STOPPED"

Now, let’s see a more complete example :
cls
' this is the
default value for pwm out
R
= 512
G
= 512
B
= 512
'Setup the
pwm channels
PWM.SETUP
12, 1, R,
10000, 10
PWM.SETUP
15, 1, G,
10000, 10
PWM.SETUP
13, 1, B,
10000, 10
'Set the
default values
PWM.OUT
1,
R
PWM.OUT
2,
G
PWM.OUT
3,
B
' these are
the sliders
a$
= ""
a$
= a$ + |R <input
type="range" id="dimmer_R" oninput="setPWM()" onclick="setPWM()"
min="0" max="1023" value="| & str$(R)
& |"/><br>|
a$
= a$ + |G <input
type="range" id="dimmer_G" oninput="setPWM()" onclick="setPWM()"
min="0" max="1023" value="| & str$(G)
& |"/><br>|
a$
= a$ + |B <input
type="range" id="dimmer_B" oninput="setPWM()" onclick="setPWM()"
min="0" max="1023" value="| & str$(B)
& |"/><br>|
a$
= a$ + |<input
type='text' id="txbox" value='---'>|
html
a$
'this is the
javascript "AJAX" code
fun$
= |function setPWM() {|
fun$
= fun$ & |r=_$("dimmer_R").value;|
fun$
= fun$ & |g=_$("dimmer_G").value;|
fun$
= fun$ & |b=_$("dimmer_B").value;|
fun$
= fun$ & |var xmlHttp =
new XMLHttpRequest();|
fun$
= fun$ & |xmlHttp.open("GET", "msg?r=" + r +"&g=" + g
+"&b=" + b, false);|
fun$
= fun$ & |xmlHttp.send(null);|
fun$
= fun$ & |r =
xmlHttp.responseText;|
fun$
= fun$ & |_$("txbox").value = r;|
fun$
= fun$ & |return
r;}|
' this is
where the javascript code is inserted into the html
jscript
fun$
'this is
where the prog will jump on slider change
onUrlMessage
message
wait
message:
print
UrlMsgGet$()
PWM.OUT
1,
val(UrlMsgGet$("r"))
PWM.OUT
2,
val(UrlMsgGet$("g"))
PWM.OUT
3,
val(UrlMsgGet$("b"))
UrlMsgReturn
UrlMsgGet$()
return
|
Open the input page in another window and run
the program

Using an external RGB led, you’ll be able to
directly control its color.
You’ll see how the exchanges can be fast using
AJAX exchanges. This program uses javascript embedded into the
code. The javascript works with the function XMLHttpRequest.
A good reference for this function is here
AJAX - Send a Request To a Server
OnEspNowMsg Event
This event is
triggered when a ESP-NOW message is received.
Example:
espnow.begin
' init the ESP-NOW
onEspNowMsg message
' set the place where jump in case of message
reception
wait
message:
print "Message
Received!"
return
|
OnEspNowError Event
This event is
triggered when a ESP-NOW transmission error occurs.
This happens, in
particular, when the receiver device has not received the
message.
espnow.begin
' init the ESP-NOW
espnow.add_peer "60:01:94:51:D0:7D"
' set the MAC address of the receiver
onEspNowError status
' set the place where jump in case of TX error
espnow.write "TX
message"
' send the message
wait
status:
print "TX
error on ";
espnow.error$
' print the error
return
|
OnMQTT Event
This event is generated when a MQTT message is
received or an MQTT event happens
Example:
....
onmqtt
mqtt_msg
wait
' receive messages from the server
mqtt_msg:
print
"TOPIC : ";
mqtt.topic$
print
"MESSAGE: ";
mqtt.message$
return
|
This event is generated when a “metadata” is
decoded when playing mp3 or streaming a web radio.
WiFI CONNECTIONS
At startup, the module will try to
connect to the router using any parameters specified in the page
“Config”.
If no parameters are specified in
the “Config” page, or the connection is unsuccessful, it will
default to AP (Access Point) mode with IP address 192.168.4.1 with
the SSID composed of ESP(+ mac address).
If the connection is successful,
the module will use the IP address defined in the “Config” page or,
if no IP address is specified, the IP will be given automatically
by the Router DHCP server.
After the module has connected to
the router it will try to reconnect automatically if the connection
is lost.
There are several commands /
functions available to manage the WIFI.
The first function is
WIFI.STATUS which permits to get the status of
the connection.
print
WIFI.STATUS ’ print 3 if connected, 6 if
disconnected
The first useful command is
WIFI.CONNECT
SSID$, password$ [,
BSSID$] [, IP$ , MASK$ [, GATEWAY$]]
This command allows you to connect
to any WIFI network (STA mode) overriding the parameters defined
into the’ “Config” page. This function is async so the connection
is done in background, while the program continues to
run.
Is then possible to check the
status of the connection using the function
WIFI.STATUS
Example :
WIFI.CONNECT
"HOMENET", "MyPassword"
print
"connecting"
While
WIFI.STATUS <>
3
Print "."
pause 500
wend
Using the optional
parameter
BSSID$,
will enable the connection to a specific WiFi access
point.
The BSSID represents the MAC
address of the WiFi access point (the router) and it is defined as
6 bytes in hex format separated by colon, i.e.
AA:BB:CC:12:34:56.
For stand alone configuration or
for ESP-NOW applications, there is another command that puts the
module in AP mode.
This command is
WIFI.APMODE
SSID$,
password$ [, channel]
[,
IP$ , MASK$]
The result is immediate and the
status can be checked using the function
WIFI.MODE (see below).
The channel is optional and is 1
by default.
It is eventually possible to
control the output power of the module with the command
WIFI.POWER pow
WIFI.POWER 5
’ set the output power
at 5 dBm.
The module can also be put in WiFi sleep mode.
This mode permits to turn off the WiFi reducing the power
requirements of the module; this is very useful for battery
oriented applications or for applications where the WiFi is not
required.
To put the module in “modem-sleep”, the
command to execute is
WIFI.SLEEP.
The module will stay in that mode until the
execution of the command
WIFI.AWAKE.
After this command, the module will reconnect
automatically to the router (the command
WIFI.CONNECT is not required).
Another function available
is
WIFI.CHANNEL that shows the current Radio
Channel used by the WIFI.
Using the function
WIFI.RSSI is it possible to get the
intensity of the signal received (RSSI)
It is also possible to scan for
the WiFi networks accessible around the module.
This can be done using the
command
WIFI.SCAN and the function
WIFI.NETWORKS(network$).
Example :
WIFI.SCAN
While
WIFI.NETWORKS(A$)
=
-1
Wend
Print
a$
The result will be :
Vodaphone, 00:50:56:C0:00:08,
-50, 5
Orange, 00:50:56:C0:32:07, -70,
5
Xxxx,
00:50:56:C0:86:CA,-78, 12
These information represent, in
the order :
SSID, BSSID(mac address),
RSSI(signal intensity), Channel Radio
The function
WIFI.MODE returns the current mode of the WIFI
connection as below:
VALUE
|
MEANING
|
0
|
The WIFI is in sleep
mode
|
1
|
The WIFI is in STATION
mode
|
2
|
The WIFI is in AP mode
|
3
|
The WIFI in AP+STA mode
|
The WIFI in AP+STA mode can
be obtained by configuring the module in AP mode and then using the
command
WIFI.CONNECT in the program.
Using a “fake” SSID / password
(example
WIFI.CONNECT
"A",
"" ) can be used to switch the WIFI
into the AP+STA mode. This can be useful for mixed ESP32 /
ESP8266 ESP-NOW operations.
Another Wifi related command
is
OPTION.MAC
mac$ that
permits to modify the MAC address of the module.
This is very important for the ESP
Now functionality.
Example :
OPTION.MAC
"AA:BB:CC:DD:EE:FF"
In addition, the functions
BAS.SSID$ and
BAS.PASSWORD$ returns respectively the login and
the password used for the STATION wifi connection.
PROGRAM AUTORUN
If a program is defined to run automatically
(“Autorun File” in the config page), the WiFi connection process is
slightly different.
If the option “Fast boot” in the config page
is selected, the program will be executed immediately and the WiFi
will be powered ON after a little delay ( 0.1 sec ).
If the command
WIFI.SLEEP is executed during the very beginning of the
program ( for example as the first line of the program) the WiFi
will be simply disabled without using any power.
This enhances the use of the module in low
power applications (i.e. on battery).
The WiFi connection can then be restored later
using the commands
WIFI.CONNECT or
WIFI.APMODE.
If the command WIFI.SLEEP is not executed at
the beginning of the program, the WiFi connection will be
established by default as described in the previous chapter
(WiFI CONNECTIONS).
The function
BAS.RESETREASON can be used at the beginning of the
program to understand the reasons for the restart of the module
enabling it to take the appropriate actions.
RECOVERY MODE
In case of any IP or Autorun problem
preventing the module from being accessed, it is possible to
temporarily bypass the IP settings of the module and disable the
Autorun file by connecting the serial TX and RX pins together
(GPIO1 to GPIO3) during the startup phase (power up).
This could happen if, for example, a wrong IP
address has been set.
Doing this action when restarting the module
will put it in AP mode with the IP address at 192.168.4.1, just
like a module that has not been configured.
A message “Recovery Mode” will be printed on
the console, but none of the existing files on the module will be
modified, including the internal configuration parameters.
In this mode it will be possible to gain
access to the module for changing such correct wrong IP parameters
using the configuration page.
When the TX/RX link is removed, the module can
be rebooted to the configured settings at the next restart.
SLEEP mode (low energy) and RTC
memory
The module can be put into low energy mode to
minimise as much as possible the power requirements.
This mode is called deep sleep and
should reduce the power consumption to a few µA but this is a
function of each ESP32 module as the power requirement
includes the different components installed on the module.
When the module is put into deep sleep all the
module activities are stopped, all the memory content of the module
is lost except for the RTC memory (this is a special memory block
inside the module that holds its content even if the module is
reset, but not when the module is powered OFF).
At the end of the sleep period, the
module restarts and reloads the program defined as autorun from the
beginning (from the first line).
To put the module in deep sleep the following
command is available :
SLEEP
value [, pin, level]
This command puts the ESP32 in deep sleep (low
energy) for 'value' seconds.
At the end of the period, the unit will reboot
and reload the default basic program.
Example
' Sleeps for 600 seconds (10 minutes)
Optionally, it is possible to wake up the
module using an external signal sent on an input pin
In this case the pin and the level must be
specified in addition to the time value.
Example
' Sleeps for 3600 seconds (1 Hour) or until the pin 32 goes to
high
SLEEP
3600, 32, 1
Only RTC IO can be used as a source for
external wake up.
They are pins: 0,2,4,12-15,25-27,32-39.
Level is 1 for wakeup on High and 0 for wakeup
on Low
The RTC memory will survive after the wake up
permitting to take trace of the actions done before the sleep.
This memory can be set as below :
BAS.RTCMEM$ =
"data to be saved during deep sleep"
And can be read as below :
A$
=
BAS.RTCMEM$
Note : the RTC memory can hold up to 7680
bytes
DATE - TIME timekeeper
The ESP module normally synchronises its date
and time from either of two NTP time servers ("pool.ntp.org" and
"time.nist.gov"). Optionally an alternative (eg: intranet) time
server can be defined using the [CONFIG] page.
Using these servers the ESP doesn’t require
any date/time setting (except the configuration of the Time Zone
and DST done using the [CONFIG] page).
The timezone is defined as a string
likeCET-1CEST,M3.5.0,M10.5.0/3
that describes how the local time must be managed in terms of time
shift and DST (summer / winter time).
A complete list of timezone strings can be
found here :
https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
An internal timekeeper has been included if no
time server is available, e.g. no available internet access.
This timekeeper starts from 01/01/1970
00:00:00 and counts the seconds since the power on of the
module.
If internet connection becomes available
later, the internal timekeeper will sync its time with the NTP
servers.
The time can be sync with the NTP time server
at any moment using the command
OPTION.NTPSYNC.
This time and date can be manually set using
the command SETTIME.
The Syntax is :
SETTIME year, month, day, hours, minutes,
seconds
Example
Set the date to 02 September 2017 at
13:58:12
SETTIME 17, 9, 2,
13, 58, 12
The time and date can also be
manually synchronised to the computer using the "Time Sync" button
in the File Manager window of the computer utility ‘tool’ if it has
a websocket connection.
WARNING:
In both cases of manual
setting, the time and date will default back to 1970 defaults at
the next module restart, so will require setting
again.
For more information about the
Time Zones and DST, please consult the following page
:
Time Zone and
DST
It is also possible to connect
an RTC (DS1307 or DS3231) to the module.
See the chapter
“RTC
Module”
for more details.
Unix Time functions
The following functions use the
“Unix Time Stamp” format :
DATEUNIX(date$),
TIMEUNIX(time$),
UNIXDATE$(value [,format]),
UNIXTIME$(value)
The “Unix Time Stamp” is a way
to track time as a running total of seconds.
This count starts at the Unix
Epoch on January 1st, 1970 at UTC.
Therefore, the unix time is
merely the number of seconds between a particular date and the Unix
Epoch.
In synthesys :
-
DATEUNIX("01/01/18")
returns the number
of seconds from 01/01/1970 to the specified date 01/01/2018
(1514764800)
-
TIMEUNIX("12:30:55")
returns the number
of second since midnight (45055)
-
UNIXDATE$("1532773308")
returns
28/07/18
-
UNIXTIME$(1532773308)
returns
10:21:48
FAT32
File System
Annex32 includes a
FATFS file system hosted on the flash memory chip.
It “emulates” a
disk file system enabling it to save and load files in a
transparent way.
Depending on the
size of the flash chip, the following free space is available :
Flash Chip size
|
Free space available
|
4M
|
1MB
|
[6] 8M
|
5MB
|
16M
|
13MB
|
Annex32 can also
use an SD CARD connected as described in the chapter SD CARD
ADAPTER.
Both the internal
FATFS and the SD CARD utilise the FAT32 file system
This means that
there are no particular limitations in terms of filename length and
directories, compared to the SPIFFS file system limitations hosted
in the ESP8266.
Unlike normal
variables, filenames and folders are case sensitive.
Annex32 supports SD
CARDS up to 16GB.
The internal and the external (SDcard)
space are mutually exclusive and cannot be accessed at the same
time.
By default Annex32 will use the SD, if
available, otherwise it will use the internal flash disk space
(FATFS).
Both the
internal FATFS and external SD CARD share the same command and
functions.
All the file
related functions share the same prefix FILE.
followed by the specific function.
FUNCTIONS / COMMANDS
|
DESCRIPTION
|
Ret = FILE.COPY(filename$, newfile$)
|
Copy the file filename$
into the file newfile$
Returns 1 in case of success or
0 if error
|
Ret = FILE.DELETE(filename$)
|
Delete the file specified by filename$
Returns 1 in case of success or
0 if error
|
Ret = FILE.EXISTS(filename$)
|
Returns 1 if filename$
exists, otherwise returns 0
|
Ret = FILE.RENAME(oldname$, newname$)
|
Rename the file oldname$
to newname$
Returns 1 in case of success or
0 if error
|
Ret = FILE.SIZE(filename$)
|
Returns the size of the file (in bytes) if the
file exist, otherwise returns -1
|
Ret = FILE.MKDIR(dirname$)
|
Create a directory specified by
dirname$
Returns 1 in case of success or
0 if error
|
Ret = FILE.RMDIR(dirname$)
|
Remote the directory specified by
dirname$
Returns 1 in case of success or
0 if error
|
Ret$ = FILE.DIR$(path$)
|
Will search for files and return the names of
entries found.
path$
represents the directory name.
path$ can
include wildcards characters as ‘*’,
‘.’ and
‘?’
The function will return the first entry
found.
To retrieve subsequent entries use the
function with no arguments. ie,
FILE.DIR$.
The return of an empty string indicates that
there are no more entries to retrieve.
|
Ret$ = FILE.READ$(filename$,
[line_num] | [start, length])
|
Returns the content of the file
filename$.
Specifying line_num,
only the corresponding line is read from the file.
If start
and length
options are specified, the file is read from the start
position for length
characters, otherwise the complete file is read in one go
The line number
starts from 1.
|
FILE.APPEND
filename$,
content$
|
Append the content of content$
to the file filename$.
If the file does not exist, it will be
created.
The file can be read back using the function
FILE.READ$(filename$)
File size is only limited by available disk
space (internal FFAT or external SD card)
|
FILE.SAVE
filename$,
content$
|
Save the content of content$
to the file filename$.
The file can be read back using the function
FILE.READ$(filename$)
File size is only limited by available disk
space (internal FFAT or external SD card)
|
FILE.WRITE
filename$,
content$
|
Same functionalities as the previous
command.
Implemented for homogeneity with other
commands
|
FILE.SAVE_IOBUFF
|
See the chapter I/O buffer for more
details
|
[7] FILE.WRITE_IOBUFF
|
See the chapter I/O buffer for more
details
|
[8] FILE.APPEND_IOBUFF
|
See the chapter I/O buffer for more
details
|
FILE.READ_IOBUFF
|
See the chapter I/O buffer for more
details
|
Examples:
List all the files
in the directory /html
d$
= FILE.DIR$("/html")
While D$
<> ""
wlog d$
d$
= FILE.DIR$
Wend
|
File operations
file.save
"/test.bas",
"The quick brown fox "
wlog
"exists",
file.exists("/test.bas")
wlog
"size",
file.size("/test.bas")
file.append
"/test.bas",
"jumps over the lazy dog"
wlog
"size",
file.size("/test.bas")
wlog
"copy",
file.copy("/test.bas",
"/AAA.bas")
wlog
"size",
file.size("/AAA.bas")
wlog
"rename",
file.rename("/AAA.bas",
"/BBB.bas")
wlog
"size",
file.size("/BBB.bas")
wlog
"size",
file.size("/AAA.bas")
wlog
"read",
file.read$("/test.bas")
wlog
"delete",
file.delete("/BBB.bas")
|
I/O
BUFFERS
The I/O BUFFER is a functionality that gives
the capability to hold and manage binary data.
In short, the I/O buffer is a block of RAM
memory that can be exchanged as a block or read and written byte
per byte. It overcomes the limitation of strings, which are
unable to include the character ASCII 0 (NUL).
It has a defined length and can be freely
dimensioned and cleared.
It can be used in the code using the
IOBUFF keyword, and Annex exposes 5 I/O buffers numbered
from 0 to 4.
The I/O buffers can have any size within the
limits of the free RAM memory available.
The main goal of this functionality is to
interface with all the functions that require exchanges using
binary data.
In the current implementation it can be used
with :
-
Files
-
Serial Ports
-
SPI
-
I2C
-
UDP
As it is essentially a block of memory,
the first command is
IOBUFF.DIM(buff_num,
size) that defines its
size.
buff_num
can span from 0 (first buffer) to 4 (last buffer)
size
can span from 0 to the maximum RAM memory available
Example:
IOBUFF.DIM(0,
1000) 'dimension the I/O buffer 0 with 1000
bytes
The I/O buffer can be filled with a given set
of data directly using the function
IOBUFF.DIM
Example:
IOBUFF.DIM(0,
10) = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
IOBUFF.DIM(1,
5) =
&h12, &hAA, &h50, &O377,
&B10101010
As soon as the buffer is dimensioned, the
given amount of RAM is reserved for the buffer.
When not required anymore, it can be removed
with the command
IOBUFF.DESTROY(buff_num)
Example:
IOBUFF.DESTROY(0)
'remove the buffer releasing the memory
reserved
Note : The I/O buffers are automatically
removed each time the program is run.
It is possible to know the size of the buffer
using the function
IOBUFF.LEN(buff_num)
Example
Print
IOBUFF.LEN(buff_num)
'print the length of the
buffer
The I/O buffer can be read byte per byte using
the function
IOBUFF.READ(buff_num,
position)