The Basics of Vesta Basic

The Anatomy of Vesta Basic
SBC2000 Memory
Battery Backable RAM
Real Time Clock RAM
EPROM
Flash Memory
EEPROM Memory
External Memory Devices
The Vesta Basic Task
Working with Tasks
Task Size Limitations
Where to Store Tasks
Task Switch Timing
Starting and Stopping Tasks
Task Structure
Line Format
Procedures
Subroutines
Functions
CRITICAL and VITAL Procedures
Variables
Data Types
Naming Conventions
Classes of Variables
Global Variables
Kernel Variables and Inter-task Communication
Variable Initialization
Arrays
Creating an Array
Two Dimensional Array in RAM
String Arrays
Arrays in EEPROM
Arrays in Flash
Sharing Array Data Between Tasks
Constant Data
Numeric Constants
String Constants and Literals
Arrays of Constant Data
Assignments Using Mixed Data Types
Operators
Expression Operators
Logical Operators
Relational Operators
Combining Relational and Logical Operators
Operator Precedence
Special Operators
String Functions
Substring Pointers
Substring Insertion
Substring Replacement
Substring Removal
Substring Reversal
Pointer Rules
Substring Pointers and String Functions
Vesta Basic Extensions
Using Extensions

The Anatomy of Vesta Basic
There are two software components of Vesta Multi-tasking Basic that reside on the SBC2000 - the Boot Monitor which takes control at power-up, and the Runtime Engine, to which the Boot Monitor will transfer control. This design makes it possible to upgrade the version of Vesta Basic on your SBC without replacing any chips. All that is required is a serial connection to the DEV port.
The Integrated Development Environment (IDE) resides on the PC and allows you to enter and edit programs. The IDE invokes the Compiler to produce a task image from the source code in the active task window. This task image can be downloaded to RAM or Flash on the SBC, or loaded onto a ROM chip with a device called a ROM programmer.
The IDE communicates via a serial connection to the IDE Monitor in the VMTB Runtime Engine on the SBC2000. When a task has been downloaded, the Runtime Engine will execute it. The IDE can cause the Monitor to control tasks in RAM (run, stop, step, etc.) and to obtain information about tasks, such as execution state and the values of variables.

SBC2000 Memory
There can be several different kinds of memoryon your SBC, proper use of which has important ramifications.
For more information on the Vesta Basic keywords pertaining to memory, see Memory Commands .

Battery Backable RAM
The onboard RAM is a large-capacity, volatile memory device that may be battery backed.
RAM is available in three sizes on the SBC2000-332: 64Kbyte, 256Kbyte and 1Mbyte, and 32k, 128k and 512k bytes on the SBC2000-188.
Battery backing is not enabled on your board by default. Unless you provide battery backup power, data will not be preserved when power is removed. Consult your Vesta Engines manual for more information on your SBC2000 controller.

Real Time Clock RAM
There are about 240 bytes of RAM available in the Real Time Clock (RTC) clock/calendar chip. The RTC will hold its values through power cycles if battery backup power is supplied to the clock. There is no limit on the number of times a byte in RTC RAM may be written.
The RTC RAM device is accessed via a serial I/O protocol, and has a relatively slow access time. There is no extra delay necessary for writes beyond that imposed by the serial access. VMTB provides routines for reading and writing to individual locations of RTC RAM. See RTC.

EPROM
EPROM is a large-capacity nonvolatile memory type that can only be written using an EPROM programming device. The SBC2000 boards do not have the capability to program EPROMs. On the SBC2000-332, access to information in EPROM occurs at approximately half the speed of accessing information in Flash or RAM.
The boot ROM is a socketed byte-wide device that sits in the EPROM slot. Boot ROM can be 128k, 256k, or 512k bytes (the SBC2000-332 may also use a 1M boot ROM).
The boot ROM on the SBC2000-332 is active for addresses 0x000000 to 0x0FFFFF (or the first megabyte) of address space, corresponding to its size. On the SBC2000-188, the boot ROM occupies addresses 0x80000 (or 0xC0000, or 0xE0000, depending upon size) to 0x0FFFFF.
All Vesta ROMmed languages use one wait state in the boot ROM. The access time requirement for boot ROM is tabulated below.
ROM Speed Min. Wait State
80 ns or faster 0
120 ns or faster 1
180 ns or faster 2

Flash Memory
Flash memory is large-capacity nonvolatile storage with fast read access. A single location can be written multiple times, but there are restrictions on subsequent writes.
On the SBC2000-332 Flash memory is available in sizes ranging from 512Kbyte to 1Mbyte. On the SBC2000-188 Flash is available in 512K devices and is accessible as an 8 bit byte read or write.
Each sector of the flash is 0x10000 (64k) in size. Flash starts at 0x200000 in the SBC2000-332 and 0x80000 in the SBC2000-188. Vesta Basic is stored in the lowest two sectors (0, & 1) on the SBC2000-332 and the highest three sectors on the SBC2000-188 (5, 6, & 7).
Flash memory is similar to EPROM in that "1" bits may be changed to "0" but a "0" cannot be individually changed to "1" until the sector is erased. Although any 16 bit word is accessible as a write operation, erasing must be done on a sector basis. Vesta software drivers organize the different sized physical sectors into 64k byte logical sectors. Erasing a sector typically takes less than 2 seconds, but may take as long as 30 seconds.
Besides providing routines to read and write individual locations, VMTB supports placing tasks and arrays in flash.
Flash memory is primarily used as a convenient method of storing application tasks.
Because Flash is 16 bits wide on the SBC2000-332, Vesta Multi-Tasking Basic will run about twice as fast when the execution engine is installed in Flash instead of 8bit wide ROM.
Flash may also be used to store data gathered by the application program. The programmer must be aware of several issues when designing a program using flash as data storage.
· Flash memory is organized as 65,536 byte sectors.
· Once an element of a sector is written, the entire sector must be erased in order to re-write that element.
· A flash memory location may be written and erased a maximum of 100,000 times.
The number of sectors available depend on the size of the flash device. The SBC2000-188 has one socket that can be occupied by either a 512k flash device, or a ROM device of up to 512k. The SBC2000-332 may have a 512k or 1 Megabyte flash device installed.
Vesta Basic occupies the first two sectors of flash on the SBC2000-332 and the last three sectors of flash on the SBC2000-188.
Sector SBC2000-332 SBC2000-188
0
Vesta Basic Task storage
1
Vesta Basic
2
Task Storage  
3
4
  Array data storage
5   Vesta Basic
6   Vesta Basic
7   Vesta Basic (last sector of 512k)
8    
9    
A    
B    
C    
D    
E  
F Array data storage  

The flash memory on the SBC2000-332 is rated at a minimum of 100,000 write cycles.
Warning! Flash memory has a life of approximately 100,000 program cycles. The smaller serial EEPROM on your Vesta single-board computer has a life of 1,000,000 program cycles. This limitation is important to keep in mind if you create a program that stores repetitive data, such as tracking operations at one-second intervals. At this rate the EEPROM will reach the end-of-life in less than 2 weeks. Store frequently updated values in battery-backed RAM.

EEPROM Memory
The serial EEPROM is a small-capacity nonvolatile storage device intended for small amounts of data that does not change often, if at all. It is designed to hold things like serial numbers and infrequently updated operational parameters such as last operator settings or calibration factors.
EEPROM is available in various sizes ranging from 128 bytes to 8K bytes. If you use the EEPROM in your application, you must specify the size of the EEPROM on your board in your application, using the EEPROM_SIZE() command. See EEPROM_SIZE.
Each location holds one byte of data, and can be written approximately 1 million times before it reaches the end of its useful lifetime. This device is accessed via a serial I/O protocol, so access is slow compared to RAM, EPROM, or Flash. Writes to EEPROM take several milliseconds to complete. There are no restrictions on the data values of successive writes to the same location.
Besides providing routines to read and write individual locations, VMTB supports placing numeric arrays in EEPROM. See Arrays in EEPROM.

External Memory Devices
The design of Vesta SBCs allows for additional memory devices such as PCMCIA RAM cards to be used. The MEM_PEEK, MEM_POKE, MEM_DPEEK, and MEM_DPOKE are provided to control these devices. However, detailed instructions on how to attach and manipulate such devices are beyond the scope of this manual.

The Vesta Basic Task

Working with Tasks
Vesta Multi-tasking Basic provides seven tasks, named Task1 through Task7, for your application. These seven tasks are available for edit through the Tasks menu of the Vesta Basic IDE. The IDE monitor is Task0 and is not available to the programmer as a task resource.
Each task is an independent entity. There are no distinctions among the tasks, such as execution priority or placement in memory. Tasks are not launched in any particular order, however Vesta Multi-Tasking Basic provides several keywords and constructs that allow you to synchronize the operation of separate tasks. See Starting and Stopping Tasks .

Task Size Limitations
Task size is limited to 192k bytes of compiled application code and constant data. Variable storage and stack space is limited by the amount of installed RAM, which may range from 128k bytes to 1 megabyte.
You can use the Tools|Task Memory menu to set compile time limits for various types of memory on a task-by-task basis.

Where to Store Tasks
Tasks may be stored in RAM, Flash, or boot ROM.
The IDE compiles, links and downloads the current task to RAM when you click the Go button. Tasks in RAM are only executed through the IDE, and are discarded on reset.
Tasks stored in boot ROM will automatically execute upon reset, unless there is a task with the same name (Task1-Task7) in Flash. This allows finished applications that have been programmed in Boot ROM to be easily updated with new tasks downloaded to Flash or RAM.
Tasks stored in Flash will also automatically execute upon reset. On the SBC2000-332, tasks stored in Flash will execute approximately 50% faster than tasks stored in RAM or boot ROM.
The IDE compiles and downloads the current task to Flash when you select Flash|Move Current To Flash, or all open tasks to Flash when you select Flash|Move All To Flash.
The IDE creates a boot ROM image suitable for programming directly into an appropriately sized EPROM device, when you select Tools|Build ROM.
When the IDE downloads a task to a device on the SBC, the new task supercedes any task of the same name that currently resides on that device.
Note: tasks stored in Flash or ROM cannot be directly controlled (stopped, animated, etc.) by the IDE. If you wish to interact with a Flash or ROM task via the IDE, you must recompile and download that task into RAM.

Task Switch Timing
The Multi-tasker uses a list of active tasks to determine the next task to execute following completion of the current time slice. Tasks that have not been loaded or have been STOPped are not on the list. This prevents completed or unused tasks from wasting processor time.
The Vesta Basic system clock is used to keep track of execution time for each task. By default, each task is allocated five 10-millisecond ticks of the system clock, which comes out to 50 milliseconds. A task can assign itself more (or fewer) ticks by using the Set Timeslice To n command. See SET TIMESLICES TO n.
The time between power on reset and execution of the first Vesta Basic statement is about 0.4 seconds on the SBC2000-332 and about 2.3 seconds on the SBC2000-188.

Starting and Stopping Tasks
Vesta Basic keywords START, STOP, SUSPEND and RUN, allow any task to control other tasks, including itself.

START [task#] Executes the task from the beginning.
STOP [task#] Suppresses the Multi-tasker from allocating time to the specified task.
RUN [task#] Allows the Multi-tasker to resume allocating time to the specified task.
SUSPEND Relinquishes control of the remainder of the current time slice to the next task.

Application tasks are numbered 1 through 7. If the task number is not specified, the task will restart or stop itself. For example, if Task1 needs to start Task2, use the following statement in Task1:
START 2
Note: START does not initialize kernel variables and does not de-allocate memory. For these reasons REBOOT may offer a more all-encompassing error recovery opportunity.
If the Multi-tasker reaches the end of executable code in a task without encountering an END statement, it will effectively STOP the task. This is especially important in that the Event-handler cannot execute a procedure in a STOPped task, but it can execute a procedure in a task that has ENDded.

Task Structure
The simplest Vesta Basic task can be organized into five sections.
Section 1 contains remarks describing the program's purpose and document design.
Section 2 is comprised of procedures, arrays and forward procedure declarations.
Section 3 contains all function and subroutine declarations as well as local and static variable declarations.
Section 4 is comprised of all the global variable declarations.
Section 5 begins with the first executable statement and is considered the main procedure.

Section 1

  REM Name and description goes here
  REM Com.txt - Handles COM Events 
  REM 4-1-2001 by Amed O'Reily

Section 2

  REM Declare forward reference here
  DECLARE x AS INTEGER ARRAY

Section 3

  REM Define any subroutines and functions
  INCLUDE "./thingy.txt"
  FUNCTION zero () AS INTEGER
  	zero=x [0]
  END 
  FUNCTION value (num AS INTEGER) AS INTEGER
  	LOCAL a AS INTEGER
 	STATIC b AS FLOAT
  	a = num + a
 	b = a / 256
 	value=num + a
  END
  SUBROUTINE report (num AS INTEGER)
 	 PRINT num
  END

Section 4

  REM Kernel and Global variable declarations:
  KERNEL index AS bleep, sum AS INTEGER
  GLOBAL index AS int2, sum2 AS INTEGER

Section 4

  REM the main routine starts here with the first executable 
  REM statement. Certain statements such as procedure
  REM definitions and global variable declarations cannot occur 
  REM after this first executable statement.
  DIM x[10] AS INTEGER
  FOR index=0 TO 2
  	SELECT index
  	CASE 0
  		sum = zero()
  	CASE ELSE
  		sum = value(index)
  	ENDSELECT
  	report(sum)
  NEXT
Tasks are subdivided into various constructs, such as declarations and procedures. Declarations define the names and types of variables that will be used in the task, and must be declared before any code that uses them. See Classes of Variables and Variable Declaration.
Procedures must be defined before the beginning of executable code. Procedures defined in one task may not be called by another. See Procedures for more information.
Normally, variables in different tasks are distinct form each other even if they share the same name. However Kernel variables are available to all tasks, see Kernel Variables and Inter-task Communication . Also, there are techniques for sharing array data between tasks, see Sharing Array Data Between Tasks.

Line Format
None of the keywords that make up the statements in Vesta Basic are case sensitive. In other words, "IF," "If," and "if," are all equivalent. In addition, all built-in procedures and user-defined procedures are not case sensitive. To make code more readable, we recommend entering all keywords and built-in procedure calls in upper case and all user-defined procedures and variables in lower-case.
Spaces are ignored.
Vesta Basic allows more than one statement to share a line of code, if the statements are separated by colons.
Some statements may not share a line even if separated by colons. They are:

  IF         INCLUDE    ELSE        ENDIF 
  WHILE      SELECT     CASE        FOR
  FUNCTION   END        DO          LOCAL
  STATIC     GLOBAL     KERNEL      ENDSELECT
  UNTIL      NEXT       SUBROUTINE  LOOP
  DECLARE    CONSTANT 
The REM statement identifies the text that follows on the line as a remark. The compiler will ignore all text to the right of the REM keyword. The REM and the text that follows will not affect the size of the compiled code. A REM statement may follow another statement on the same line, but the two statements must be separated by a colon.

Procedures
Vesta Basic provides several types of procedures that make your program easier to read and debug. Functions and subroutines are the building blocks of your program, where most of the work is done. External routines are procedures that are defined in separate files and are associated with your program using the INCLUDE statement. Functions and subroutines are executed when called by the main routine or by other routines and must be defined or declared before any code may call them.
Functions are procedures that can receive data passed to them and return a value (See FUNCTION ). Subroutines are procedures that can receive data passed to them but do not return a value (See SUBROUTINE ). Extensions are external procedures that are associated with your program through the INCLUDE statement (See INCLUDE ).
Vesta Basic Procedures allow you to encapsulate code for individual tasks, making is easier to program and debug. The variables from each encapsulated procedure can be isolated from the rest of the program as local variables. By passing a copy of the variables to serve as its list of arguments, the procedure cannot modify the original variables. With this method, program behavior is more structured and self-contained.
Many very useful routines are included on your VMTB CD-ROM in the form of examples and extensions that you can either copy into your application or INCLUDE as part of your compiled application. The ROADMAP document lists and describes the examples.
The keyword VITAL may be used to protect procedures from event interruptions. The Vesta Basic event handler monitors various types of events and temporarily diverts control to the event routine specified by your program when the particular event occurs (see VITAL). These event routines and all routines called by the event routine must be defined using the VITAL keyword. Any routines that must execute without event interruption should use the keyword VITAL in their definition.

Subroutines
Subroutines are defined using the SUBROUTINE statement, followed by the statements that make up the subroutine and ending with the END statement. An early exit to the subroutine may be defined at any point with the RETURN statement.
Subroutines are designed to "encapsulate information." The data passed as arguments are copies of the variables from the calling procedure. The subroutine cannot modify the original variables. This keeps program behavior more structured and self-contained.
Subroutines do not return a value, and therefore are best suited for output routines such as PRINT, BEEP, or POKE. If you want to give a subroutine access to a global variable, the global variable declaration must precede the subroutine definition.

  SUBROUTINE tone (freq AS INTEGER, duration AS INTEGER)
  	LOCAL I AS INTEGER
  	BEEP(freq) :REM Beep at frequency 
  	FOR I = 1 TO duration
  		REM
  	NEXT I
  	BEEP (0) :REM shut off beeper
  END
Invoke the subroutine with the subroutine name or the optional CALL statement, followed by the subroutine name.
  CALL tone(333, 400) 
  REM generates a short beep at 333Hz
  CALL tone(333.0, 400) 
  REM converts the float constant to
  REM an integer
Subroutines must be called with arguments whose types correspond to those described in the definition of the subroutine. Vesta Basic will attempt to convert arguments to the correct type, however conversions between strings and numeric values are not automatically possible.
Subroutines may invoke other subroutines and functions. A subroutine may also invoke itself. In order for another procedure to invoke a subroutine, the subroutine must either be placed before the invoking procedure in the task code, or the subroutine must be declared before the subroutine is called, using the following syntax:
  DECLARE SUBROUTINE name
Neither the keyword SUBROUTINE nor the name you assign to the subroutine are case sensitive.

Functions
Functions are defined using the FUNCTION statement (which indicates the names and data types of any arguments passed to the function, and the value the function will return) followed by the statements that make up the function and ending with the END statement. An early exit to the function may be defined at any point with the RETURN statement.
Functions can accept more than one value as data but can only return a single value to the calling procedure.

  FUNCTION square_root (num AS FLOAT) AS FLOAT
  square_root = num ^ 0.5
  END

There are two ways to invoke the function:
1. Assign its return value to a variable.
result = square_root (x)
2. Use the return value in an expression.
result = 7+square_root (9)
Functions must be called with arguments of the corresponding types.
Example of what not to do:

  FUNCTION sq (value AS INTEGER) AS INTEGER
  sq=value*value
  END
  VAR=sq("ABC")
Functions may invoke other functions, subroutines, or themselves. In order for another procedure to invoke a function, the function must either be placed before the invoking procedure in the task code, or the function must be declared at the beginning of the task, using the following syntax:

DECLARE FUNCTION <name> AS <type>

Neither the keyword FUNCTION nor the name that you assign to the function, are case sensitive.

CRITICAL and VITAL Procedures
There are occasions when it is necessary to ensure that a procedure will complete without interruption. Vesta Basic provides two keywords for such situations:

VITAL suppresses the execution of the Multi-tasker and the Event-handler.
CRITICAL suppresses the execution of the Event-handler only.

The Multi-tasker is the portion of the Runtime engine that controls time sliced task switching. The CRITICAL declaration will prevent Vesta Basic's Multi-tasker from swapping tasks before the procedure is completed.
The Event-handler is the portion of the Runtime engine that passes control to the appropriate routine in response to certain conditions such as an error condition. The VITAL declaration will prevent the Multi-tasker from swapping tasks and the Event-handler from responding to ON events before the procedure is completed. Sources of events that may be deferred until the procedure completes are: interrupts, communication events, timer events and run-time errors such as division by 0.

Variables

Data Types
Vesta Multi-Tasking Basic recognizes four data types. The data types and their capacities are listed in the chart below.

SBC2000-332 and SBC2000-188
Type Storage Range
Integer 16-bit signed integer -32,768 to 32,767
Long 32-bit signed integer -2,147,483,648 to 2,147,483,647
Float Single precision float, 7 significant digits +/-1.7 x 10 +/-38
String Alphanumeric string 254 characters

Each string variable is allocated 256 bytes of memory no matter what length the value assigned to that variable may be. The maximum length of a string's value is 254 characters.
By default, numbers are assumed to be in decimal format. The assumed format can be changed to hexadecimal using the HEX command (see HEX), and can be changed back using the DEC command (see DEC). When the format is decimal, numbers will be interpreted as hexadecimal, when preceded by the symbol 0x ("zero, x"), followed by up to four hexadecimal digits for integer values and 8 digits for long values. These digits may be 0 thru 9 or A though F. The A though F are not case sensitive.
When the format is hexadecimal, numbers will be interpreted as hexadecimal even when expressed without the preceding "0x", and the letters A though F are allowed with out generating an error.

Naming Conventions
The names of variables, subroutines and functions must conform to these rules

    1) Must be no more than 30 alphanumeric characters long (A thru Z, a thru z, 0 thru 9 and underscore)
    2) Must begin with an alphabetic character (a thru z or A thru Z).
    3) Are not case sensitive
    4) Cannot be identical to Vesta Basic Keywords.
The Compiler will issue an error if too many characters are used in a name.
Vesta Basic does not differentiate between upper- and lower-case characters for variable names, procedure names, or keywords. This manual denotes keywords in upper-case letters, and variables and procedure names are in lower case.
Names cannot be identical to Vesta Basic keywords or Vesta Basic built-in procedures. Undocumented keywords exist in Vesta Basic that communicate with the IDE. Do not name a variable or procedure starting with "IDE".

Classes of Variables
Variables must be declared before they are used and in each task where they are used. Declaration establishes the data type of the variable, and where the variable will be used: There are four storage classes:

STATIC variables may be accessed only in functions and subroutines where they are declared. The contents of Static variables are retained after the procedure is completed.
Variables of global scope (GLOBAL, KERNEL) and variables of local scope (LOCAL, STATIC, and arguments to functions and subroutines) can have the same name, belong to the same category, and still be distinct from each other. The local variable will be used only inside the procedure that declares it, and the global variable will be used everywhere else.
Example:
  GLOBAL var1 AS INTEGER
  SUBROUTINE foo()
  	LOCAL var1 AS INTEGER 
  	:REM Distinct from 
  	:REM global var1, but confusing
  	var1 = 1 :REM Only changes local var1, 
  	:REM global var1 unaffected
  END

Global Variables
Global variables must be declared before any executable code in the task. When Globals are declared after all subroutine or function definition, the programmer assures that information contained in those procedures will not be shared with the rest of the task.
If you need to access to a global variable within a procedure, that variable must be declared before the first procedure that references it.
A good practice is to designate, at the beginning of your code, a small set of global variables that must be accessible to all procedures. Declare the remainder of the global variables just before the main procedure. Instead of using global variables in procedures, pass values to procedures as needed.

Kernel Variables and Inter-task Communication
Inter-task communication is accomplished through the use of Kernel variables.
A common inter-task protocol uses a flag variable and separate variables that hold the data to be passed.
In the example below, Task1 is sending data to Task2. The variable called "info" contains the data to be exchanged. The "flag" variable controls the exchange.
Task 1

  GLOBAL loopcntr AS INTEGER 
  KERNEL info AS INTEGER, flag AS INTEGER
  FOR loopcntr = 0 TO 9
  	info = loopcntr
  	flag = 1 :REM flag tells Task2 that
  	:REM Task1 is waiting for data
  DO
  	:REM wait for task2 to execute
  	SUSPEND :REM SUSPEND hands control to 
  	:REM the next task
  	LOOP UNTIL flag = 2
  	:REM when flag=2, task2 is done
  NEXT loopcntr
Task 2
  KERNEL info AS INTEGER, flag AS INTEGER
  DO WHILE 1
  	DO
  		:REM wait for task 1 to change the 
  		:REM flag variable to 1
  	LOOP UNTIL flag = 1
  	PRINT info :REM This is where Task2
  		:REM uses info.
  	flag = 2 :REM Set flag to tell Task1
  	:REM that Task2 is ready for 
  	:REM more data. 
  LOOP
When several tasks are monitoring the same flag, the test/set sequence must not be interrupted by another task.
The solution is to embed the test/set sequence in a VITAL subroutine. It is important to embed only the test/set instructions in a VITAL procedure because if a wait-for-other-task-completion were included, the condition would never occur (task switching is defeated in a VITAL procedure).

The following example illustrates how to prevent more than one task from accessing a shared resource.

  KERNEL lock AS INTEGER
  VITAL FUNCTION lockit() AS INTEGER
  IF lock=0
  	lockit=1
  	lock=1
  ELSE
  	lockit=0 
  ENDIF
  END

  SUBROUTINE lock_resource()
  	DO WHILE lockit()<>1
  		SUSPEND
  	LOOP
  END
  SUBROUTINE unlock_resource()
  	lock=0
  END
  ...
  REM any task accesses the resource thus
  REM wait until resource is available 
  lock_resource()
  REM use resource
  access_shared_resource()
  REM release to other tasks
  unlock_resource()
These issues are especially important during the allocation of memory resources. The DIM statement allocates memory and assigns arrays to specific memory addresses. If an array assignment in a task relies on the results of a DIM statement in another task, it is imperative that the first DIM statement executes before the second. This can be controlled by using a kernel variable as a flag.
See also Sharing Array Data Between Tasks.

Variable Initialization
Numeric variables are initialized to zero. String variables are initialized to an empty string.
Array variables are never initialized by Vesta Multi-Tasking Basic; they must be initialized by application code.
Global and static variables are initialized only once, at task startup. Local variables are initialized on every invocation of the procedure that declares them. Kernel variables are initialized when the first task that declares them first references them. They are not re-initialized until the SBC2000 is reset.

Arrays
Vesta Multi-Tasking Basic supports arrays of integers, longs, floats and strings. Arrays may be stored in RAM, FLASH, ROM or EEPROM.
SBC2000
Array Type -332 -188 element size
Integer * * 2
Long * * 4
Float * * 4
String * * 256

Arrays may be of either one or two dimensions. Square brackets are used to denote array indices.
Array indices start at 0 and are of type LONG. The DIM statement establishes the range of the index or indices. If a reference to an array is outside this range a run-time error will result.
Individual array elements may be passed to procedures as arguments.
Array data is not zeroed upon reset. Array variables are never initialized by Vesta Multi-Tasking Basic.

Creating an Array
The programmer has the choice of creating arrays in flash or RAM as well as the choice of data type. The creation of an array is a one or two-step process.

    1. Declare the array before any procedures that will reference the array. If no procedures reference the array this step may be omitted.
    2. Dimension the array, specifying its name, indices, data type, type of storage (optional) and location (optional).
The following statements create a one dimensional array of 256 elements in RAM.
  DECLARE x AS INTEGER ARRAY
  (... any procedures ...)
  DIM x[256] AS INTEGER
This creates an array of 256 elements whose index is 0 to 255 has been created in RAM. An attempt to access array elements with an index is less than zero or greater than 255 will result in a run-time error.
The first step allows procedures to access the array and is optional. The second statement allocates 512 bytes of RAM from the memory manager, establishes the array organization (one dimensional), the data type (integer), the type of memory (RAM or flash) and its location in memory.

Two Dimensional Array in RAM
Creation of a two dimensional array is straightforward.

  DIM xyarray[10,20] AS INTEGER

Creating the Largest Possible Array
Vesta Multi-tasking Basic allows you to use the largest available block of contiguous RAM to create an array for applications such as data logging.

  DIM x[RAM_AVL()/2] AS INTEGER
RAM_AVL() returns the number of bytes of the largest block of RAM currently available. See RAM_AVL.

String Arrays
Creation of a string array is easy

  DIM z[1000] AS STRING
Each element requires 256 bytes, so a string array with these dimensions would take a quarter Meg of RAM. However, creative programming can be used to access data within the string and allow you to squeeze more information into each array element.
See String Functions.

Arrays in EEPROM
Arrays in EEPROM are the ideal place to store configuration parameters, operating set points, sensor linearizing curves or other infrequently changed operating data. Arrays in EEPROM are non-volatile and will be retained throughout a power cycle. Individual bytes of the EEPROM may be modified without the concern of erasing an entire sector like in Flash memory. The number of write cycles of an EEPROM byte is 1,000,000, so do not create array elements in EEPROM whose values are modified frequently. The size of your onboard EEPROM is dependent on the product that you purchased, typically 4k or 8k bytes.

  DIM language [4] as INTEGER IN EEPROM

Arrays in Flash
Data stored in flash memory is secure throughout a power cycle of any duration.

  DIM temperature[100] AS INTEGER IN FLASH
Unfortunately, any element of an array in flash may only be written once before the entire 64k byte sector must be erased. The challenge is to identify and erase the sector in which an array resides.
Memory for data storage in flash is allocated from the highest flash location downwards. The sector number of the start of an array in flash is given by:
  start-of-flash = 0x80000 on SBC2000-188
  start-of-flash = 0x200000 on SBC2000-332
  sector = (ADDR_OF(arrayname) - start-of-flash)/65536
SIZE_OF_FLASH() returns the capacity in bytes of the flash device installed on your SBC2000.
FLASH_AVL() returns the number of bytes available for data storage in the flash.

Placing an Array at a Specific Location in Flash
Vesta Basic allows you to assign an array to a specific location in Flash. To do this, you must know the size of the tasks you will be putting in flash (so that you don't place an array in the middle of code space) and the size of the flash device.
Each sector of the flash is 0x10000 (64k) in size. Flash starts at 0x200000 in the SBC2000-332 and 0x80000 in the SBC2000-188. Vesta Basic is stored in the lowest two sectors (0,1) on the SBC2000-332 and the highest three sectors on the SBC2000-188 (5, 6, & 7).
For example, to place our array at the beginning of the 4th sector on an SBC2000-332, execute the following dimension statement:

  DIM x[32767] AS INTEGER = 0x240000
On the SBC2000-332, Flash starts at 0x200000, and to get to the forth sector we would add 0x40000 to get the 0x240000.
For the SBC2000-188 we would use:
  DIM x[32767] AS INTEGER = 0xC0000
Notice that an entire sector has been allocated to the x array. To erase the sector use the following statement.
  FLASH_ERASE(4)

Sharing Array Data Between Tasks
The ability to place an array at a specific location in memory can be used to share array data between tasks. The array is created in the normal fashion by the first task, the location of the array is passed to the second task in a kernel variable and the second task dimensions an array at the same specific location.
Task 1

  KERNEL array_location AS LONG
  DIM shared_array[100] AS INTEGER
  array_location = ADDR_OF(shared_array)
Task 2
  KERNEL array_location AS LONG
  DO
    REM this is very important you must wait for the other task
    REM to allocate memory for the array
  LOOP UNTIL array_location <> 0 
  DIM shared_array[100] = array_location
To learn how to ensure that a procedure will complete without interruption, see CRITICAL and VITAL Procedures.

Constant Data
The keyword CONSTANT identifies data that will not change during the execution of the program. Constant variables are saved differently than ordinary data, and the compiler has a few tricks for speeding up the code when constant variables are used.
The Vesta Multi-tasking Basic compiler handles constant strings, numbers and arrays differently, so each is covered in it's own section below.

Numeric Constants
The range of an integer constant is -32,768 to 32,767. Integer constants can be expressed in decimal or hexadecimal format. When expressed in hexadecimal, the number must be preceded by a zero and a lower case "x", followed by up to four hexadecimal digits. These digits may be 0 thru 9 or A thru F. The A thru F are not case sensitive.
The range of a long constant is -2,147,483,648 to 2,147,483,647. Long constants can also be expressed in decimal or hexadecimal. When expressed in hexadecimal, the number must be preceded by a zero and a lower case "x", followed by up to eight hexadecimal digits.
Floating point constants may be expressed in two ways: In standard exponential form (scientific notation (e.g., +3.14159 E+0), or standard decimal format (e.g., 3.14159). The range of floating point constants is +/-1.7 x 1038. The accuracy of floating point numbers is about 6.5 significant digits. For example, if the number 12345678 is assigned to a floating point variable, the result will be greater than 12345650 and less than 12345700.
Enclose a single character in single quotes to return the ASCII value of that character (x='A' would result in x containing 65).

  IF key='A' OR key='a'
  IF key=65 OR key=97
Both statements are logically equivalent, but the first one is easier to understand.

String Constants and Literals
A literal string is anything enclosed in double quotes.
CONSTANT arrow AS STRING="->"
A string constant is assigned to a string variable with an assignment statement.

  string1=arrow
string1="abcdefgh"
Any ASCII character, including control characters, may be embedded into a string by using a backslash character followed by the ASCII code in the range 0-255, that represent the character.
  CONSTANT crlf AS STRING = "\013\010"
  PRINT x, j, z, crlf
Some common control characters:
  Sequence Meaning
   \010     line feed
   \013     carriage return
   \012     form feed
   \009     tab
For a complete list of the ASCII character set, see Appendix A.

Arrays of Constant Data
Arrays of Constant Data may be created, and require less memory space than providing the same information using READ/DATA statements would.

  REM the following is on one line
  DIM array_of_constants[10] AS INTEGER CONSTANT = [0,1,2,3,4,5,6,7,8,9,]
The contents of the array can appear on multiple lines, but the first portion of the statement (from "DIM" through "[") must be on a single line.

Assignments Using Mixed Data Types
It is possible to assign an expression of one data type to a variable of a different data type. The only limitations are based on the ability of the receiving variable to hold the value of the expression. For example, a long constant value cannot be assigned to an integer variable if the long constant value is outside the limits of the maximum possible integer value. The rule holds true, similarly, for float constants assigned to integer or long variables. Both of these events will generate a compiler error.

  intvar = 1000000 :REM results in a compiler error
Assigning a float constant to long or integer variables is permitted, but the variable will contain only the integer portion of the truncated floating constant. The floating point number is not rounded to the nearest integer before the value is truncated.
  intvar = 3.9 :REM results in intvar containing 3
During run time, a mixed data-type assignment will produce the same results as during compile time. No errors will be generated if the receiving variable is not large enough to hold the assigned data. Instead, the upper or lower limit of the data type will be stored.
  longvar = 1000000
  intvar = longvar
  REM results in intvar containing 32,767
Conversely, if an integer variable is assigned to a long, the integer value will be sign extended.
String data may not be involved in either a mixed-type assignment or mixed-type expression.
It is possible to have the result of a mixed data-type expression assigned to a variable of a different type. In this case, before being stored in the receiving variable, the expression is evaluated according to the rules governing the mixed data-type expression; the result is converted according to rules governing mixed data-type assignments.
For Example:
  floatvar = 2/3 
results in floatvar containing 0.0 because the result of the integer division is 0.
  floatvar = 2/3.0 
will result in floatvar containing 0.666 . . . because the integer 2 will be promoted to a float 2.0, and the division will have a floating point result.

Operators

Expression Operators
Vesta Multi-Tasking Basic supports the following math operators:
+ add
- subtract and unary minus
* multiply
/ divide
\ modulus (remainder)
^ exponentiate
Programmers must remember to take into account the data range when using math operations on integer and long data types. These data types are stored as 16- and 32-bit signed integers. Operations are performed as 2's complement. Adding 1 to +32,767 will result in -32,768 for an integer variable.
Dividing by zero results in a run-time error. A run time error also will result if an attempt is made to exponentiate a negative number to a fractional exponent (e.g., take the square root of -1).
Expressions with Mixed Data Types
When data-type expressions are mixed, lesser data types are sign extended to wider data types. The result is expressed in the widest data type involved in the expression.
For example:

  intvar + floatvar will have a float result
  longvar + intvar will have a long result

Logical Operators
Vesta Multi-Tasking Basic supports the following bitwise logical operators:
AND returns TRUE if both corresponding bits are true
OR returns TRUE if either corresponding bit is true
XOR returns TRUE if either but not both corresponding bit is true
NOT inverts all bits and returns the result
These operators can only be used on integer and long values.

Relational Operators
Vesta Multi-Tasking Basic supports the following relational operators:

An expression is considered "true" if nonzero and "false" if zero. The relational operators return all bits set (-1) if true and all bits cleared (0) if not true.
Relational operators may be used on strings as well as numbers. The ASCII characters of the strings are compared, reading left to right.

Combining Relational and Logical Operators
Relational operators and logical operators are designed to work together as well as independently.

  IF (a<b) OR (c<>0)
combines the logical operator "OR" with the relational operators, "<" and "<>".
Longs and integers can be operated upon in the same expression, using logical operators. The integer is converted to a temporary long. The program then processes this temporary long value with the other long.
Floats and integers can be operated on in the same expression, using logical operators.
Strings may also be operated upon with relational operators:
  "came" >= "cameo" AND 3.0 = 3.
This expression evaluates to a false, (represented by the number 0). The two relational expressions are evaluated first because relationals take higher precedence. The string expression evaluates to an integer of zero because "came" has an earlier spelling than "cameo." The number expression evaluates to true, which is the number 0xFFFF (-1) because 3.0 = 3. The results of both comparisons are bitwise ANDed.
With these rules, logical expressions may be created out of any combination of zero values, which are false and nonzero values, which are true. The result of these relational comparisons can be either true or false.

Operator Precedence
Unary and special operators and (- and NOT) have the highest precedence, followed in order by:

Parentheses may be added to control or modify the order of evaluation. It is considered good coding practice to use parentheses liberally to clarify evaluation sequences.

Special Operators

  MIN     MAX     ABS
  SIZE_OF ADDR_OF
  ROW_OF  COLS_OF 
and have equal precedence to "-" and" NOT".

String Functions
Vesta Basic provides the following string functions:

See String Manipulation, for more information.
String functions may be used on string array elements and string constants.

Substring Pointers
Substring position pointers allow easy manipulation of text within a string.
Vesta Multi-Tasking Basic supports a complete range of string operations using substring pointers AND the curly brace operator to identify a substring and what to do with it:

  string1{3}   :REM Refers to the 4th position in the string
  string1{4,8} :REM Refers to the 5th through 9th position in the string.
The first element (character or symbol) of a string is position 0. The position following the last is identified with a "$".

Substring pointers may be used on either side of the equals sign with a subtle difference in meaning:

  string1 = "01234567"
  xx1 = string1{2} :REM xx1 is "2"
  xx1 = string1{2,5} :REM xx1 is "2345"
  string1{2} = "x" :REM string2 is "01x234567"
  string1{5,6} = "x" :REM string2 becomes "01x23x67"
When the substring pointer is on the right side of the equals sign, it refers to a character or characters that something can be set to. When it is used on the left side of the equals sign, a single pointer refers to an insertion position, and double pointers refer to a span of characters to be replaced.

Substring Insertion
When a single pointer is used to identify the insertion point in the string, the text from the insertion point to the end of the string will be shifted to the right of the inserted text:

  string1 = "0123456"
  string1{2} = "abc"
  REM string1 now equals "01abc23456"

Substring Replacement
When two pointers are used to identify the beginning and end positions of the characters to be replaced, the characters from the first position to the last will be deleted and the new text inserted in its place:

  string1 = "0123456"
  string1{2,3} = "abc"
  REM string1 now equals "01abc456"
Note that the number of characters deleted need not equal the number of characters inserted.

Substring Removal
When a character or a set of characters is replaced by a null or space, the effect is to delete the characters:

  string1 = "0123456"
  string1{2,3} = ""
  REM string1 now equals "01456"
  string1 = "0123456"
  string1{2,3} = " "
  REM string1 now equals "01 456"

Substring Reversal
A substring will be reversed if the first of the two pointers is greater than the second:

  string1 = "0123456"
  string1{4,2} = "abc"
  REM string1 now equals "01cba56"

Pointer Rules
Pointers may be an integer, a variable, an expression or a special pointer (the $ symbol). The $ symbol represents next available position in a string (LEN(string)+1). The $ symbol may not be used as part of an expression.

  string1 = ""
  FOR index = 0 to 5
  string1{$} = STR(index)
  Next 
  REM string1 is now " 0 1 2 3 4 5"
The maximum length of a string variable is 254 characters. The permitted range of substring pointers is 0 to the position following the last defined element (LEN(string)+1). Values outside are forced into this range:
  string1 = "0123456"
  string1{12,14} = "abc"
  REM string1 now equals "0123456abc"
Insertion of a substring that creates a result greater than the maximum string size will cause the last characters of the destination string to be dropped.

Substring Pointers and String Functions
Substring pointers may be used with string functions such as LEN() and ASC() to perform some very powerful operations:

  String1 = "abcdefg"
  num1 = LEN(string1{5,$})
  REM NUM1 now equals 2

  string1 = "123456"
  num1 = VAL(string1{0,3})
  REM num1 now equals 123
  x = string1{LEN(string1)-4, LEN(string1)-1}
  REM x becomes "3456"

String constants, literal strings, and string array elements cannot be operated upon or use substring position pointers directly. However, this limitation can easily be overcome by using a string variable as a holder of data to be operated upon. Array data can then be moved into an array element.

Vesta Basic Extensions
Vesta Basic Extensions are external procedures written in C that extend the Vesta Multi-tasking Basic language. There are a total of 256 "slots" built into the Vesta Basic architecture and reserved for external procedures. Some of these slots are used by the external procedures discussed in this section. Many others are used by Vesta Basic "internals", and 32 slots, numbered 0-31, are reserved for programmers who want to write a few specialized routines in C to extend their Vesta Basic program.
In order to write your own extensions you will need the Vesta C Library and a C compiler. You can download your extensions and incorporate them into a new flash image from the Vesta Basic IDE using the Tools|Extensions menus.
For more information on how to write extensions, consult the Vesta C library manual.

Using Extensions
Vesta Basic extensions are usually declared at the beginning of the source code for any task that makes use of them. External procedures are declared like any other procedure, except that you must specify the slot number of the extension. This is done by following the declaration with a colon and an integer that indicates the slot number of the extension. You can call the extension procedure anything you like, but we suggest that for clarity, you use the names provided here. Names of extension procedures are not case sensitive.
Example:

  SUBROUTINE Mynewthing(bit AS INTEGER):43
  FUNCTION Mydoodad(bit AS INTEGER) AS INTEGER:45