Venom-SC Language Help

About this help file

This help file contains a description of the Venom-SC Language and detailed information on every keyword and object in it. There is also a discussion of the language structure, a short list of major new features not covered in the Tutorial Guide, and various tables, charts, diagrams and appendices.

You will probably want to use this help file once you have familiarised yourself with the Venom-SC language from Venom-SC - a Tutorial Guide - supplied as a paperback book in your VM-1 starter kit - or download it from www.microrobotics.co.uk.

Finding what you want

There are several ways to find the information you want in this file:

· From this file, use the Contents, Index or Search tabs at the top of the panel to the left.
· From VenomIDE (our integrated development environment): highlight a Venom keyword, right click it for a pop-up menu, and choose Help on highlighted text.

The most up to date information

NOTE Although this help file reflects the most current information possible, you should read the Venom-SC Release Note for information that may not have been available prior to the publication of this version. In particular, Venom-SC is being continually improved. The Release Note will document the added features and improved functioning available in any particular version of Venom-SC over that described in this help file.

The Release Notes and the Tutorial Guide can be found online at www.microrobotics.co.uk

WARNING: Users of Micro-Robotics Control Equipment should be aware of the possibility of a system failure, and must consider the implications of such failure. Micro-Robotics Ltd. can accept no responsibility for loss, injury, or damage resulting from the failure of our equipment. Use of our products in applications where their failure to perform as specified could result in injury or death is expressly forbidden.

D017 Version: 2012 04 18

Copyright © 2005-2012 Micro-Robotics Ltd

All rights reserved


Language Overview
1. Description and heritage of Venom-SC
2. The structure of Venom-SC
3. New features


Description

Language Overview

Description

Venom-SC is a language for writing small-to-medium sized control applications. Typical uses are

· Industrial automation
· Process control
· Intelligent instruments
· Security systems
· Hand-held devices

Heritage

Venom-SC is based on the original Venom Language running on the Scorpion K4 and K4S. Venom was the ‘object oriented’ translation of the language that ran on the Micro-Robotics Scorpion Control Computer. This language, known as Scorpion, was loosely based on LOGO, a language used to teach computing to schoolchildren.

The ‘SC’ stands for ‘Semi-Compiled’. This means that the code is partly compiled, but not all the way down to native machine code. The earlier languages developed at Micro-Robotics were interpreted; semi-compilation yields a considerable speed increase while maintaining the small code size and flexibility of an interpreter.

Block Structured

Statements in Venom may be grouped together into a block equivalent to a single statement using [ and ]. Language constructs are based around the ‘recursive’ nature of statements.

No statement separators

Venom has no statement separators equivalent to C’s semicolon ‘;’. Instead the Venom parser relies on the syntactic structure of each keyword and operator to recognise where a statement ends. Venom statements will span any ‘white space’, including carriage returns. This allows indentation to reflect the block structure of code.

Weakly Typed

Variables in Venom are stored as a value and a type. The type of a variable is only set when the variable has been assigned a value. Potentially any variable may hold a value of any type. This means the compiler cannot do any type checking on variables. All type checking is done at runtime rather than compile-time. This makes for a flexible and forgiving language for fast application development, but isn’t so formally precise as strongly typed languages. Runtime type checking also has a small speed penalty.

All variables take eight bytes of storage. Four bytes are used to hold the value element of the variable, and one is used to hold the type. Another byte is used to indicate the write-protection status of the variable. The remaining two bytes are reserved for future use.

When a global variable is first created, it is given the special type ‘Unassigned’. This allows the runtime system to error if there is an attempt to use a variable before it has been given a value. Local variables are currently initialised to the value integer zero, unless explicitly initialised at declaration.

Name Scope

Venom has two main user-defined-name scopes: Global variables and local variables. Global variable names are used for procedures and also integer, floating point and other types of variable. Global names are ‘visible’ from any procedure and any task in the multitasking system - unless local variable names eclipse them.

Local variables are only visible from within the procedure where they are defined. If a local variable has the same name as a global, then the local takes precedence. Local variables are created when the procedure is called, and destroyed when the procedure is done. They are held on the stack.

Parameters passed to procedures are essentially local variables that have been initialised to the parameter values, and are equivalent to locals in their operation.

Macros

Macros are bits of program text that have been given a name so that they may be instantiated many times, or simply to improve readability. Macro names are currently just globals. That is, macros are simply another kind of global variable – one that the compiler knows to expand into text at compile time.

Object Orientation

Venom is object oriented in a limited sense: all the objects are pre-defined by the language authors. All the message names have been pre-defined. Because of the weakly typed nature of the language, any variable may potentially accept any message with any parameters, returning any, or no, result. As with other type checking, this is all sorted out at runtime.

A variable that ‘holds’ an object is actually more equivalent to a pointer to that object. If you copy the variable into another variable, then you haven’t got two objects, you have two ‘pointers’ to the same object. They aren’t actually pointers, but ‘handles’. A handle is a value that uniquely identifies a particular object to the code that deals with that type of object. It may, or may not, be a memory pointer.

Future versions of Venom-SC may allow application writers to define their own Venom object types and message names in Venom code or other languages.

Garbage Collection

Garbage collection is the term given to the freeing-up of memory, and other resources, that are no longer required by a program. In some high level languages garbage collection is done automatically.

There is no automatic garbage collection system in Venom, so you will need to keep track of the objects you create yourself. This is most easily handled by creating all the objects your program will ever need at the start of your program. This is the best way in most Venom applications, but there are some applications where you can't predict how many objects of a given type you'll need at the start. In these cases you'll need to create objects dynamically.

Objects created dynamically (i.e. created and destroyed during program operation, rather than just created at the start) are often held in variables local to a procedure. In this case the AUTODESTRUCT mechanism may be used to remove these objects when the procedure ends.

There is a built-in 'memory-leak detector' (or Garbage Scanner) that may be used to qualify Venom programs.

Data Structures

All data structures are handled by objects. Currently the data structures available are:

ARRAY – a fixed-size array of initialised data. ARRAYs can take many types of data.

Buffer – a variable-sized list of variable data that can hold integers, floats, text. Special buffers ('Buffer of Any') may also contain mixed data of any type, including other objects. Buffers can perform sophisticated operations on the data they contain.

String – a fixed-maximum-size array of text.

String Handling

To handle textual data, Venom has string constants, String objects , Arrays of strings, and text Buffers. It also has the PRINT command, which is used to do much more than print to an output device in Venom - it's used to move text around, and extract parts of it.

Multitasking

The Venom-SC language and its forebears have multitasking built in. To the application writer, the task manager is a pre-emptive round-robin system. That is, all tasks have equal priority and run one after the other, being swapped out by the task manager with little external control. Underneath, tasks run co-operatively – choosing when to swap out. This makes the Venom runtime system easier to manage and more efficient. Each part of the venom runtime system is required to obey rules that set the maximum period a task may run for. This then defines the system latency as a the maximum time-slice period multiplied by the number of tasks.

Task scheduling is indicated to the task manager by using language constructs that wait. Examples are WAIT, EVERY and any message to an object that needs to wait: e.g. keypad . Get.

Printing

Printing is used to create a textual representation of a numeric value or an object, and send this text to an output device.

However, in Venom, printing is also used as the basis for most text or string manipulation.

Printing an object, or printing to an object are used to handle a many otherwise lengthy or tedious operations. For example you can show the date and time in an instantly recognisable format by printing the RealTimeClock object. Conversely you may also set the time in the clock by printing a date and time to it.

There are a set of special printing keywords that represent operations like carriage return (CR), clear screen (CLS) and so on. Additional formatting of print output is handled by passing special parameters to the print command using the colon print format operator.

Print output is packaged up into ‘print jobs’. These are discrete amounts of text with some extra coding to take care of the special print keywords that Venom uses. Using print jobs reduces the overhead of sending print output to an output device character by character.


Language Structure

Language Overview

Language Structure

The following is a list of all the elements of the language, building from the bottom up. Only the major structural layers are discussed here; the details of the structure of each keyword and symbol are discussed in the main body of the book.

Character set

Venom-SC uses the following characters, which have been arbitrarily divided into the following classes for discussion:

Alphabetic: A-Z a-z _

Numeric: 0-9

Operator Symbols: + - * / \ < = > @ ? ! ^

Number base: $ % ~

Quote: “ ‘

Separator: , . : ;

Bracket: () []

White space:<SPACE> <TAB> <CARRIAGE-RETURN>

Control: <CTRL-C>, <CTRL-T>

Any other character will cause a syntax error, unless it is part of a character constant or string constant.

Constants

Constants may be integer (sub-divided into decimal, hex and binary), floating point, character or string:

12 $AF %1101101

12.34 1.2E-5

‘A’

“A string”

Integer constants start with a numeric character, or a $ for hexadecimal numbers, or a % for binary numbers. Decimal constants may only use numeric characters. Hexadecimal constants consist of the characters 0-9 and A-F or a-f. Binary constants may only use 1’s and 0’s.

Floating-point constants start with a numeric character and have a decimal point somewhere within them. They may also optionally have an exponential part, indicated by an ‘E’ or ‘e’ followed a positive or negative integer exponent.

Character constants are a single character surrounded by single quotes: ‘A’.

String constants are a group of characters surrounded by double quotes: “abcde”.

The Venom-SC compiler is capable of a high degree of constant folding, so many expressions involving constants are also themselves treated as constants by the compiler: 10 + 100 is treated as 110.

Variable names

Variable names may be up to 64 characters long. They consist of alphabetic, numeric and underscore ‘_’ characters. Names may not begin with a number. Variable names may not be the same as any Venom keyword, class name, or message name.

Variables

Variables in Venom are always eight bytes. Any variable may hold any of the various data types, including handles to any type of object. The value portion of the variable is four bytes wide (32 bits).

There are two main 'scopes' of variable: global and local. Global variables are created simply by using their name either on the command line or in a procedure. Any variable that is not explicitly defined as a LOCAL variable is global.

Loop indexes

There are two ‘variables’ defined by the language: INDEX and INDEX0. These are loop indexes: they hold the loop count for the looping construct currently running. INDEX starts counting at 1, INDEX0 starts at 0. You cannot assign values to them. A distinct value for INDEX0 is held for each level of loop nesting.

Expressions

Expressions consist of one or two sub expressions linked by an operator. The simplest sub-expressions are constants, variables and procedure calls. Expressions of arbitrary complexity may be built up from this ‘recursive’ structure. The order of evaluation of operations is defined by the operator precedence. Parentheses ( ) may be used to override the precedence rules.

There are three main kinds of operator binding in Venom: binary, prefix, and postfix.

Binary operators take two operands, one before the operator and one after it. Prefix operators appear before the operand, and postfix operators appear after it.

Pointer Expressions

This shouldn’t really be a separate level of language structure …

Venom supports many kinds of pointer expressions. In particular you may take a pointer to any variable (including procedures, objects, local variables) using the @ (‘at’) symbol. You may then ‘de-reference’ a pointer using the ! (pronounced ‘pling‘) symbol. Thus you may do many of the sophisticated functions available in other modern languages like calling procedures using procedure pointers.

Statements

A venom statement is relatively complicated to define. Venom statements are the most complicated of the structural layers of the language, closely followed by expressions.

A statement is either

· One of the system operations: MAKE, PRINT, DELETE, HELP, … , etc.
· One of the Venom flow control constructions: IF WHILE REPEAT EVERY … etc.
· An assignment using the := (becomes equal to) operator
· An expression (normally this is a procedure call or a message to an object)
· Square brackets, [ ], surrounding a set of sub-statements.

Detailing each of these…

Venom system operations and flow control constructions are all different, but many of them have one or more expressions or sub-statements as part of their structure. These are all documented later in this book. For example the WHILE statement needs an expression and a sub-statement to complete it:

WHILE <expression> <statement>

Venom assignment syntax is

<Left-hand side expression> := <expression>

A left-hand side expression must evaluate to either a variable, the address of a variable, a memory location, or a message to an object.

Expressions are covered elsewhere.

Square brackets [ ] are for grouping statements together so they are equivalent to a single statement:

[<statement><statement><statement> … ]

As with expressions, statements of arbitrary complexity may be built up with this recursive structure.

Comments

The Venom comment separator is semicolon ‘;’. The compiler ignores any further text until the next carriage return. There is currently no in-line comment structure like C’s /* */. Comments may be placed anywhere within the code.

Procedures

Simply speaking, a procedure is a named list of statements. A procedure is delimited by the keywords TO and END. A procedure may also have a list of parameter names, and a set of local variables. Internally, local variables and parameters are the same thing. The syntax for a procedure is

TO <proc name> (<parameter name> , …)

LOCAL <local variable name> := <expression> , …

<statement>

<statement>

…

<statement>

END

The parameter name list and the local variable declarations and assignments are optional.

Parameters may be separated by commas or white space.

LOCAL variable declarations may be separated by the keyword LOCAL or by commas. You may initialise local variables with any expression. The LOCAL declarations must all come before any other statements.

All procedures return a result: if you don’t explicitly set the return value using the RETURN keyword, then a default value is returned. Currently this is integer zero.

To call a procedure, use its name alone, or with parentheses ( ), after it. If the procedure takes parameters then you need to put expressions for these in parentheses after the name. For example:

my_proc

my_proc()

my_proc_with_params(1,2)

Venom Stack

There is a procedure call stack (called the Venom Stack) that stores the return address of the code that the procedure was called from and the frame pointer - that is a pointer to the current stack frame. A stack frame is an area of the stack that holds the values of all the parameters and local variables that are associated with a procedure. A new stack frame is added to the stack when a procedure is called and removed when the procedure is done.

The return address and frame pointer take 8 bytes of stack memory each, as do each of the parameters and local variables. The size of the Venom Stack is large enough for just about any sensible program that doesn't use recursion.

Tasks

A task is a section of the overall application program that may run concurrently with other sections. In the simplest case there may only be one task running. However it is possible to create other tasks. These tasks will all run at the same time and are independent: in general, several tasks may carry out different operations at the same time.

The venom syntax for creating a new task is:

<task object> := START <statement>

The sub-statement to START will be run as an independent task.

Although the statement may be any Venom code it is good practice to keep it short: often it’s just a single procedure call.

A task will run continuously until it runs out of code to execute, or if it is stopped using STOP or STOP ALL. If the task code is an infinite loop then the task will never end.


New Features

Language Overview

New Features

This section list major new features that have been implemented since the first edition of the Tutorial Guide was printed in 2003.

VenomIDE

This Integrated Development Environment is not strictly a language feature, but it immeasurably improves the Venom-SC programming experience.

The Tutorial chapter Your Development Environment is now completely superseded by VenomIDE. However, if you don't have access to VenomIDE for some reason you can still use a terminal emulator and text editor to program in Venom, as described in this chapter.

Strings

It is now possible to have variable strings of text in Venom-SC. These are implemented using the String object. Strings have a smaller memory overhead than Text Buffers. Additionally, string constants are now also treated like objects (in fact they are just a kind of String object), so you can send messages to them.

Buffer of Any

Buffer of Any is a new kind of buffer that can hold mixed data of any type - including other objects. One use for this might be to hold a list of other buffers, or a list of string objects, for example.

AUTODESTRUCT

AUTODESTRUCT is used to provide much-improved object management for dynamically created objects.

Power operator

There is now a ‘Power of’ operator: X ^ Y.

Type operator

There is now a TYPEOF operator that will return the type of any Venom variable or expression – expressed as an integer in the range 0-255.

For example

TYPEOF 1.0

TYPEOF my_buffer


Language Keywords

This is the complete list of keywords in the Venom-SC language in alphabetic order. Symbols are grouped according to function rather than ASCII order.

How to use the Keywords section

The keywords are in alphabetic order, with the non-alphabetic symbols at the front, roughly grouped together by function rather than in ASCII order. Each keyword has a syntax description followed by information on what the keyword does, with code examples

PRINT net ; This is a code example

There may be supplementary information of various kinds, indicated by the following icons:

LIMIT

This gives information on any limits to the parameters or results of the keyword

Hardware

This gives information on the hardware needed to use this keyword.

memoryUse

This gives information on the memory usage of the keyword

TimingIcon

This gives information on timing aspects of the keyword

SeeAlso

This gives pointers to other parts of the manual for related topics

BugAlert

This warns you to beware of putting bugs in your code

Syntax descriptions

Under each keyword there is a semi-formal description of the way it is used in a program; both the syntax and the types of parameters and results are given.

The syntax descriptions are not intended to be fully precise, but instead to give a simple guide as to how the keywords and symbols should be used. The complexity of a fully precise description of each keyword might obscure rather than illuminate its operation.

· Here is a guide to interpreting the syntax descriptions.
· Text in italics indicates an optional part of the construction.
· Text in <angle brackets> indicates a reference to a ‘lower level’ construct:
· <name> means any Venom name, and may be qualified by Global or Local
· <statement> means any Venom statement
· <expression> means any Venom expression, and may be qualified by a data type.
· The following indicate the data type of a value: Int, Float, String, Object, Pointer, Any. Any means that the data type might be any of the other types.
· The symbol rarrow means the construction returns a result. The type is given in 'light' (not bold) text: e.g. Int
· Ellipses … indicate optional repetition of the preceding construct.

As an example let’s look at one of the more complex keywords: TO

TO <global name> (<local name> , …)
<Local list>
<statement>
…
END

And expanding one of the terms:

<Local list> is one of:

LOCAL <local name> := <expression> , …

or

LOCAL <local name> := <expression>

…

And here’s what it means…

TO is the keyword.

<global name> means a global variable name.

( <local name>, …) means an optional list of local variable names (the parameter list).

<Local list> means a list of local variables, which is defined below; it can take several forms: delimited by commas, or by the keyword LOCAL.

<statement> means any venom statement, with the ... below indicating a list of such statements.

:= <expression> means an optional assignment with an expression.


+

Language Keywords

+

< Int expression> + < Int expression> rarrow Int
< Int expression> + < Float expression> rarrow Float
< Float expression> + < Int expression> rarrow Float
< Float expression> + < Float expression> rarrow Float

The + operator adds two numbers. If either operand is a floating-point number, the result will be floating-point.

See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands and result of + are those that apply to all internal calculations. SeeNumber Limits


. [Dot]

Language Keywords

. [Dot]

<Object expression> . <Message> (<param list>) rarrow Any
<Object expression> . <Message> (<param list>) := Any

The dot operator is used to send a message to an object.

See each of the object types for the list of message they accept, and what each one does.

(Note: the same character is also used in floating point numbers to represent the decimal point).

Active Variables

An active variable is a notional value 'inside' an object which can both be read, and also written using :=.

An example is Digital’s message .Asserted, which can be used both to read and write the state of a Digital channel:

-->PRINT Motor_Actuator.Asserted, CR
-1
-->Motor_Actuator.Asserted := FALSE

Some active variables can also take parameters, like Buffer.Element(p).

For example, to set the tenth element of a Buffer called ‘values’ to 99, then read it out again:

-->values . Element(9) := 99
-->PRINT value . Element(9)
99

Sub classes

A message to an object can return an object as its result.

When a message actually creates a new object of a different type, then this new object is one of a 'sub-class'.

An example is Keypad’s InputBuffer.

ib := kpd . InputBuffer (10, 10)

Here ib is a new Keypad:InputBuffer object. It will accept messages:

k := ib . Key

Sub-class objects are always related to the ‘parent’ object – that’s why they are created in this unusual way. This is because they will need to be 'aware' of each other in some way to work correctly.

In the case of Keypad’s message, InputBuffer, scanning the keypad with Update will also update all InputBuffers and other subclass objects associated with the keypad.


*

Language Keywords

*

< Int expression> * < Int expression> rarrow Int
< Int expression> * < Float expression> rarrow Float
< Float expression> * < Int expression> rarrow Float
< Float expression> * < Float expression> rarrow Float

The * operator multiplies two numbers. If either operand is a floating-point number, the result will be floating-point.

See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands and result of * are those that apply to all internal calculations. See Number Limits


/

Language Keywords

/

< Int expression> / < Int expression> rarrow Float
< Int expression> / < Float expression> rarrow Float
< Float expression> / < Int expression> rarrow Float
< Float expression> / < Float expression> rarrow Float

The / operator divides the left-hand operand by the right-hand. The result is always floating-point, even if both operands are integers. Use DIV if you want to do integer division.

See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands and result of / are those that apply to all internal calculations. SeeNumber Limits


^

Language Keywords

^

<Int> ^ <Positive Int> rarrow Int
Otherwise...
<Int or Float> ^ <Int or Float> rarrow Float

The ^ operator raises the first operand to the power of the second. If both operands are INT and the second is positive then the result will be an integer.

Note: ^ has the same precedence as *, etc. See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands and result of ^ are those that apply to all internal calculations. See Number Limits


"

Language Keywords

"

"<characters>"  rarrow  String constant

<characters> is a string made up from any printable character apart from “ and \. These and other special characters may be introduced with an escape sequence.

The double quote symbol is used to enter text strings into the program. It must always be balanced with another quote at the end of the string. Strings may not extend over more than one line. All quoted strings are string constants. That is you may not change the characters within the string after it has been defined.

You may use string constants in fairly sophisticated ways. For example you may enable your application for different spoken languages. By running one of the procedures below at any time you can change your user interface language:

TO english

Yes_string = “Yes”

No_string = “No”

END

TO french

Yes_string = “Oui”

No_string = “Non”

END

…

IF answer_correct

PRINT yes_string

…

If you need more sophisticated text handling (manipulation of characters within a string etc), use a String object or Buffer object.

Similar to string objects

Note that string constants and String objects (variable strings) are very similar: string constants will accept many of the messages that string objects will. For example string constants can be asked for their length with .Length:

PRINT Yes_string.Length

3

Escape sequences

In Venom-SC an escape sequence is introduced with the \ character ('backslash'). The complete list of escape codes is

Sequence | Yields the character | ASCII
\\ | Backslash: \ | 92 | $5C
\" | Double quotation mark: " | 34 | $22
\$hh | Any ASCII character from hexadecimal | - | hh
\a | Causes a terminal to emit an audible alert | 7 | $07
\b | Backspace | 8 | $08
\f | Form feed | 12 | $0C
\n | New line | 10 | $0A
\r | Carriage Return | 13 | $0D
\t | Horizontal tab | 9 | $09
\v | Vertical tab | 11 | $0B
\^hh | Sprite insertion - see GraphicsLCD accept print. | - | hh

The sequence of \ followed by any other character is ignored completely (no characters are entered into the string constant) – though additional sequences may be added in future.

SeeAlso Print formatting for strings.


=

Language Keywords

=

<Any expression> = <Any expression> rarrow Int

The ‘Equals’ operator takes two numbers and performs a comparison.

It evaluates to TRUE (-1) if its two operands are the same type and value, FALSE (0) otherwise.

N.B. Unlike other operators, = does no type coercion, so a Float is never equal to an Int

For example,

PRINT 1 = 1.0
0

This limitation is used so as to preempt problems caused by Floats being imprecise in some circumstances. If you need to compare an Int and a Float, use the type conversion operators AS INT or AS FLOAT:

PRINT 1 AS FLOAT = 1.0
-1

Comparing floats

While it is possible, it is not usually a good idea, to compare two Float values using =. Two Float values may appear the same in some circumstances, but may be different in others. For example

-->PRINT 1/7 , CR

0.142857

-->PRINT (1/7 = 0.142857) , CR

0

i.e. the two values for 1/7 were not seen to be the same.

Instead use operators like > and <, etc. to compare Floats.

Comparing strings

When = is used to compare strings, the comparison is made between the objects' 'handles' (pointers), not the text. Thus = can not usefully be used to compare two strings - instead use String.Compare.

See operator precedence for which operators are evaluated first.

LIMIT

The two operands can be of any type.


<>

Language Keywords

<>

<Any expression> <> <Any expression> rarrow Int

The ‘Not equal’ operator takes two numbers and performs a comparison.

It evaluates to TRUE (-1) if its two operands are of different types or values, FALSE (0) otherwise.

In general, it is unwise to use = and <> with floating point numbers. See = for more information about this.

See operator precedence for which operators are evaluated first.

LIMIT | The two operands can be of any type.
SeeAlso | Equals operator


<

Language Keywords

<

<Any expression> < <Any expression> rarrow Int

The ‘Less than’ operator evaluates to TRUE (-1) if the first operand is less than the second, FALSE (0) otherwise.

< can be used with mixed integer and floating-point operands.

See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands of < are those that apply to all internal calculations. See Number Limits


>

Language Keywords

>

<Any expression> > <Any expression> rarrow Int

The ‘Greater than’ operator evaluates to TRUE (-1) if the first operand is greater than the second, FALSE (0) otherwise.

> can be used with mixed integer and floating-point operands.

See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands of > are those that apply to all internal calculations. See Number Limits


<=

Language Keywords

<=

<Any expression> <= <Any expression> rarrow Int

The ‘Less than or equal’ operator evaluates to TRUE (-1) if the first operand is less than or equal to than the second, FALSE (0) otherwise.

<= can be used with mixed integer and floating-point operands.

See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands of <= are those that apply to all internal calculations. See Number Limits


>=

Language Keywords

>=

<Any expression> >= <Any expression> rarrow Int

The ‘Greater than or equal’ operator evaluates to TRUE (-1) if the first operand is greater than or equal to than the second, FALSE (0) otherwise.

>= can be used with mixed integer and floating-point operands.

See operator precedence for which operators are evaluated first.

LIMIT

The limits to the operands of >= are those that apply to all internal calculations. See Number Limits


%

Language Keywords

%

%<zeros or ones> rarrow Int

<zeros or ones> is a number made up from the characters 0 or 1 only

The percent symbol is used to indicate binary (base-2) numbers. Binary numbers are often useful for accessing memory or hardware registers directly, and also for entering ‘sprite’ bitmaps. For example:

PRINT %101010
42

LIMIT | The maximum positive number that can be entered in binary is %1111111111111111111111111111111 (31 1’s). The minimum, most negative, number that can be entered in binary is %10000000000000000000000000000000 (a 1 and 31 0's)
SeeAlso | See also $, ~~


'

Language Keywords

'

'<character>' rarrow Int

<character> is any printable character, or one of the escape code sequences.

The single quote is used to enter ASCII character constants into a program. It is just another way of expressing an integer.

For example

-->PRINT 'A' ;ASCII code for A

65

-->PRINT '\'' ;escape sequence for ACSII single quote

39

The full list of escape codes for other characters is

Sequence | Yields the ASCII code for | ASCII Value
\\ | Backslash: \ | 92 | $5C
\' | Single quotation mark: ' | 39 | $27
\a | Causes a terminal to emit an audible alert | 7 | $07
\b | Backspace | 8 | $08
\f | Form feed | 12 | $0C
\n | New line | 10 | $0A
\r | Carriage Return | 13 | $0D
\t | Horizontal tab | 9 | $09
\v | Vertical tab | 11 | $0B


~

Language Keywords

~

PRINT ... ~ <Int expression> ...
PRINT ... ~~ <Int expression> ...

The tilde modifier (pronounced tillda) is used to print integers in hexadecimal or binary.

Hexadecimal

In hexadecimal the letters A-F will always be printed in upper case. For example:

PRINT ~41457
A1F1

Note that hexadecimal numbers are not printed with a $ prefix. Hex numbers are always printed as ‘unsigned’ E.g.

PRINT ~-1
FFFFFFFF

The formatting of hexadecimal numbers is the same as decimal integers.

SeeAlso

See also $, %, :

Binary

Printing in binary is indicated using two tildes - ~~.

For example:

PRINT ~~42
101010

Note that binary numbers are not printed with a % prefix. Binary numbers are always printed as ‘unsigned’ E.g.

PRINT ~~-1
11111111111111111111111111111111

The formatting of binary numbers is the same as decimal integers. See : for more details.

SeeAlso

See also $, %, :


: [print formatting]

Language Keywords

: [print formatting]

PRINT <Any expression> : <Any expression> : … , …

The colon symbol is a print format modifier.

Zero or more colons are used after each item in a PRINT list to specify the formatting of the item being printed. Each colon is followed by a parameter. The way these formatting parameters are interpreted depends on the type of thing being printed:

Integers

Floats

Strings

Objects

Other formatting options

C-Style formatting

IP dotted-quad style

[****]


Formatting Integers

Only one colon formatting parameter is used for integers, and this sets the minimum number of characters, or field width, used to print the number. This is used to make neat columns of right-justified numbers, for example:

-->PRINT 1:4, 123:4, CR, 99:4, 456:4
1 123
99 456

If the number takes more digits than the given field width, it will take as many characters as it needs. Hence to print a number with no minimum field width use :0 like this:

-->PRINT 1:0, CR, 1234:0, CR, -56:0
1
1234
-56

If the colon is omitted the default field width of 6 places is used:

-->PRINT 1,CR,1234,CR,-56,CR
1
1234
-56

If a negative field width is used, the number is printed in the same number of places as if the number was positive, but leading zeros are used instead of spaces to pad out the number. For example:

-->PRINT 1:-6,CR,1234:-6,CR,-56:-6,CR
000001
001234
-00056


Formatting Floats

There are three ways of formatting floating point numbers. The type of format applied to the number depends on how many colons are used.

: General

When just one colon value is given it simply specifies the total fieldwidth the number should be printed in. (If no colon is used then the default Float fieldwidth of 13 is applied).

Beyond that, the formatting is dependant on the value of the number, but will generally aim to represent the number in the most precise form possible.

-->PRINT 1.234,CR,10.324,CR,100000.0:11,CR,0.123,CR,1.123E8:16

1.234

10.324

100000

0.123

1.123E+08-->

: : Fixed Point

When two colons are used, the floating-point number is printed in ‘fixed point’ format. The first colon value gives the total fieldwidth and the second the precision (the number of digits after the decimal point). The fieldwidth will be exceeded if it is too small to represent the number correctly with the specified precision.

-->PRINT 3.1415:15:3, CR, 3.1415:9:3, CR, 3.1415:3:3
3.141
3.141
3.141

If the fieldwidth is negative, then the number will be printed with leading zeros.

: : : Exponential

When three colons are used the number is printed in exponential notation. The first colon value gives the total field width to print in. The second gives the precision to use. The third specifies exponential notation, irrespective of its value. Four characters are used to print the ‘E’, the exponent and its sign. The fieldwidth will be exceeded if it is too small to represent the number correctly with the specified precision. For example:

-->PRINT 3.1415:15:3:5, CR, 12.34:9:3:3, CR, 0.0019:3:3:3

3.141E+00

1.234E+01

1.900E-03-->


C-style printf() formatting

As a convenience for those used to C-style print formatting with printf(), you can use a colon followed by a string to format any Venom-SC printing.

The string must start with a ‘C’ or a ‘c’ character, which informs Venom-SC that this is a C format string. Then just use any of the normal C conventions for formatting.

For example

-->PRINT 12 : "CThe boy was %li years old\r\n"

The boy was 12 years old

-->

-->PRINT 123.45:"Cthe offset was %+9.3fmm"

the offset was +123.450mm-->

Note that an upper-case ‘C’ will put send the Venom variable to printf() as a long, float or pointer quantity, and a lower-case ‘c’ will send it as an int or char quantity.

If you are printing strings and floats you will need to use ‘C’, whereas if you are printing characters you will need to use ‘c’. For integers you can use either, though of course they will be truncated to 16 bits if you use ‘c’. Remember that you will need to use the long integer specifier 'l' or 'L' when you use 'C'.

Also, you can only include one % format descriptor in each string - because you can only apply the C-style formatting to one Venom variable at a time.


IP dotted-quad formatting

If you use the string “IP” to format any Venom variable, it will be printed in the standard IP address format of a ‘dotted quad’:

PRINT 1234567890:"IP"

73.150.2.210-->

SeeAlso

See also 'PRINT message' in the Index for printing each object type.


Formatting Objects

Colon print formatting is also used to specify to an object how it should print itself. Each object type attaches its own meaning to the colon values given. For example, to print a Timer’s period as HH:MM:SS, the following format is used:

-->PRINT timer_object :1 :1
01:30:00

For more information, see the PRINT message for each object type in Object Types.


Formatting strings

You can use the : operator to specify how a string is to be printed. One colon, :n, will print the leftmost n characters from a string. If the number is negative, you get the rightmost n characters:

-->str := "abcdefghij"

-->REPEAT 10 PRINT "[",str:INDEX0-5,"]"

[fghij][ghij][hij][ij][j][][a][ab][abc][abcd]-->

Using two colon operators allows you to print any portion of a string you wish to, and additionally, will pad out the printed portion with space characters to a required width. This allows you to both select portions of the string and to implement scrolling text.

The first colon specifies where to start printing within the string, and the second specifies how many characters to print. If the start position is negative, or more characters are requested than are in the string, then space characters are printed.

-->REPEAT 10 PRINT "[" , "abcdefghij" :INDEX0-5:10 , "]" , CR

[ abcde]

[ abcdef]

[ abcdefg]

[ abcdefgh]

[ abcdefghi]

[abcdefghij]

[bcdefghij ]

[cdefghij ]

[defghij ]

[efghij ]

-->

You can use colons to print text Buffers or String objects in exactly the same way.

Incidentally, you may find it useful to know that string constants understand the all same messages as String objects.


,

Language Keywords

,

... <list_item> , <list_item> ...

Commas separate items in a parameter list, a print list or other lists.

Parameter lists are used when calling procedures, sending messages or in MAKE statements or similar keywords. The use of commas in parameter lists is optional. However, you must use commas to separate items in a PRINT list.

fred(a,b,c,d)
MAKE vt100 TerminalFilter("VT100", serial2)
k:=keys.Key(3,1)
or
fred(a b c d)
MAKE vt100 TerminalFilter("VT100" serial2)
k:=keys.Key(3 1)

Comma may be used to separate items in LOCAL declarations.


?

Language Keywords

?

? <Int> lrarrow <Int>
?? <Int> lrarrow <Int>
???? <Int> lrarrow <Int>

The ‘query’ operators give direct access to the memory of the controller.

They may be used to access hardware registers, or directly read and write to the RAM or flash memory. No checking is done on what is being accessed, so using them carelessly is dangerous. In particular, writing to the wrong address can cause unpredictable errors in unrelated parts of the program.

The size of values read or written depends on the number of ? symbols used. Hence one ? reads and writes bytes, ?? read and write 16-bit words, and ???? read and write 32-bit long-words.

Hence to print the byte at $F0 in hexadecimal:

PRINT ~? $F0

To set the two bytes at $8100 to $FF00:

??$8100 := $FF00

Note that with multi-byte accesses, the highest byte goes first, so in the previous example, $8100 gets $FF and $8101 gets $00.

To transfer 4 bytes from $8100 to $8104:

????$8104 := ????$8100

Note that hexadecimal is very often used for the addresses and values, as it is number base that naturally suits operations on memory.

LIMIT | The ?? and ???? operators must be given an even address to work with. Supplying odd addresses will yield undefined results.
TimingIcon | Multi-byte accesses are done atomically with respect to tasks and interrupts, so ‘skewed’ reads or updates will not occur.


!

Language Keywords

!

! <Pointer> rarrow Any
! <Pointer> := Any
(! <Pointer>)(<parameter list>) rarrow Any

The ! (or 'pling') operator is used to follow a pointer, either to read the value of the thing pointed to, or to write it.

Using Pointers

Pointers are created with @ followed by the name of a global or local variable. ! is used to follow the pointer, and so access the variable:

-->a := 99
-->p := @a
-->a := 100
-->PRINT !p,CR
100
-->!p := 101
-->PRINT a,CR
101

Pointers are usually used for ‘pass-by-reference’ parameters, getting multiple results from a function and so on.

Procedure Pointers

Procedure pointers are really the same as other pointers. You just use @ with a procedure name instead of an ordinary variable name. ! is used to call the procedure, with parameters if necessary. In the following example, ! is used to call a comparison routine to decide on the ordering of a sort.

PROGRAM START
TO ascending(a,b)
RETURN a<b
END

TO descending(a,b)
RETURN a>b
END

TO sort(tab,routine)
LOCAL len,swapped,temp
tab := tab.copy
len := tab.Length
DO
[ swapped := FALSE
REPEAT len - 1
[ IF NOT (!routine)(tab.(INDEX0),tab.(INDEX))
[ temp := tab.(INDEX0)
tab.(INDEX0) := tab.(INDEX)
tab.(INDEX) := temp
swapped := TRUE
]
]
]
WHILE swapped
RETURN tab
END

ARRAY tabconst (8,10)
7,4,2,6,1,3,9,5,8,10
END

PROGRAM END

-->PRINT sort(tabconst,@ascending)

1 2 3 4 5 6 7 8 9 10-->

-->PRINT sort(tabconst,@descending)

10 9 8 7 6 5 4 3 2 1-->


@

Language Keywords

@

@ <Any global name> rarrow Pointer
@ <Any local name> rarrow Pointer

The @ symbol is used to create pointers. These pointers are used to pass information to procedures or messages about how to fetch or set a result, without fetching it or setting it immediately. The detailed uses of this are described under each pointer type separately:

Creating Pointers

A pointer will point to a variable. A pointer is created by prefixing the name of the variable with @. The pointer may be followed (or de-referenced) the ! operator.

One common use of pointers is for 'pass-by-reference' parameters for procedures. Normally the value of a parameter is calculated and this value is passed to the procedure. The procedure cannot 'reach back' and change the value of the original variable. For example:

TO fail_to_swap(a,b)
LOCAL temp
temp := a
a := b
b := temp
END

-->x := 1
-->y := 2
-->fail_to_swap( x , y )
-->PRINT x,y,CR
1 2

Setting the parameter variables a and b in fail_to_swap does not have any effect on x or y, since they are local to the procedure. In some languages, such as Pascal, it is possible to define a procedure so that it can reach back to the variables in the parameter list. In others, such as C, you need to pass pointers to the procedure, and use pointer operations to read and set the variables. Venom is like C in this respect.

The swap routine written properly in Venom would be:

TO swap(a,b)
LOCAL temp
temp := !a
!a := !b
!b := temp
END
-->x := 1
-->y := 2
-->swap( @x, @y )
-->PRINT x,y,CR
2 1

This ability to set the caller's variables can also be used to return more than one result from a function.

Note: If pointers to local variables are taken, it is important to ensure that the lifetime of the local variable they point to is not less than that of the pointer, otherwise you could be left with a 'dangling pointer’. This means that the pointer to a local variable must not be used after the procedure that created the local variable has finished. There is no such problem with pointers to global variables.

Memory addresses

The pointer created by using @ is not the memory address of the variable. However you can find the memory address by converting the pointer to an integer using AS INT.

Creating Procedure Pointers

A procedure pointer is a a pointer to a procedure, and is created by prefixing the name of the procedure with @.

TO square(x)
RETURN x * x
END

-->operation := @square

Procedure pointers are most often used where one of a number of similar procedures might be called with the same parameters.

See here for how to use a procedure pointer.


:=

Language Keywords

:=

<LHS> := <Any>

Where <LHS> indicates a valid Left Hand Side expression and is one of

<global name>

! <pointer>

<Object> . <message> (<parameter list>)

???? <Int>

The assignment operator may be used to set the value of variables, active variables (i.e. a message to an object that may be assigned a value), or internal memory locations.


( )

Language Keywords

( )

Parenthesis, or round brackets, are used in three different contexts in Venom-SC:

Evaluation order

( <Any> ) rarrow Any

Parentheses, or round brackets, are used to force the evaluation of an expression before normal operator precedence. Parentheses may be nested, that is you may put parentheses inside other parentheses.

For example

-->PRINT 3*4+5, 3*(4+5), 4*(3-(4-5)),CR

17 27 16

-->

Any legal expression of any type can be put in parentheses.

If you need to start a command with parentheses then you need to use square brackets to indicate the start of a command (this is a limitation of not having statement separators like ; in C):

[(!pointer).Put(0)]

LIMIT

The maximum level of parenthesis nesting is currently set by the stack space available to the Venom compiler and is not defined as yet.

Parameter list

(<Any> , …)

Formal parameter list

(<Local name> , …)

Round brackets are used to indicate both formal and actual parameter lists.

A formal parameter list follows the procedure name in a procedure definition. It lists the names of the parameters to the procedure.

An actual parameter list follows a procedure name in a call to a procedure. It lists the values to pass to the parameters of the procedure.

In both formal and actual parameter lists the commas separating the parameters are optional.

fred(1 2 a * b + c)

fred(1 , 2 , a * b + c) ;equivalent.

LIMIT

The maximum number of parameters you may pass is 253. Each local variable used will reduce the number of parameters available by one.


; [Comment]

Language Keywords

; [Comment]

; <characters>

<characters> is a list of any characters apart from Carriage Return.

The semi-colon symbol is used to introduce a comment into the program. The compiler will ignore text from the semi-colon until the start of the next line.

Comments serve the very important purpose of documenting the program, both for the author and anyone maintaining it.

Comments do not affect the code size or execution speed of your programs.


ABS

Language Keywords

ABS

ABS <Int expression> rarrow Int
ABS <Float expression> rarrow Float

The ABS operator returns the absolute value of its operand; in other words, it makes it positive.

For example:

-->PRINT ABS 99, ABS -99
99 99

See operator precedence for which operators are evaluated first.

BugAlert

The absolute value of the most negative integer ($80000000) has no representation as a positive number within the 32-bit values allowed in Venom-SC. 0 is returned.


ACOS

Language Keywords

ACOS

ACOS <Float expression> rarrow Float

The ACOS operator returns the inverse cosine of an angle in radians.

See operator precedence for which operators are evaluated first.

SeeAlso

See also COS SIN TAN ASIN ATAN


ALL

Language Keywords

ALL

All is used only in conjunction with other keywords, such as CATCH, LIST, STOP.


AND

Language Keywords

AND

<Int expression> AND <Int expression> rarrow Int

The AND operator is used in what appear to be two different contexts, although its operation in each is the same. It is often used in the expression of an IF construct to make a more complex condition.

IF cows_home AND its_milking_time

machine . On

Simply put, AND will return TRUE only if both of its parameters are TRUE.

However in more detail, AND returns the bit-wise AND of its two operands.

A bit is set in the result if both of the corresponding bits in the operands are set. Because of this, AND is often used to clear one or more bits while leaving the rest alone. For example

PRINT ~~%101010 AND %001100
1000

Internally, what happened was this 32-bit operation:

AND

0000000 00000000 00000000 00101010
0000000 00000000 00000000 00001100
0000000 00000000 00000000 00001000

See operator precedence for which operators are evaluated first.

SeeAlso | See also OR, EOR, NOT, TRUE, FALSE
BugAlert | Beware that all non-zero values are taken by the IF construct as meaning TRUE, but that it is possible for AND to return FALSE even when both its operands taken separately would be treated as TRUE.


ARRAY

Language Keywords

ARRAY

ARRAY name (Any Const prototype , Int Const size)
Any Const value
Any Const value
…
END

Note: the keyword ARRAY can be used in two contexts:

1. To define constant arrays - i.e. lists of data values that are fixed
2. With MAKE or NEW to create Array objects that can hold variable data

Here we will look at constant arrays.

A Venom ARRAY is a data structure - i.e. something that holds a collection of data. The data held by an array is all of the same type, and there is a fixed amount of it.

The kind of array considered on this page holds constant data - that is the values of the data never change during the lifetime of the program.

Constant arrays are created at compile time - i.e. they are written into your program code alongside, and in a similar way to procedures. For example, a section of your code might look like this:

...

TO simple_procedure
led.On
END

ARRAY simple_array (8,5)

1,2,3,4,5

END

...

ARRAY names

Arrays are given a name, which has to obey the same rules as any name in Venom.

Parameters to ARRAY

After the ARRAY keyword, and the name of the array, some parameters are supplied in parentheses:

ARRAY name (prototype , size)

prototype is a value that gives the type of data elements that the array will hold:

Prototype value | Element type | Range of values element can hold
8 | 8-bit integer (unsigned) | 0 to 255
16 | 16-bit integer (signed) | -32768 to +32767
32 | 32-bit integer (signed) | -2,147,483,648 to 2,147,483,647
1.0 * | Floating point (IEEE single precision) | ~ ±1.0E±38, ~7 digtits of precision
"" ** | String constant | Any string constant or String object
@dummy_name*** | Pointer to a global | Any pointer to a global variable

*or any floating point number. **or any string constant. *** or any pointer to a global variable.

size (an integer) specifies the number of items in the array - i.e. how much data it will hold.

Data items

After the array parameters have been supplied, the data that fills the array is listed. You should use commas to separate the data, especially if you need to enter negative numbers. If there are not enough data items, then the array is filled to the end using the value of the last item. If there are too many items, then a syntax error is given.

Accessing the array

Once created, a constant array is an Array object, and may be accessed using the same messages as for any kind of array; see the Array object.

Examples

Here are some examples of small ARRAYs.

;An array of 8-bit integers

ARRAY lookup_data (8 , 5)

2 , 3, 5, 7 , 6

END

;An array of string constants, with the last 4 being the same.

ARRAY phrases (“” , 6)

“Hello”

“Goodbye”

“Ciao”

END

;An array of procedure pointers

ARRAY handler (@dummy , 3)
@first_proc
@second_proc
@third_proc

END

See here how to call such procedures.


AS

Language Keywords

AS

<Float> AS INT  rarrow  Int
<Pointer> AS INT  rarrow  Int
<Int> AS FLOAT  rarrow  Float

The AS operator is used to 'cast', or change the type of, a value.

The AS INT operator takes a floating-point number, and returns the integer part of it, truncating towards zero. For example:

-->PRINT 2.7 AS INT, -2.7 AS INT
2 -2

If AS INT is used on an integer, it has no effect.

AS INT will also convert a value of type Pointer to an integer, in this case representing the actual address of the thing pointed to in memory.

For example, in the following code, addr is set to the address in memory of the value of the global variable var.

var := 1.0

ptr := @var

addr := ptr AS INT

The AS FLOAT construct takes an integer and gives the nearest floating point representation of it. For example:

-->PRINT 23 AS FLOAT
23.000000

If AS FLOAT is used on a floating-point number, it has no effect.

Note: Information may be lost when casting in either direction. AS INT obviously loses the fractional part of the number, but also AS FLOAT will lose precision from integers larger than ~16,777,216.

See operator precedence for which operators are evaluated first.

LIMIT | The maximum float which can be cast to an integer for general calculation is 2.1474828E9. The maximum float that can be cast to an integer for storage in a variable or passing to a procedure or message is 1.0737418E09. The maximum integer which can be cast to a float to be stored in a variable without losing precision is around 17,000,000.
SeeAlso | See also Number limits


ASIN

Language Keywords

ASIN

ASIN <Float expression> rarrow Float

The ASIN operator returns the inverse sine of an angle in radians.

See operator precedence for which operators are evaluated first.

SeeAlso

See also COS SIN TAN ACOS ATAN


ATAN

Language Keywords

ATAN

ATAN <Float expression> rarrow Float

The ATAN operator returns the inverse tangent of an angle in radians.

See operator precedence for which operators are evaluated first.

SeeAlso

See also COS SIN TAN ACOS ASIN


AUTODESTRUCT

Language Keywords

AUTODESTRUCT

AUTODESTRUCT

This keyword is applied to a list (or part of a list) of LOCAL variables to indicate that they hold objects that should be destroyed when a procedure ends.

Example syntax:

TO proc

LOCAL a, b, c

LOCAL d

AUTODESTRUCT

LOCAL temp_obj

…

temp_obj := NEW String(100)

…

END

Any Local variables declared after the AUTODESTRUCT keyword will be examined when the procedure ends. Each of them that holds an object will be sent the message Die.

Local variables listed before AUTODESTRUCT are treated as normal: i.e. any objects they hold will not be destroyed.

This is particularly useful if you have to create temporary objects in your code, and don’t want to have to think of all the possible places or mechanisms via which your code might exit the procedure, at each of which you would have to explicitly kill all the temporary objects.

AUTODESTRUCT works in conjunction with END, RETURN, REGION/EXIT, CATCH/THROW, STOP and STOP ALL.

It does not act when an error stops a task, or when CTRL-C breaks into the main task.

SeeAlso See also NEW, Zero-memory objects, Garbage Scanner


AWAIT

Language Keywords

AWAIT

AWAIT <Int expression>

The AWAIT command waits indefinitely while the condition is false (i.e. zero). When the condition becomes non-zero, program execution resumes at the next statement in the program. For example:

AWAIT the_cows_come_home
milking_machine . On

While it is waiting AWAIT will swap tasks.

It is functionally equivalent to, but slightly more efficient than,

WHILE <condition>

SWAP

TimingIcon

A task waiting in AWAIT ‘swaps out* ’ as soon as it finds the expression is false (zero). Hence the overhead of a task waiting in AWAIT is the time it takes to calculate the expression each time it gets scheduled. AWAIT also allows the task manager to put the controller core to sleep, saving power.

* ‘Swapping out’ means that the task passes control to the task manager which will find another task to run, or carry on with the current task if there are none.

BugAlert

Beware that all non-zero values are taken by the AWAIT construct as meaning TRUE, but that it is possible for AND, for example, to return FALSE even when both its operands taken separately would be treated as TRUE.

SeeAlso

SWAP


BEEP

Language Keywords

BEEP

PRINT ... BEEP ...

The BEEP print item is used to cause an audible warning on the device printed to. It is equivalent to ASCII character 7 (BEL).


BREAK

Language Keywords

BREAK

BREAK

Break is used to break out of loops. Break will immediately exit to the next statement past the end of any loop.

EVERY 1000

[

done_it := do_something

IF done_it = TRUE

BREAK

]

carry_on

When done_it is true, then execution will immediately carry on at carry_on.

SeeAlso

See also FOREVER, EVERY, WHILE, DO, UNTIL, REPEAT


BS

Language Keywords

BS

PRINT ... BS ...

The BS print item is used to move backwards one character on the device printed to. It is equivalent to ASCII character 8.

This character is intended to be non-destructive - i.e. it moves back one space, but does not rub out the previous character. To do a destructive delete operation, it is safest to send a BS, then a space, then another BS.


CALL

Language Keywords

CALL

CALL (<Int expression> , <parameter list> , ...) rarrow Any

CALL will call code compiled from C or Assembler.

CALL takes any number of parameters, but the first one must be the address of the code to call, e.g.

CALL (address_of_my_code)

Your called code should expect to receive one parameter, equivalent to a void* in C, in register ER6. Your code is responsible for saving and restoring the contents of any other registers it uses.

The value in ER6 is a pointer to the Venom stack that contains all the parameters to CALL, except that the code address (the first parameter) has been overwritten with the number of Venom parameters sent to CALL. This first parameter position is also the place to put any result you wish to return from CALL. Note the Venom stack grows upwards, i.e. it starts at low memory.

CALL (address , A , B , C)

Would put the following on the venom stack

C

B

A

rarrow 4 ;N Params - Put return result here.

Each Venom value on the Venom stack is 8 bytes wide. The first 4 bytes are the value (MSB first on a 'big-endian' processor). The other 4 bytes hold the type and write-protection information (there is also some reserved space).

Byte 0 1 2 3 4 5 6 7

[xx][xx][xx][xx][--][--][WP][TYPE]

For example, say you wanted to call a C routine that multiplies two numbers and sends the result back. See below for the definitions used.

long mult2ints(venom_value * stk)

{

/* Do the multiplication */

* stk = (stk + 1)->value.as_int * (stk + 2)->value.as_int;

/* Set the type of the result to integer */

* stk -> val_type = VENOM_TYPE_INT;

}

Here are some definitions used with Venom variables. There is the possibility that these will change slowly over time, so check they are up to date if you need to use them. They will be made available on our website if they change.

typedef struct

{

union

{

long as_int; /* The actual value of an int… */

float as_float; /* … or access it as a float */

void * as_pointer; /* or a pointer… */

unsigned long long_word;/* or one 32-bit word… */

unsigned short word[2]; /* or two 16-bit words… */

char byte[4]; /* or four 8-bit bytes. */

}value;

char res1; /* Reserved for future use */

char res2;

char write_protect; /* If set, don't allow writes */

char val_type; /* The data type. */

}venom_value;

#define VENOM_TYPE_INT 0

Task Swap Timing

Internally the Venom task manager relies on each task electing to 'swap out'. So as not to contravene the task manager's rules your foreign code should not take more than 2mS to complete.

An operating system call to the task manager to swap tasks will be made available later so your code can take as long as it needs to complete.


CASE

Language Keywords

CASE

SELECT CASE <Int expression>
CASE <Int Const> , …

<statement>
…
CASE ELSE

<statement>

The SELECT CASE construct allows the choice of one of many actions based on the value of an integer expression.

CASE is used in three distinct places: immediately after the SELECT keyword that introduces the construct; at the start of each numbered action; and at the start of the CASE ELSE, or default, action.


CATCH

Language Keywords

CATCH

CATCH <Int expression> <statement> rarrow Int
CATCH ALL <statement> rarrow Int

The CATCH construct is used to handle errors that occur in the code it ‘contains’, including errors in any procedures called by that code. There are two forms of the construct: catch a particular error, or catch all errors. CATCH returns zero if it completed normally, or the error number if there was an error.

CATCH is similar to long jump in C.

A list of error numbers is given in an Appendix.

The following example shows CATCH being used to trap division by zero.

IF CATCH 6
[

PRINT a / b
]
THEN PRINT “Division by zero!”

THEN was used to make it obvious that CATCH is being used as a condition for IF in this case.

The next example uses CATCH ALL. It also illustrates catching errors in subsequent procedures, and saving the return value from CATCH in a variable for later assessment.

err := CATCH ALL

[

a_procedure_call
]

IF err

PRINT “Error number “, err , “ occurred”,CR

Notes:

CATCH overrides the action on errors set by system.ErrorAction.

CATCH should not be used to intercept errors occurring within a PRINT statement. If you do this then there may be a memory leak.

SeeAlso

See also THROW, OperatingSystem:ErrorAction

BugAlert If you jump out of a CATCH leaving any objects locked that would normally be unlocked by the natural progression of your code then you should take care to unlock these objects to the correct level. This also applies to the case where you jump out of a procedure called by PRINT TO.

See the section on Restored Locking in the Tutorial Guide for hints on how to do this.


CENTRE

Language Keywords

CENTRE

This special print keyword centre-justifies text in objects like the GraphicsLCD:Window.

SeeAlso LEFT, RIGHT, CENTRE.


CHR

Language Keywords

CHR

PRINT ... CHR <Int expression> ...

The CHR print item is used to print 8-bit characters.

The first 128 8-bit characters are often interpreted using the ASCII standard. A table of ASCII values is given in an Appendix.

The second 128 characters (from 128 to 255) are not coved by the ASCII standard, and are likely to be interpreted in widely differing ways by different systems.

LIMIT | The character given must be between 0 and 255.
SeeAlso | See also PRINT


CLS

Language Keywords

CLS

PRINT ... CLS ...

The CLS print item is used to clear the screen of an output device. The text cursor is moved to the home position.

SeeAlso

See also HOME, PRINT


COS

Language Keywords

COS

COS <Float expression> rarrow Float

The COS operator returns the cosine of an angle in radians.

See operator precedence for which operators are evaluated first.

SeeAlso

See also SIN TAN ACOS ASIN ATAN


CR

Language Keywords

CR

PRINT ... CR ...

The CR print item is used to move to a new line on the output device. AsynchronousSerial translates it into characters 13, 10.

SeeAlso

See also PRINT


DECLARE

Language Keywords

DECLARE

DECLARE <name> <name> ...

DECLARE <Int>

DECLARE allows you to catch spelling mistakes and other errors in your program by supplying lists of all the valid global variable names you intend to use in your program.

After a DECLARE statement, any new global variable name that was not declared in a DECLARE list will generate a warning as the code compiles. The only exceptions are the names of procedures, arrays and macros when you are defining them.

Usually DECLARE statements are used at the start of your first (or only) program code file to define all the global variable names used in the project, however you can place them in your project files wherever you need them.

DECLARE statements don't wrap over lines, so you should use DECLARE at the start of each line, e.g.

DECLARE my_variable your_variable

DECLARE xx yy

You can vary the sensitivity of response to undeclared names by using a form of DECLARE that takes an integer parameter, e.g.

DECLARE 0

DECLARE 1

After reset, but before declaring any names, the declare sensitivity is 0. After declaring a list of names the 'declare sensitivity' is set at 1. See the table below for an elaboration of declare sensitivity.

Level

Action on seeing new global name

0

No action (default level)

1

Warning issued on all undeclared global names. This is the level set after declaring a list of names.

All undeclared names are registered and so will not generate another warning, until memory is cleared.

2

Syntax error issued on all undeclared global names.

Undeclared names are not registered and so will generate an error every time they are seen.

3

Strict: As above, but also requires that all names, including procedure, array and macro definitions, must be declared.

Code efficiency

A useful side effect of using DECLARE is that any names declared at the start of an application are allocated in the symbol table first, and the first 256 names produce smaller (and marginally faster) code than the rest of the names.


#DEFINE

Language Keywords

#DEFINE

#DEFINE <name> <text of macro> ;optional comment

#DEFINE is used to define macros.

Macros are pieces of program text that have been given a name. They may be used to define constants, or larger fragments of code.

Examples:

#DEFINE PI 3.14159

#DEFINE clock_present net . Find(160)

#DEFINE Age .Element(5) ;invent new message name

Macro Rules

· Macros should be defined before they are used
· Macros may only be one line long
· Macros may be nested to any level
· Macros may be redefined. The compiler will issue a warning.
· A null macro with no text may be defined.

Listing Macros

Macros may be listed out:

LIST DEFINE ; lists all macros

LIST <name> ; lists out the given macro

LIST WORD ; lists out all symbols by type, including macros.

Current limitations

These are limitations on the current implementation of macros in Venom-SC. These limitations may be removed in later versions.

· Macros can’t take parameters.
· #DEFINE is parsed as a venom statement but can't appear inside a procedure definition.
· A macro name is a global name. This means that if there is a local variable name the same as the macro name, the compiler will see the local variable rather than the macro.


DELETE

Language Keywords

DELETE

DELETE <global name>

The DELETE command is used to set the type of a global variable to 'un-initialised'. If the variable refers to a procedure in RAM, its memory is released. If the variable refers to an object, this will be sent the message ‘Die’ to recover any memory or other resources it held.

LIMIT | The name given must be a global name.
SeeAlso | See also LIST WORD


DIV

Language Keywords

DIV

<Int expression> DIV <Int expression> rarrow Int

The DIV operator divides the first operand by the second, giving the integer part of the result. The operands and the result are always integers. Use ‘/’ if you want a floating point result.

See operator precedence for which operators are evaluated first.

SeeAlso

See also /


DO

Language Keywords

DO

DO <statement> WHILE <Int condition>
DO <statement> UNTIL <Int condition>

The DO construct is used to loop at least once, with the loop condition tested at the end of the loop.

If more than one statement is used within the construct, they must be surrounded by square brackets []:

DO
[ shout("Hoi")
lean_on(gate)
WAIT a_while
] UNTIL the_cows_come_home

The special loop count values INDEX0 and INDEX increment each time round the loop. These values are available in the statement and in the expression.

You may terminate any loop in Venom with the BREAK command.

SeeAlso

See also WHILE, UNTIL


ELSE

Language Keywords

ELSE

IF <Int condition> THEN
  <statement>
ELSE
<statement>

ELSE is part of the IF ... THEN ... ELSE ... construct, which is described in more detail under IF. It is followed by a statement, which is performed if the condition evaluated to the value 0 (zero).

ELSE is also part of the SELECT CASE construct.


END

Language Keywords

END

TO <procedure name>
...
END

~OR~

PROGRAM END

~OR~

ARRAY <array name>(...)
...
END

END is part of the definition of a procedure, described in more detail under TO. It serves to mark the end of the procedure.

It is also used as part of the PROGRAM and ARRAY constructs to mark the end.


EOR

Language Keywords

EOR

<Int expression> EOR <Int expression> rarrow Int

EOR calculates the bit-wise exclusive-or of its two operands.

A bit is set in the result if either of the corresponding bits in the operands are set. EOR is often used to flip one or more bits while leaving the rest alone. For example:

PRINT ~~%101010 EOR %001100
100110

Internally, what happened was this:

EOR

00000000 00000000 00101010
00000000 00000000 00001100
00000000 00000000 00100110

See operator precedence for which operators are evaluated first.

SeeAlso

See also AND, OR, NOT, TRUE, FALSE


EVERY

Language Keywords

EVERY

EVERY <Int expression> <statement>

The EVERY command is used to repeat code at regular intervals. The period is specified in milliseconds.

The special loop count values INDEX0 and INDEX increment each time round the loop. These values are only available in the statement.

You may terminate any loop in Venom with the BREAK command.

If the statement takes longer to execute than the specified interval, EVERY will not attempt to regain the lost time.

¹ | As soon as the statement has been executed, the EVERY command swaps tasks to allow other tasks to run. If there are no other tasks ready to run, the processor core is put to sleep to save power.
SeeAlso | See also FOREVER, WAIT


EXIT

Language Keywords

EXIT

EXIT <Region name>

The EXIT command is used as part of the REGION construct to jump out of control structures and procedure calls back to a known place when something unexpected happens. Control returns to the end of the last REGION of the given name that was entered, and the REGION statement returns TRUE to indicate that EXIT was used.

[Region and EXIT are similar to long jump in C]

Note: EXIT should not be used in a function called by PRINT to break out of a PRINT statement. The memory used to build the print job will not be returned properly.

SeeAlso

See also RETURN, CATCH.


EXP

Language Keywords

EXP

EXP <Float expresssion>

The EXP function returns the value of ‘e’ raised to the power of an expression.

SeeAlso

See also LOG


FALSE

Language Keywords

FALSE

FALSE rarrow Int

FALSE is a convenient constant exactly equivalent to integer zero.

SeeAlso

See also AND, OR, EOR, NOT, TRUE


FILL

Language Keywords

FILL

[Reserved keyword]


FLOAT

Language Keywords

FLOAT

<Int expression> AS FLOAT rarrow Float

FLOAT is used as part of the AS FLOAT operator to convert the given value to floating point. See AS for more information.


FONT

Language Keywords

FONT

PRINT … FONT <Int expression> …

The FONT print item is used to set the character font of text on the device printed to.

SeeAlso

See also PRINT TO GraphicsLCD:Window


FOREVER

Language Keywords

FOREVER

FOREVER <statement>

The FOREVER command is used to repeat the following statement indefinitely.

The special loop count values INDEX0 and INDEX increment each time round the loop. These values are only available in the statement.

You may terminate any loop in Venom with the BREAK command.

SeeAlso

See also EVERY


GOTOXY

Language Keywords

GOTOXY

PRINT … GOTOXY (<parameter list>) …

The GOTOXY print item is used to move the cursor to a particular location on the screen on the output device.

PRINT TO glcd , GOTOXY (10 , 40)

SeeAlso

See also AlphaLCD, GraphicsLCD.


HELP

Language Keywords

HELP

HELP <anything>

HELP followed by a global variable tells you something about what that variable contains. This is particularly useful for objects.

HELP followed by an unrecognised word will tell you it is an undefined variable or a spelling mistake.

HELP followed by anything else tells you what kind of keyword or symbol it is. This is a useful way to check whether a word you want to use is a Venom keyword.

SeeAlso See also PRINT, LIST


HOME

Language Keywords

HOME

PRINT HOME

The HOME print item is used to set the cursor position to the top left on the output device.

SeeAlso

See also PRINT


IF

Language Keywords

IF

IF <Int condition> THEN
<statement>
ELSE
<statement>

The IF ... THEN ... ELSE ... construct is used to conditionally execute a statement, or to choose between two statements, on the basis of the condition.

If the condition is not FALSE (ie. TRUE or any non-zero integer), the first statement is executed. If the condition is FALSE, the statement after the ELSE is executed.

The ELSE portion is optional.

For example:

TO count10
REPEAT 10
[

IF INDEX=5

PRINT " Five"
ELSE

PRINT INDEX
]
END
-->count10
1 2 3 4 Five 6 7 8 9 10

The keyword THEN is optional and only used when code clarity would be improved.

ELSE association

Note that if you have nested IF constructs then any ELSE statement will be associated with the last IF. The example below won’t work in the way the indentation seems to imply:

IF temperature < 23.5

IF switch.Asserted

heater. On

ELSE

heater. Off

To make it work you need brackets [ ], used like this:

IF temperature < 23.5

[

IF switch.Asserted

heater. On

]

ELSE

heater. Off

SeeAlso | See also SELECT CASE
BugAlert | Beware that all non-zero values are taken by the IF construct as meaning TRUE, but that it is possible for AND to return FALSE even when both its operands taken separately would be treated as TRUE.


INDEX and INDEX0

Language Keywords

INDEX and INDEX0

INDEX rarrow Int
INDEX0 rarrow Int

INDEX and INDEX0 count the number of times round the current FOREVER, EVERY, DO, WHILE or REPEAT loop. INDEX counts from 1, and INDEX0 counts from 0.

Only the INDEX of the most recently entered loop is available, so if you have nested loops and need the outer INDEX, you need to store it in a variable. The following example demonstrates this, and prints a times-table:

TO times_table_up_to(max)
LOCAL outer_index
REPEAT max
[ outer_index := INDEX
REPEAT max
[ PRINT outer_index:1," times ",INDEX:1," is ",outer_index*INDEX:1,CR
]
]
END
-->times_table_up_to(10)
1 times 1 is 1
1 times 2 is 2
1 times 3 is 3
...
2 times 1 is 2
2 times 2 is 4
...
10 times 9 is 90
10 times 10 is 100

LIMIT

INDEX counts up to the maximum integer, $7FFFFFFF. It then wraps round to the minimum integer, $80000000, and continues back up through zero again. For a loop being executed 50 times a second, the wrap-round will occur after just under a year.

Hence if you use INDEX in extremely long-term loops, you should ensure that you allow for the case where it becomes extremely large. Using AND to create a lower-range INDEX which repeats itself is one way of doing this.


INT

Language Keywords

INT

<Float expression> AS INT rarrow Int

INT is used as part of the AS INT operator to convert the given value to an integer. See AS for more information.

SeeAlso

See also AS


LEFT

Language Keywords

LEFT

This special print keyword left-justifies text in objects like the GraphicsLCD:Window.

SeeAlso RIGHT, CENTRE.


LIST

Language Keywords

LIST

LIST <procedure name>
LIST ALL
LIST WORD
LIST TASK
LIST DEFINE

In the interpreted predecessors to Venom-SC, LIST was used to list back the source code of procedures. Listing back of source is not available in the compiled version, so instead LIST lists out a summary of the procedure:

-->TO proc (a,b)

02> LOCAL c,d,e

03> PRINT a + b, CR

04>END

Procedure Defined

-->LIST proc

;TO proc(a,b)

; LOCAL c,d,e

; No source list [32 bytes @$2600DC]

;END

-->

The one exception to this is LIST startup, which will list the source of Venom-SC’s default startup procedure. If you have written your own startup, then its source will not be listed.

LIST ALL lists all the procedures in the machine in the same format as LIST for a single procedure.

The LIST WORD, TASK and DEFINE commands are described under TASK, WORD, and DEFINE respectively.

SeeAlso

See also WORD, TASK, DEFINE


LOCAL

Language Keywords

LOCAL

LOCAL <Local name>, <Local name>, …

LOCAL <Local name> := <Any expression>, …

LOCAL declares one or more local variables for a procedure. These are variables that can only be used within the procedure, and which are created each time the procedure is called.

Giving procedures their own local variables makes a program more reliable because you can be sure that another part of the program can't change the value of the variables by mistake.

If a procedure is recursive, or more than one task is using it, each instance of the procedure call has its own copy of the local variables.

All LOCAL definitions must appear before any other statements in the procedure. They may be separated with commas, or with the keyword LOCAL.

Local variables may be initialised with := when they are defined. You can use any expression, including previously defined local values. Un-initialised local variables currently default to the value integer zero.

TO proc

LOCAL val := 1.0 , val2 := 1.1

LOCAL loc_obj := NEW Digital(128)

LOCAL val2 ; not initialised

…

END

Autodestruction

If you are using local variables to hold temporary objects then you can use the AUTODESTRUCT keyword to indicate that the objects should be automatically destroyed when the procedure ends.

LIMIT | The maximum total number of locals and parameters a procedure can have is 253.
TimingIcon | Having local variables makes the procedure marginally slower to call, but they are marginally faster to access than global variables.


LOG

Language Keywords

LOG

LOG <Float expresssion>

The LOG function returns the natural logarithm (or Loge) of an expression.

SeeAlso

See also EXP, Power of ^


MAKE

Language Keywords

MAKE

MAKE <global name> <Object Class> (<parameter list>)

The MAKE command is used to create an object of the given type, and put it in a global variable. The parameters passed to MAKE for each object type are listed in the Object Types section.

As an example, the following statement creates a Digital object called motor_power, on digital channel 128:

MAKE motor_power Digital(128)

Conventionally, MAKE is used to create permanent objects. I.e. the application never needs to kill them with Die. Where possible it’s a good idea to put all your MAKE statements in the init procedure, which is normally called by startup shortly after power-on.

On the other hand, temporary objects (which may be created and deleted while the application runs) are created with the NEW function. There is not much difference between MAKE and NEW. Mainly their use should be used to indicate the way the object is to be treated. As an aid to thinking about the status of objects that are created, MAKE will not work with LOCAL variables.


MOD

Language Keywords

MOD

<Int expression> MOD <Int expression> rarrow Int

The MOD operator divides the first operand by the second, and gives the value of the remainder. MOD can only work with integers.

MOD is often used to make numbers 'wrap round'.

If either operand is negative the sign of the result is implementation-dependant, but the following expression will always be true for all integer values of a and b.

a = a MOD b + a DIV b * b

The following example shows a simple pseudo-random number generator that uses MOD to stop the calculated number becoming too large and causing an integer overflow. The result of the random number generator is then used to calculate a dice throw from 1 to 6.

;sets the seed from the clock
;the MOD prevents overflow later
TO set_random_number_seed
seed := clock . Time MOD 259200
END

;Calculate next seed value with algorithm and constants
; taken from Numerical Recipes in C (Press et. al.) Ch. 7
;Randomness subject to warnings contained therein!
TO large_random_number
seed := ( seed * 7141 + 54773 ) MOD 259200
RETURN seed
END

;Give a number from 1 to 6. We don’t use MOD here

; because the bottom bits of the number are not random.
TO dice_throw
RETURN (6 * large_random_number) DIV 259200 + 1
END
-->set_random_number_seed
-->EVERY 500 PRINT dice_throw
3 6 4 2 5 3 5 2 4 1 1 2 2
1 5 3 4 5 5 3 6 2 1 6 2 2
1 4 4 3 5 5 3 4 2 4 3 5 5 ...

See operator precedence for which operators are evaluated first.

TimingIcon

If you want to MOD with a power of two, using AND is faster:

x MOD 2N = x AND (2N - 1)

eg. for x MOD 16 use x AND 15.


NEW

Language Keywords

NEW

NEW <Object Class> (<param list>)  rarrow  Any

The NEW function is used to create an object of the given type and parameters. The parameters taken by individual object types are given under Creation for each object type in the Object Types section.

As an example, the following function creats a temporary DateTime, which is then set to the current time:

TO now

AUTODESTRUCT
LOCAL dt := NEW DateTime

dt := clock.Time

…
END

NEW is used when creating temporary objects held in local variables, rather than setting up permanent objects at the beginning of an application (when MAKE is used)

Garbage collection

If you don’t kill temporary objects, they may accumulate in memory and eventually crash your application. To prevent this you can use the AUTODESTRUCT mechanism to kill them automatically when the procedure ends.

If you don’t use AUTODESTRUCT then you have to keep track of temporary objects explicitly, sending them the Die message at each point your procedure might exit.


NIL

Language Keywords

NIL

NIL rarrow Nil

NIL is a special object that is used as a placeholder for any other type of object, or to represent ‘no object’.

NIL will accept any message, and will return FALSE to all of them.

It is useful for situations where, in the normal course of events, an object is used but sometimes you wish to allow for situations where ‘no object’ needs to be represented.

The most common example of this is substituting the value NIL for an output stream object when you want PRINT output to be discarded:

lcd := NIL ;all PRINT TO lcd will now be discarded.

Testing for NIL is done with = and <>, as follows:

IF lcd = NIL

[

 …

]


NOP

Language Keywords

NOP

NOP

The NOP statement introduces a no-operation bytecode into the compiled Venom code. This can sometimes be useful to introduce more embedded source-line numbers into some code, or to change its timing slightly.


NOT

Language Keywords

NOT

NOT <Int expression> rarrow Int

The NOT operator gives the Boolean complement of its operand. Each bit in the operand is ‘flipped’ to give the result. Because of the two's complement integer number system used by Venom, the following equation is always true:

NOT x = - ( x + 1 )

NOT is often used to negate a condition before testing it with IF or similar constructs:

IF NOT its_a_bull
attach_milking_machine

BugAlert | Note: because NOT simply inverts all the bits in its operand, IF NOT and WHILE NOT, etc, may not work as you might expect for values that are neither TRUE (-1) nor FALSE (0).
SeeAlso | See also AND, OR, EOR, TRUE, FALSE, operator precedence


OR

Language Keywords

OR

<Int expression> OR <Int expression> rarrow Int

The OR operator is used in what appear to be two different contexts, though on examination its operation in each is the same. It is often used as part of an IF construct to make a more complex condition where OR will return TRUE if either or both of its parameters are TRUE. For example:

IF cows_home OR testing_machine

machine . On

In fact OR returns the bit-wise OR of its two parameters, and the above is just a simple case of this.

A bit is set in the result if either of the corresponding bits in the operands are set. OR is often used to set one or more bits while leaving the rest alone. For example:

PRINT ~~%101010 OR %001100
101110

Internally, what happened was this:

OR

00000000 00000000 00101010
00000000 00000000 00001100
00000000 00000000 00101110

See operator precedence for which operators are evaluated first.

SeeAlso

See also AND, EOR, NOT, TRUE, FALSE


PRINT

Language Keywords

PRINT

PRINT <print item> , …
PRINT TO <Object> , <print item> , …

The PRINT command is used to send textual output to an output stream or device.

When used without the TO, the output is sent to the default output, which is usually the terminal. For example:

-->PRINT "Hello world"
Hello world

When used with TO, the output can be sent to any object, for example:

PRINT TO printer, "Data readings"

PRINT will print the contents of any variable, including objects.

See the colon operator : for setting different print formats.

Each object responds to being printed in it’s own way. Objects also respond to colon formatting values.

-->PRINT clock , " ",clock: 4

14-Feb-02 11:37:19 11:37:19 am-->

PRINT has a set of keywords for special actions. Not all of these are understood by every output device.

PRINT keyword | Action
CLS | Clear Screen
HOME | Go to the Home position
CR | Carriage Return
LF | Line Feed
GOTOXY | Go to a position
FONT | Set the font style
LEFT | Justify to the left
RIGHT | Justify to the right
CENTRE | Justify to the middle
JUSTIFIED | Justify to the margins

.

LockIcon

PRINT will always lock the output device while printing is in progress.

SeeAlso

See Also the colon format operator :


PROGRAM

Language Keywords

PROGRAM

PROGRAM "<filename>" Int line_number Int checksum Int flags
... procedures ...
PROGRAM END

Old syntax for this command is still supported and is listed here.

The PROGRAM construct is used when downloading Venom-SC source code files to the controller. PROGRAM is usually generated by the VenomIDE development toolset so you are not likely to need to use it directly.

When downloading program source text within the PROGRAM construct, echoed characters and prompts are turned off – instead a summary of each procedure is printed. Errors are reported as they occur, and are summed up at the end.

Pressing CTRL-C will escape from the PROGRAM construct.

Parameters

During the download process, the filename is associated with every procedure between the PROGRAM statements, to allow errors to be located in the source code files. The filename is supplied as a string constant

The optional line_number parameter gives the line within the file of the PROGRAM statement. If line number is not present the value used internally defaults to 1 to allow the PROGRAM command to be used explicitly within a text file (when you are not using VenomIDE).

The optional checksum parameter gives the checksum of all the characters sent between the PROGRAM ... and PROGRAM END statements. This is later used by Venom to check the integrity of the code that has been downloaded. If the checksum matches with the sum of the actual characters sent then 'Checksum OK' is reported at the end of the download. This parameter only likely to be used by VenomIDE.

The optional flags parameter is for fine tuning of the download process from VenomIDE. The flags are sent as binary bits set in an integer value. The bit values are:

1: Don't Echo Procedure Names

This is useful for large projects where you don't want to see every procedure name that is defined, as the large amount of text might hide syntax errors, etc.

2: Remove all procedures that were in this file before defining new ones

This removes any procedure that was downloaded from this file the last time you did a download. It helps to keep the code in the VM-1 consistent with your project, and save on VM-1 memory.

4: Don't report Error Count, End of File, or Checksum OK if no problems encountered

This will only report End of File, or any problems with the download, if any have occurred. This is useful if you have a project with lots of files.

PROGRAM: Old syntax

PROGRAM START
PROGRAM END

This is the old syntax for PROGRAM. You might need to use it if you don't have access to VenomIDE, but need to download code using a simple terminal emulator. Put these commands at the beginning and end of each Venom code file to suppress echoing back of the code as it is downloaded.


REGION

Language Keywords

REGION

REGION <global name> <statement> rarrow Int

The REGION construct is used to create an area of the program that can later be ‘jumped out of’ with EXIT. You may EXIT a REGION even from procedures many calls deep. This facility is used to deal with exceptions.

If the region is EXITed, control continues just after the REGION construct, and the REGION construct returns TRUE. If the region finished naturally, the REGION construct returns FALSE.

The global name is used to identify which REGION to exit. You can use the same name many times for different regions, even using the same name in nested regions or in REGIONS in different tasks. When EXIT is called, the first REGION encountered with the correct name is EXITed.

You can nest REGIONs as many times as you like.

Here is an example that illustrates EXITing a REGION from within a procedure called within the REGION.

TO test_region

result := REGION reg

[

try_something

something_else

]

next_statement ;After EXIT is called, we end up here

; and we can test result if necessary.

...

END

TO try_something

IF exception

EXIT reg ;Jump out of the REGION.

...

END

BugAlert If you EXIT from a REGION leaving any objects locked that would normally be unlocked by the natural progression of your code then you should take care to unlock these objects to the correct level. This also applies to the case where you jump out of a procedure called by PRINT TO, which implicitly locks the output stream object.

See the section on Restored Locking in the Tutorial Guide for hints on how to do this.


REPEAT

Language Keywords

REPEAT

REPEAT <Int count> <statement>

REPEAT executes a statement a pre-determined number of times.

The count expression is evaluated only once, at the start of the loop.

If the count is less than 1, the statement is not executed at all.

The system variables INDEX and INDEX0 count the loop iterations.

The following example shows REPEAT being used to print a line of stars of a given length:

TO stars(n)
REPEAT n

[

PRINT "*"
]
END

-->stars(10)
**********-->

LIMIT | The maximum value of count is $7FFFFFFF, the maximum positive integer.
SeeAlso | See also BREAK


RETURN

Language Keywords

RETURN

RETURN <Any>

The RETURN statement is used to return a value from a procedure. The procedure is exited immediately.

In the following example, RETURN is used to make a function that cubes its parameter:

TO cube(x)
RETURN x*x*x
END
-->PRINT cube(4),CR
64
-->PRINT cube(4.6415888)
100.0

RETURN can also be used to leave a procedure early, even if the procedure doesn’t normally return a result. You can just use a dummy return value, like integer zero.

TO proc

IF leave_early

RETURN 0

carry_on_processing

END

LIMIT | The value returned may be of any type - including any numerical value or object type.
SeeAlso | TO, END
BugAlert | Beware of returning pointers to local variables. See @ for more details on this.


RIGHT

Language Keywords

RIGHT

This special print keyword right-justifies text in objects like the GraphicsLCD.

SeeAlso LEFT, CENTRE.


SELECT

Language Keywords

SELECT

SELECT CASE <Int>
CASE <Int Const> , ...
<statement>
...
CASE ELSE
<statement>

The SELECT CASE construct allows the choice of one of many actions based on the value of an integer expression.

Each case in the construct is labelled with one or more integer constant values, and has one statement to execute. If the value of the expression matches one of the case values then the statement is executed. If it matches none of the cases, then the ELSE case statement is executed. The ELSE case is optional and may appear anywhere in the list of cases.

TO test_select(n)
SELECT CASE n
CASE 1,2
[
PRINT "it was 1 or 2"
]
CASE 3
[
PRINT "it was 3"
]
CASE 200
[
PRINT "it was 200"
]
CASE ELSE
[
PRINT "it was none of them!"
]
END

There is no check for duplication of the case values; matches are tested from the top down.

Note: You may nest SELECT constructs, but watch out: the case statements may get associated with the wrong SELECT statement unless you use square brackets [], just as in IF/ELSE.

TimingIcon | The first cases are the fastest to check, but it’s only ~3.5 μS per case (measured on the VM-1 with a 16MHz clock). The ELSE case is always reached after checking every other case, no matter where it appears in the list of cases.
LIMIT | Currently the case constants must be expressions that evaluate to a constant in the range -32768 to 32767.


SIN

Language Keywords

SIN

SIN <Float> rarrow Float

The SIN operator returns the sine of an angle in radians.

See operator precedence for which operators are evaluated first.

SeeAlso

See also COS TAN ACOS ASIN ATAN


SQRT

Language Keywords

SQRT

SQRT <Float> rarrow Float

The SQRT function returns the square root of an expression.


START

Language Keywords

START

START <statement>  rarrow  Task

The START command creates a new task. START returns immediately, returning a Task object as its result.

The statement is run as an independent task in parallel with all other tasks.

The Task object returned by START may be used to control the task, or request information about it.

Keep tasks simple

It is good practice to write applications where START's statement is simply a procedure call, rather than a more complicated block of statements:

START monitor_procedure

Separate context

The code being run as a task by START has a different context to that of the code of any procedure around it. This means you can't use local variables from a procedure within the START statement. For example, the following is illegal:

TO my_proc

LOCAL loc_var := 0

START another_proc(loc_var) ; Use of local variable in wrong context!

END

This also applies to the loops: even if START appears inside a loop, the statement to start isn't in the loop context. This means you can't use INDEX and INDEX0 from the procedure's loop in the START code. You can use INDEX for a loop within the START code, however.

Thus the first is legal but the second isn't:

TO my_proc

START EVERY 1000 PRINT INDEX,CR

END

TO my_proc

REPEAT 4

START web_server(INDEX0) ; Use of INDEX outside of a loop!

END

[To achieve what the code above is trying to do you will need to use a global variable to provide the index, and check each task has taken the value before starting the next one]

Listing tasks

You can use LIST TASK to get a list of all the tasks currently running.

If you don't have a command line because code is running, then you can hit CTRL-T to get the same effect (so long as Serial.Escape is not disabled).

memoryUse | Currently a task will take four blocks of memory. One is for the copy of the task’s code. One is for the task object (~100 Bytes) and two are for the task’s Venom stack (1600 bytes) and processor stack (1000 bytes).
LIMIT | There is no limit other than memory to the number of tasks you may use. However, if your application needs to use more than four or so, you should consider re-writing it.
TimingIcon | Each task is given slots of around 1mS (2mS max), in a round-robin cycle. Hence the more tasks there are, the less often any one of them gets a slot. If the task is waiting for something, such as in AWAIT, reading a character or locking an object, it will swap out to the next task as soon as it realises it has to wait, and will not take the full slot time. Any task that is waiting on a timing event or an interrupt will cause the processor to sleep to save power if possible.
SeeAlso | See also STOP


STOP

Language Keywords

STOP

STOP <Task expression>
STOP <Int expression>
STOP ALL

The STOP command is used to completely stop a task. The Task object or the task ID number may be used to identify which task to stop.

The task ID number is a unique 32-bit number assigned to each task when it is created. LIST TASK will list all the tasks together with their task ID numbers.

The command line task (Task ID 0) cannot be stopped.

STOP ALL will stop all tasks except the command line task. If you type CTRL-C at an empty command line, then STOP ALL will be applied to any tasks running.

STOP is most often useful when debugging from the command line.

BugAlert | When a task is stopped with STOP, it is terminated immediately. It is likely to leave objects that it had locked in the locked state, which may cause a runtime error if another task tries to lock any of them. For this reason, STOP is not generally recommended for use within an application. It is cleaner to use tasks that never stop, or that stop by coming to the end of their code. See here for how to prevent the associated runtime error, if you need to.
SeeAlso | See also START, LIST TASK


SWAP

Language Keywords

SWAP

SWAP

SWAP will cause an immediate task swap. If there are no other tasks ready to run then SWAP will allow the processor core to sleep: some processors have a SLEEP instruction that puts the processor core into a low power state. Interrupts are handled normally by waking the core.

SWAP is not often needed as using a language construct that waits (which implies task swapping) is often a better solution.

Constructs such as WAIT, AWAIT, EVERY, and many messages to objects, such as Keypad.Get will swap tasks if they cannot return immediately.

SeeAlso

See also WAIT, AWAIT, EVERY


TAN

Language Keywords

TAN

TAN <Float expression> rarrow Float

The TAN operator returns the tangent of an angle in radians.

See operator precedence for which operators are evaluated first.

SeeAlso

See also COS SIN ACOS ASIN ATAN


TASK

Language Keywords

TASK

LIST TASK

LIST TASK lists out all tasks running.

TASK 0:

in proc_a (line 2)

in main (line 4)

in startup (line 13)

in the command line.

[During bytecode 'BRA' at $260442]

___________________

TASK 1:

in proc_b (line 2)

in a task started from main (line 2).

[During bytecode 'BRA' at $2603FE]

___________________

TASK 2:

in serial.Get

in proc_c (between lines 1 & 2)

in a task started from main (line 3).

[During bytecode 'MSG' at $26041C]

___________________

You can also type CTRL-T to show all the tasks even when the command line task is busy. CTRL-T is enabled and disabled using serial.Escape, along with the CTRL-C Break function.

SeeAlso

See also LIST, START


THEN

Language Keywords

THEN

IF <Int condition> THEN
<statement>
ELSE
<statement>

THEN is used as an optional part of the IF construct to separate the condition and the first statement. For a simple condition, this isn't always necessary, but it is useful when the condition looks like a statement in its own right. This is often the case when CATCH or REGION is used:

TO run_machine
IF CATCH_ALL
[
do_the_works
]
THEN
[
PRINT "Something awful happened"
emergency_action
]
END


THROW

Language Keywords

THROW

THROW <Int expression>

The THROW command is used to simulate an error in the program.

THROW may be used to test error-trapping with CATCH, or as a way for your application to generate an error.

As an example, the following procedure complains if it is given anything out of the range 0 to 9:

TO read_input(x)
IF x<0 OR x>9 THROW 3 ;range error
RETURN inputs.Element(x).value
END


TO

Language Keywords

TO

The keyword TO is used to define procedures and also to direct print output.

Procedures

TO <global name> (<local name> , …)
<Local list>
<statement>
…
END

<Local list> is as list of the following:

LOCAL <local name> := <expression> , …

A procedure is a named sequence of Venom statements.

Procedures may declare local variables. Locals must be declared before any executable statement. Locals may be initialised to any value using :=.

Procedures may take parameters. The names of any parameters are specified in parentheses after the procedure name. Parameters behave just like local variables, but they are initialised by the code that calls the procedure.

Local variables and parameters will eclipse any global variable with the same name - i.e. the global with the same name is invisible inside the procedure.

The RETURN statement can be used within the procedure to make it return a result.

The following example shows a procedure that gives the x to-the-power y (y positive) and shows how it is called:

TO power(x, y)
LOCAL result := 1
REPEAT y
result:=result*x
RETURN result
END
-->PRINT power(10,3) ,CR
1000
-->PRINT power(2,16) ,CR
65536

There are many other examples of procedures throughout this document.

PRINT direction

PRINT TO <Object>, <print item> , …

TO is used as part of the PRINT command to send the output to a different device than the default.

PRINT TO buff, “put this text in a buffer”

LIMIT | The maximum number of parameters and local variables combined is 253.
SeeAlso | Print redirection


TRUE

Language Keywords

TRUE

TRUE rarrow Int

TRUE is a constant that represents -1.

This is ‘all 1s’ in binary.

BugAlert | Please note that IF, WHILE, DO...UNTIL, AWAIT etc all treat any non-zero value as ‘true’. However AND, and NOT work on each individual bit of their operands. Thus the expression 1 AND 2 will evaluate to ‘false’, even though both 1 and 2 are ‘true’ as seen by IF, etc.
SeeAlso | See also AND, OR, EOR, NOT, FALSE


TYPEOF

Language Keywords

TYPEOF

TYPEOF <expression> rarrow Int

The TYPEOF operator returns an integer representing the type of the result of the expression, i.e. whether the expression is an integer, floating point number, string, pointer, object, etc. In general you don’t need to know what these values are – you can just compare them as below:

TO procedure (parameter)

IF TYPEOF parameter = TYPEOF 0 ; is it an integer parameter?

[

;process the integer

]

END

Object types

As expected, the type numbers returned for objects are different for each object type. However, you may be surprised to find that two objects that may appear to be of the same type will actually have different type numbers. Examples of this are Digital channels on the I2C Bus compared to Digital channels on the controller’s on-board I/O ports.

If you want to test whether an expression is an object, then you can use TYPEOF NIL. The NIL object will always have a type value smaller than any object’s type, but larger than any other type.

IF TYPEOF thing >= TYPEOF NIL ; is it an object of some kind?

[

]

Constant folding

When it can, the compiler will optimise TYPEOF expressions into a simple integer. Currently this applies to

TYPEOF <integer constant>

TYPEOF <float constant>

TYPEOF <string constant>

TYPEOF NIL

Thus, TYPEOF <constant> may be used as the CASE of a SELECT CASE construct:

TO procedure (parameter)

SELECT CASE TYPEOF parameter

CASE TYPEOF 1 ; Deal with integers

[

]

CASE TYPEOF 1.0 ; Deal with floats

[

]

CASE TYPEOF “” ; Deal with strings

[

]

CASE ELSE ; Deal with other types…

[

]

END

Other types

There are two non-object types that are visible to the Venom-SC user but haven’t been mentioned. These are the types associated with REGION and pointer.

There are also types that are not visible to the Venom-SC user, as they get trapped or converted before TYPEOF can get hold of them (e.g. procedures, macros, undefined variables), or because they will never be put in a venom variable.

SeeAlso

See also AS


UNTIL

Language Keywords

UNTIL

UNTIL <Int condition> <statement>

UNTIL is like the inverse of WHILE. It will continue looping while the condition is false.

UNTIL also is part of the DO ... UNTIL ... construct, described in more detail under DO.

SeeAlso

See also BREAK

BugAlert

Beware that all non-zero values are taken by the UNTIL construct as meaning TRUE, but that it is possible for AND to return FALSE even when both its operands taken separately would be treated as TRUE.


WAIT

Language Keywords

WAIT

WAIT <Int expression>

The WAIT command is used to wait for a given number of milliseconds. This is used to build in delays between actions. For example, the following piece of code runs a motor for one second:

TO one_second_run
motor.On
WAIT 1000
motor.Off
END

If you need to make something execute something at regular intervals, use EVERY.

Timing over long periods can be done with Stopwatch, Timer and RealTimeClock objects.

LIMIT | The minimum time usefully used by WAIT is 1 millisecond. The maximum time is $7FFFFFFF milliseconds, or about 25 days.
TimingIcon | While waiting for the time to elapse, the task manager will process other tasks. If there are no tasks that can proceed the task manager will send the processor to sleep to save power. WAIT has a resolution of 1mS. WAIT 1 will wait for between 0 and 1 mS.


WORD

Language Keywords

WORD

LIST WORD

LIST WORD gives a list of all the global names seen by Venom, under headings giving what they are being used for. The following example shows the user names just after memory has been cleared:

Procedures:

startup init main

Integers:

Floats:

Strings:

Pointers:

Regions:

Objects (inc. 'Nil'):

system serial net led clock s

Undefined:

The last category, unused, contains names which have been deleted, or which have been seen by Venom-SC but never assigned a value. Unprintable words typed in moments of frustration also turn up here, so beware! Clearing the memory will get rid of these.

SeeAlso

See also LIST


WHILE

Language Keywords

WHILE

WHILE <Int expression> <statement>

The WHILE construct executes the statement while the value of the condition expression remains non-zero. If the condition is zero to start with, the statement is never executed. For a loop that executes at least once, see DO.

In this example, the condition is index0 < 10 and the statement is PRINT index0.

-->WHILE index0 < 10 PRINT index0

0 1 2 3 4 5 6 7 8 9-->

Normally when you use WHILE you would indent the code in the statement, and the statement might well be a block delimited by [].

WHILE x <> 15

[

process(x)

deal_with(x)

]

Within the loop, INDEX0 and INDEX count from 0 and 1 respectively, incrementing each time round the loop.

SeeAlso | See also UNTIL, DO, BREAK
BugAlert | Beware that all non-zero values are taken by the WHILE construct as meaning TRUE, but that it is possible for AND to return FALSE even when both its operands taken separately would be treated as TRUE.


Object Types

Most of the work in a typical Venom application is done by Objects. Objects come in many different types. Different types of object respond to different messages to perform many different functions.

How to use the Object Types section

This section of the manual contains detailed information on every object type currently in Venom-SC for the VM-1. It does not contain any hardware information; for this you should see the datasheet for your controller.

If you are new to Venom-SC you are advised to familiarise yourself using the Tutorial Guide - this help file is designed for quick reference to enable you to find the exact syntax or function of a particular object type or message.

Each object type section has a header that gives a short description of the type and a summary of the messages available. Some object types have sub-objects - e.g. ‘Keypad.InputBuffer'.

After the header for each object type the messages are given in alphabetical order. The exceptions are Creation, which is always shown first - giving information on creating the object – and standard ‘system’ messages such as Printing, Accepting Print, and Die, which are put at the end.

Some messages do very similar things in many objects, or are always accepted because they are used internally by the system and must never give an error. These are only documented separately if they do something out of the ordinary. These ‘generic’ messages are, Lock, Unlock, TestLock, Owner, and Die. They are documented in general in the next section.

Each message has a syntax description, details of what the message does and sometimes some code examples. Following this there may be some paragraphs with icons indicating other information relevant to the object:

LIMIT | Denotes information on any limits to the parameters or results of the message, or the number objects of this type that can be created.
Hardware | Denotes information on the hardware needed to use this type or message.
memoryUse | Denotes information on the memory usage of the message, or the memory used when the object is created.
TimingIcon | Denotes information on timing aspects of the message.
SeeAlso | Denotes pointers to other parts of the manual for related topics.
LockIcon | Denotes information about if and when the object should be locked.
BugAlert | This warns you to beware of putting bugs in your code

Syntax descriptions

Each message has a syntax description, including the data types of parameters and results. In order to be precise, some of these are quite complex. To quickly jog your memory it may be easier to look at one of the code examples. The format of the syntax description definitions is as follows:

obj . Message (data_type item , …) rarrow data_type

bold is used for message names and user-defined names. (Data types are shown in plain text.)

Text in <angle brackets> indicates a reference to a ‘lower level’ construct, e.g.:

<print list> means any valid Venom print list.

italics denote optional parts of a message.

The data types of parameters and return results are given in 'light' text, e.g. Int.

rarrow indicates that the message returns a result.

lrarrow indicates that the message may be used to either set or read a value, i.e. it is an active variable.


Generic messages

Object Types

Generic messages

There is a set of generic messages that are accepted by all objects:

Lock

Unlock

TestLock

Owner

Die

Though every object must accept these messages, some objects may not do much in response.

For a description of how to use locking please see the Venom-SC Tutorial Guide.

The following paragraphs describe the messages and their return results and parameters.

Lock

Obj . Lock lrarrow Int

In general, calling lock will lock an object so no other task can use it.

Specifically, calling Lock will attempt to lock the object for exclusive use by the current task:

· If the object is not locked by any task then the current task claims it, and the lock level is set to 1.
· If the object is already locked by the current task then the lock level is incremented.
· If the object is already locked by another task then the current task has to wait until the object is fully unlocked by the task that holds it.

When Lock finally succeeds, it will return a value that may be useful later: the original lock level, i.e. the number of times the object had been locked originally. This is zero if the object had not been locked at all.

If an object has no lock then Lock will return zero always.

You can also call Lock by assigning a value to it. This used in the Restored Locking scheme described in the Tutorial. Basically, the lock level is set to the assigned value. If the value is zero, then the object is completely unlocked.

If an object has no lock then assigning a value to Lock will do nothing.

Unlock

Obj . Unlock

Unlock will reduce the lock level by 1, assuming the object was ‘owned’ by the current task. If the lock level is zero then the object not locked anymore. Further calls to Unlock are simply ignored.

If an object has no lock then Unlock will be accepted but do nothing.

TestLock

Obj . TestLock rarrow Int

TestLock is rather like Lock, except that it won’t wait if it can’t lock an object immediately. Instead it just returns a zero result to indicate failure.

If it succeeds in locking the object then it returns the resultant lock level. Note: this is one more than Lock would have returned.

If an object has no lock then TestLock will return the value 1 (one) always.

Owner

Obj . Owner rarrow TaskObject OR NIL

Owner will return an object that represents the task that owns the locked object, or NIL if the object is not locked.

If an object has no lock then Owner will return the value NIL always.

Die

Obj . Die

Die will remove an object from memory, and will generally attempt to clean up any resources the object may have used. Sending the Die message to an already dead object will not result in the usual runtime error.


Common object properties

Object Types

Common object properties

This page lists some general properties that are common to some or all objects.

Zero-Memory objects

Many objects don't take up any memory, or other resources, when they are created. An example of this is the Digital object. When a Digital is created with MAKE or NEW, an object handle is returned, which is simply a value. You can create an unlimited number of zero-memory objects without using any memory in the controller. Sometimes it is a useful convenience to do this, for example:

TO set_a_channel(chan, state)

NEW Digital (chan) . Asserted := state

END

SeeAlso By way of comparison, also see AUTODESTRUCT, which is useful for cleaning up objects that do use memory. It is safe to use AUTODESTRUCT for any object.


AlphaLCD

Object Types

AlphaLCD

The AlphaLCD type is used to drive alphanumeric LCD displays made by Hitachi, Sharp, Densitron and other compatible manufacturers.

Summary of messages

MAKE

Put

Reset

Sprite

PRINT TO


Creation

MAKE obj AlphaLCD (Int chars, Int rows, Int loc)

The three parameters specify the number of characters per row, the number of rows, and the location.

Connecting an LCD

Location refers to the method of connecting the LCD to the controller: the Expansion Bus, or one of the I2C Buses.

· Expansion Bus: Alphanumeric LCDs will plug directly into the Expansion Bus LCD socket on some of our standard Application Boards. To design your own board refer to the circuit diagrams on our website.
· I2C Bus: To connect LCDs via an I2C Bus a PCF8574 (digital I/O port) IC is required to form the interface. The location parameter used should be one of the equivalent Digital channel numbers for the ‘8574. A large number of LCDs may be connected to a single controller this way.

On creation, the display device is initialised and the display area cleared. The locations available for connecting an alphanumeric LCD are listed in the table below.

Location | Location numbers
Expansion Bus | 0
First I2C Bus | 128, 136, 144, … , 248
Second I2C Bus | 384, 392, 400, … , 504

MAKE lcd AlphaLCD (20,4,0)

MAKE disp AlphaLCD (40,2,160)

The first of the above examples creates a 20 char x 4-line display on the expansion bus, whilst the second creates a 40 char x 2-line display on the first I2C bus.

LIMIT | Multiple AlphaLCD objects may be created via the I2C buses at the various locations, but only one AlphaLCD may be created on the expansion bus. The parameter rows must be in the range 1-4.
LockIcon | If the AlphaLCD is being used by more than one task, it is recommended that Locking is used before issuing Put or Die messages.


Put

obj . Put (Int)

This message displays a character on the AlphaLCD.

The character could be an ASCII value or may have been defined using AlphaLCD.Sprite.

LockIcon

Note: if using the AlphaLCD object in more than one task, it should be locked before sending the Put messages, and unlocked afterwards.

-->lcd.lock

-->REPEAT 5 lcd.put(65 + index0)

-->lcd.unlock


Reset

obj . Reset

This message re-initialises the controller IC, refreshing the existing display. Should you wish to clear the display use:

-->PRINT TO lcd, CLS

SeeAlso

See also Accepting Print.


Sprite

obj . Sprite (Int address)

This allows eight user-defined characters in the LCD controller IC to be defined. Each character is defined by eight bytes. Only the five least significant bits are used. address is the address in memory of 64 bytes of data defining all eight characters. The first eight bytes are for character 0, and the next eight for character 1 and so on.

The following example uses an array of data in binary format that defines an ‘F’-shaped sprite, so you can see the relationship between the bits in the definition and the pixels on the LCD. Up to seven more characters could be defined.

ARRAY user_chars(8,64)
%11111, ;an 'F' character with an underline
%10000,
%10000,
%11110,
%10000,
%10000,
%00000,
%11111,
$FF ;[Fill the rest of the array with $FF for now]
END
Lcd . Sprite(user_chars . Pointer) ; define the characters
Lcd . Put (0) ; sends character 0 to the LCD.

SeeAlso

See also Array.


Accepting Print

PRINT TO obj, <print list>

Printing to an AlphaLCD object displays text on the LCD. The object also understands the following printing keywords:

CR

Go to the beginning of the next line, scroll up a line if necessary.

HOME

Go to the top left of the display.

CLS

Clear the display and go to the top left.

GOTOXY

Go to the given character position. The top left position is (0,0). Wrap-around will occur if x or y are outside the limits of the display.

-->PRINT TO lcd , “Hello” , GOTOXY (10 , 1) , “World”


Analogue

Object Types

Analogue

The Analogue object type allows read and write access to analogue I/O.

Devices currently supported are:

· VM-1 on-board channels: Eight 10-bit inputs, two of which may also be configured as 8-bit outputs.
· PCF8591: each has four 8-bit inputs and one 8-bit output.
· AD7998: 12-bit inputs.
· MAX1236 and 1238: 12-bit inputs, 4 or 12 channels.

Additionally we provide Venom-SC code to drive the following ICs indirectly:

· MCP3421
· ADS1110

Summary of Messages

MAKE

Value

PRINT


Creation

There are several on-board and off-board analogue drivers available.

· Onboard Analogue I/O and PCF8591
· AD7998 and variants
· MAX1236/1238
· MCP3421 (Venom code driver only)
· ADS1110 (Venom code driver only)

Onboard Analogue I/O and PCF8591

MAKE obj Analogue (Int channel)

This creates an analogue object on the device specified by the channel number. The table below shows the analogue input or output that relates to each channel number.

Analogue Device | I / O | Channels | Resolution
VM-1 On-board ADC | Input | 40 – 47 | 10 bits
VM-1 On-board DAC | Output | 46 – 47 | 8 bits
I2C Bus 1; PCF8591 | Input | 256 - 287 | 8 bits
I2C Bus 1; PCF8591 | Output | 288 - 295 | 8 bits
I2C Bus 2; PCF8591 | Input | 512 - 543 | 8 bits
I2C Bus 2; PCF8591 | Output | 544 - 551 | 8 bits

Formula for channel number of an analogue I/O on a PCF8591 on an I2C Bus:

Bus * 256 + Address * 4 + PCF8591AIN + 32 * PCF8591AOUT

Where:

Bus is the I2C Bus number (1 or 2)

Address is the binary value of the address bits on the IC (A0 + 2*A1 + 4*A2)

PCF8591AIN is the number of the input (0-3, use 0 if an output)

PCF8591AOUT is 0 for an input, 1 for an output.

For example:

--> MAKE voltage_reading Analogue(256) ;the 1st I2C analogue input

memoryUse

Analogue is a Zero-Memory object

AD7998 and variants

Variants include: AD7997, and the -0 and -1 addressing options.

MAKE obj Analogue (0, Int bus, Int I2C_add , Int channel)

bus should be 1 or 2 for which I2C Bus you wish to use.

I2C_add should be in the range 64 - 68. Note: this clashes with the PCF8574 address range.

channel should be in the range 0-7.

For example, an object to read channel 2:

MAKE a Analogue(0,1,64,2)

PRINT a.Value

Read any channel

If you make an analogue object like this on channel 0, you can later select which channel you wish to read when you call the Value message. This can sometimes be more convenient than defining the particular channel in the MAKE. Here is an object that will read channel 0 by default, but will read any channel if you so specify.

MAKE a Analogue(0,1,64,0) ;Set up to read channel 0

PRINT a.Value ;Read channel 0

PRINT a.Value(2) ;Ask to read channel 2

Other options

There are many other options available on the AD7998 than are accessible through this driver. You can use the I2C Bus object to access them.

For your information, the MAKE command does not communicate with the device at all, and the Value message uses the device in Command Mode (Mode 2), and does a simple read of the selected channel.

memoryUse

Analogue is a Zero-Memory object

MAX1236/1238

MAKE obj Analogue (Int type, Int bus , Int channel, Int setup)

type should be 4 for MAX1236 and 5 for MAX1238

bus should be 1 or 2 for which I2C Bus you wish to use.setup is an optional parameter - it defines the setup register value sent to the device each time it is read.

channel should be in the range 0-3 for the 1236 and 0-11 for the 1238.

If setup is not supplied, a default value is used. See below.

For example, an object to read channel 2:

MAKE a Analogue(4,1,2)

PRINT a.Value

Read any channel

If you make an analogue object like this on channel 0, you can later select which channel you wish to read when you call the Value message. This can sometimes be more convenient than defining the particular channel in the MAKE. Here is an object that will read channel 0 by default, but will read any channel if you so specify.

MAKE a Analogue(4,1,0) ;Set up to read channel 0

PRINT a.Value ;Read channel 0

PRINT a.Value(2) ;Ask to read channel 2

Other options

There are many other options available on the MAX1236/8 than are accessible through this driver. You can use multiple objects with different setup register values, or you can access the IC directly using the I2C Bus object.

The setup register value is optionally selectable during MAKE (default value $D2), however the configuration register value is fixed at $61, plus the channel selection bits. See the device datasheet for the meaning of the bits in these registers.

For your information, the MAKE command does not communicate with the device at all, and the Value message sends the setup register value followed by the configuration register value, and then does a simple read of the selected channel.

memoryUse

Analogue is a Zero-Memory object

MCP3421

This device is not supported directly, but Venom code to drive it is listed here for your convenience. It uses the I2C Bus object.

See the device datasheet for the meanings of the bits in the configuration value.

;Some constants for the ADCs.

#DEFINE ADC_ADDRESS %11010000 ;I2C address of the MCP3421.

#DEFINE ADC_CONFIG %00011000 ;Continuous, 16-bit, 1:1 gain.

TO setup_adc

net.Lock

net.On

net.Put(ADC_ADDRESS)

net.Put(ADC_CONFIG)

net.Off

net.UnLock

END

;Read raw adc value for a channel.

TO read_adc

net.Lock

net.On

net.Put(ADC_ADDRESS+1)

a := net.Get()

b := net.GetLast()

net.Off

net.UnLock

RETURN a*256 + b

END

Notes: you only need to lock the bus if more than one task uses it.

Multiple devices

Notes: you can get MCP3421 with eight different I2C Addresses, however it is likely to be difficult to source non-base address ICs in small quantities. It is possible to use more than one MCP3421 of the same address on a single I2C bus by multiplexing the SDA signal using an analogue multiplexer IC. Contact Micro-Robotics for details of the circuit required.

ADS1110

This is similar to the MCP3421, above, and so may be driven with similar code.


Value

obj . Value lrarrow Int

This active variable allows analogue values to be read from Analogue objects defined on input channels, and analogue values to be written to Analogue objects defined on output channels.

The value is not the voltage, but the ‘step number’ in the analogue range. The correspondence between Value and the actual voltage is given below, assuming that the analogue reference voltage is 5 Volts, and ignoring device offset and linearity errors.

Device | Value range | Voltage step
8-bit | 0 - 255 | ~19.5 mV
10-bit | 0 - 1023 | ~4.88 mV
12-bit | 0 - 4095 | ~1.22 mV
16-bit | 0 - 65535 | ~76.2 µV

Note: the output impedance of the DACs is often quite high - check the drive capability in the device datasheet.

Channel Selection

obj . Value(Int chan) lrarrow Int

On some analogue objects if you pass a parameter to the Value message you can select which channel you wish to read by a number rather than by defining it in the MAKE.


Printing

PRINT obj

Prints the the analogue object like this:

[Analogue: 317]

where the number is the value of the input or output.


Array

Object Types

Array

Array is an object intended for storing a fixed amount of data. For example, Arrays may be used to store a look-up table for linearising a sensor; store a set of strings for implementing a generalised menu system; or hold a table of procedure pointers in a sophisticated application.

Arrays may be constant - that is their contents are defined at compile-time, they naturally reside in Read Only Memory (ROM), and their contents are fixed once you have written your program - just like procedures. Constant arrays are created in a special way: Creating constant arrays.

Arrays may also be variable - that is they are created during program execution (using MAKE, NEW or .Copy), they naturally reside in Read/Write Memory (RAM), and their contents may be set and reset at any time after creation. See MAKE for how to create them.

Arrays may also be non-volatile - that is their contents are variable, but the values are retained while the controller is powered down. See here for how to create them.

ARRAYs can hold data of the following types:

· 8, 16 or 32-bit integers
· Floating point numbers
· Pointers (to global variables)
· Strings (variable or constant)

Each array holds only data of a single type.

If you need an object that can hold any type of data, use Buffer of Any.

Summary of messages

MAKE

Address

Checksum

Copy

Element

Length

Reset

Valid

PRINT


Creation

Here we will look at creating variable arrays. See here for creating constant arrays, and below for non-volatile arrays.

MAKE obj Array (Any prototype , Int n , … )

Prototype is a value that indicates the type of data that the array will hold:

Prototype | Element Type | Range of values element can hold
8 | 8-bit integer (unsigned) | 0 to 255
16 | 16-bit integer (signed) | -32768 to +32767
32 | 32-bit integer (signed) | -2,147,483,648 to 2,147,483,647
1.0 * | Floating point (IEEE single precision) | ~ ±1.0E±38, ~7 digits of precision
"" ** | String (string constant or String object) | N/A
@dummy_name*** | Pointer to a global | N/A

*or any floating point number. **or any string value. *** or any pointer to a global variable.

n is the number of elements in the array.

The … indicate that you can put some initialising data in the parameter list. If there are fewer initialisers than elements, then the value of the last initialiser is used to fill the array. If no initialisers are present, then the array is not initialised: the data may be any random set. Take care not to put too many initialisers in as you may run out of space on the Venom-SC stack. A sensible limit is 10 or so. If you need more initialisers than this use a constant Array and take a copy of it.

memoryUse Arrays use a single, contiguous block of RAM that is large enough to hold all their data plus 18 bytes.

Non-volatile arrays

MAKE obj Array (Any prototype , Int n , NIL )

Non-volatile arrays are similar to variable arrays, but store their data in the NV RAM area of the controller's memory - any data held here is retained when the controller is not powered, as long as the backup battery holds up.

You specify a non-volatile array by using a third parameter with value NIL, and no further parameters.

You must take care when creating non-volatile arrays - they must be created only once, in the same order and with the same size each time the controller starts up, in order that they 'overlay' the same block of memory. See this explanation of NV RAM for more information.

Example:

TO init

Free(2) := 50 * 1024 + 1000; enough NV-RAM for File system and NV Arrays

MAKE fs FileSystem("RAM", 50*1024)

MAKE nv_array1 Array(8, 100, NIL)

MAKE nv_array2 Array(16, 200, NIL)

MAKE nv_array3 Array(1.0, 50, NIL)

… ;other init code

END

If there is not enough NV-RAM to create the array, then a ‘Resource Error’ is given.

Useful extras

You can write default values to the non-volatile array from another array using Copy. You can use Checksum and Valid to detect corrupt or uninitialised data.

Example code

Using Arrays of strings

The following bit of code illustrates the use of an 'array of strings'. Here we are using both String objects and string constants in the array - it can handle both. See if you can work out what is going on here; you may need to learn about String objects, array initialisers (above), and the Element message.

-->MAKE sa Array ("",5,"X") ;New array - each element is constant "X"

-->REPEAT 3 [sa.(INDEX0) := NEW String(10)] ; 3 new string objects put in array

-->sa.(0).Put("Hello") ; Two of the string objects have text loaded in them

-->sa.(1).Put("Goodbye")

-->PRINT sa ; print out what's in there:

Hello

Goodbye

X

X

-->

BugAlert You are responsible for killing any string variables you no longer use, e.g: sa.(0).Die else you will create a memory leak.


Address

obj . Address rarrow Int

Address returns the memory address of start of data in the array. Data is arranged contiguously: elements are in order with no gaps.

The address will always be aligned to the number of bytes required by the largest object used by the host processor. In the case of the VM-1 it will be aligned to an even address.

Notes:

Constant ARRAYs of strings are arranged as a list of pointers, followed by all the string data.

The pointer data in an array of pointers is not in an easily usable format.


Checksum

obj . Checksum rarrow Int

Checksum will form a 16-bit checksum (not specified exactly) of all the bytes in the array and put its value into the array header, so the array contents may be validated at a later time. It will also return the value of the checksum so that it may be used for other purposes.

SeeAlso

See also: Valid.


Copy

obj . Copy rarrow Array

obj . Copy(Array source)

Make a new copy of an array

Copy without any parameters makes a copy, in normal RAM, of any kind of array, and returns the new array object. You can modify the elements of the copy, as it will be a variable array.

For example, this creates a new array initialised to the contents of the original:

variable_data := lookup_data . Copy

Copy the data only to an existing array

Copy with a single parameter - another array - will copy the data only from the second array into the first.

non_vol_array.Copy(default_data)

Note: no check is done for the two arrays being the same type - the data is copied as raw bytes. If the arrays hold different amounts of data, then no overflow will occur, but underflow will: if the source array is smaller, some elements at the end of the destination array may not be set.

Note: the checksum is not set to a valid value after the copy.

This old functionality will be removed at a later date:

Copy with a single parameter value 1 will return a new non-volatile array.


Element

obj . Element (Int num) lrarrow Any
obj . (Int num) lrarrow Any

Individual elements in an array are accessed using the Element message.

The parameter num specifies the element number.

Elements will be checked for the correct type when they are written. For integer arrays, the written values will be truncated to the correct size by removing higher-order bytes.

Examples

ARRAY phrases ("",2)

"Hello"

"Goodbye"

END

-->Print phrases . Element (1)

Goodbye-->

Venom abbreviation allows .() to replace .Element(), so you could also use:

-->Print phrases . (0)

Hello-->

And...

-->MAKE data_list Array (8, 10, 0)

-->PRINT data_list.(0)

0-->

-->data_list.(0) := 10

-->PRINT data_list.(0)

10-->


Length

obj . Length rarrow Int

Length returns the number of elements in the array.


Reset

This old functionality will be removed at a later date:

obj . Reset

Reset operates only on Arrays that have been created using the Copy message on another Array.

It will copy the data from the 'parent' into the 'child' array.


Valid

obj . Valid

Valid will return TRUE if the checksum in the array header matches the checksum of all the data in the array.

Valid will be TRUE immediately after a Checksum message.

It will be FALSE immediately after the value of any element in the Array is changed. Valid is useful for checking the integrity of non-volatile parameters.

TO init

Free (2) := 10000 ; enough NV-RAM for all my n.v. Arrays

MAKE nv_array1 Array(8,100,NIL)

IF NOT nv_array1 . Valid ;Check the integrity of the data.

[

nv_array1 . Copy(default_array) ; corrupt! Set the defaults

nv_array1 . Checksum ; set the checksum.

PRINT “PARAMS CORRUPT – DEFAULTS LOADED.”

]

…

END

SeeAlso

See also: Checksum


PRINT

PRINT obj :fw

Printing the array will print out each of the elements of the array in order, each element on a new line.

If colon formatting is used, the specified format is applied to each element as it is printed.


AsynchronousSerial

Object Types

AsynchronousSerial

AsynchronousSerial objects provide interfaces to serial communication ports. The two ‘hardware*’ ports can operate at standard rates up to 38400 baud, or higher non-standard rates. The ‘software*’ port can operate at up to 9600 baud.

There is configurable handshaking available on ports 1 & 2: hardware (RTS/CTS), software (XON/XOFF), or none.

*Software serial port

Serial ports 1 & 2 are 'hardware' ports - that is they are implemented almost entirely in hardware sub-systems in the VM-1's microcontroller. Port 3 is a 'software' serial port - it has been implemented by using a different hardware sub-system (the counter-timer block) and some software drivers to synthesize a serial port. Because it it not supported in 'native' hardware, it takes more processor power and cannot run as fast as a 'hardware' port.

Port 3 is implemented using the Pulse I/O channels 5 and 6.

You should be careful when you also want to use a PulseCounter or Shaft object that uses channel 2: you will need to define a different counter register than the default channel, 6. Contact us if you need more information on this rather tricky subject.

The software port does not have any kind of flow control.

Summary of Messages

MAKE

Baud

Escape

Flush

Format

Free

Get

Handshake

InputBuffer

Look

OutputBuffer

Put

Queue

Timeout

Valid

PRINT TO


Creation

MAKE obj AsynchronousSerial(Int baud_rate, Int port, Int handshake)

When making an AsynchronousSerial object the baud rate, the port and, optionally, the handshaking are specified.

Generally the VM-1 uses a group of four channels for each serial port: Transmit, Receive, Handshake input and Handshake output. If hardware handshaking is not enabled then the handshake channels are free to be used for other purposes. See the VM-1 datasheet for more information on these channels.

Here we create a serial communication object on port 1 talking at 38400 baud, with hardware handshaking:

MAKE serial AsynchronousSerial(38400,1,1)

An object like this is created by the default startup routine at either 38400 or 9600 baud, depending on the state of the User Switch.

· The port values are port 1, 2 & 3. Port 3 is a 'software' port. See here for details.
· The baud rates available on the hardware serial ports lie in the range 31 to 500000. For the software port it is 300 to 9600.
· Handshaking takes values of 0 (none), 1 (hardware handshaking) or 2 (software handshaking). There is no handshaking at all on the software port.
· The input and output buffers are both 256 bytes long. This is not configurable.

Hardware

You may need to connect RS232, RS485 or other line transceivers to your VM-1 in order to use this object to communicate with other equipment. Our development kits include these transceivers on the application board.


Baud

obj . Baud lrarrow Int

The Baud active variable controls the baud rate of the serial port.

To ensure a baud rate change happens smoothly you should ensure that the serial output buffer is empty before changing baud rate.

The baud rates available on the main serial port range from 31 to 500000, though the highest ‘standard’ baud rate is 38,400 bd. In general the exact baud rate is not possible so the closest alternative will be selected. So long as it is within a couple of percent of the correct value it will be acceptable. Reading Baud gives the exact rate used.


Escape

obj . Escape lrarrow Int

The Escape active variable turns CTRL-C (break) and CTRL-T (list tasks) on and off. When escape is 0 (or FALSE), CTRL-C & CTRL-T are treated as normal characters.

Escape only apples to the main serial port (port 1). The default state after, MAKE, is that CTRL-C & CTRL-T are enabled.

Escape is ignored when sent to the other serial ports.


Flush

obj . Flush

This message will flush the serial input buffer, discarding any characters in it.

It may be applied to the AsynchronousSerial object itself, or to an InputBuffer sub-object.

SeeAlso

See also: InputBuffer.


Format

obj . Format lrarrow Int

The Format active variable allows the serial communication format to be changed. The integer value is a set of flags coded as bits in a binary number:

Bit | Value | Meaning… | …When 0 | …When 1
0 | 1 | Data length | 8 | 7
1 | 2 | No. Stop bits | 1 | 2
2 | 4 | Parity type | Even | Odd
3 | 8 | Parity used | No | Yes
4 | 16 | ‘Parity’ bit forced to 0 | No | Yes

The default format is ‘8-NONE-1’ which has a format value of zero.


Free

obj . Free rarrow Int

Free may be sent to the AsynchronousSerial object itself, or the InputBuffer or OutputBuffer sub-objects.

Free returns the amount of free space in the serial input or output buffer. If it is applied to the AsynchronousSerial object itself, it returns the input buffer value.


Get

obj . Get rarrow Int

The Get message returns a character from the serial port, but waits if there isn't one available yet.

Note: CTRL-C characters can be trapped by the Escape function and so not seen in Get. If these characters need to be received, Escape may be turned off with serial.Escape.

obj . Get(String s[, Int n])

This will store a whole line of text in string s.

By default the line is terminated with CR and input is not echoed back to the serial line.

If n = 1, the line is expected to be terminated with CRLF or just LF (CR is ignored)

If n = 2, the input is echoed back to the sender (useful for interactive keyboard input)

Neither CR nor LF is included in the stored string.

If the string capacity is reached, Get returns without collecting any further input.

Obj.Get(array a [, Int start, Int size])

a | An array of 8 bit integers
start | (default 0) element number at which to start transferring data to array
size | (default whole array) how many bytes to transfer

This gets a fixed number number of characters into an array very efficiently.


Handshake

obj . Handshake lrarrow Int

Handshake allows the handshaking function of the port to be set.

Value | Handshaking
0 | NONE
1 | Hardware
2 | Software

Software handshaking is performed with the XON and XOFF characters in the ASCII character set. If enabled, these characters assume their control function and may not be sent over the serial link.

SeeAlso

See also: Timeout.

Hardware

Handshaking is not available on the 'software' port: port 3.

LIMIT

The handshaking 'high and low water marks' inside the input buffer are set at 1/4 and 3/4 of the buffer size, i.e. at 64 and 192 characters. Thus handshake output is asserted 'off', or XOFF is sent, when there are more than 192 characters in the input buffer, and these signals are turned on again when there are fewer than 64 characters.

On the other side of the serial ports, when handshake input is asserted off, or XOFF is seen coming in, then no more than two characters are sent before transmission terminates.


InputBuffer

obj . InputBuffer rarrow <InputBuffer>

This returns a sub-object to the AsynchronousSerial object that allows the input side of the serial stream to be treated distinctly. Further messages may be sent to the InputBuffer object:

sib := serial.InputBuffer

WHILE sib.Queue

[serial.Get] ; read chars while they are there.

The input buffer object may also be used with ‘dot-chaining’. This is more readable, but slightly less efficient:

WHILE serial.InputBuffer.Queue

[serial.Get]


Look

obj . Look rarrow Int

Look fetches, and returns the value of, the next character in the serial input buffer. If there was no character waiting it returns –1.

SeeAlso

Get


OutputBuffer

obj . OutputBuffer rarrow SerialOutputBuffer

This returns a sub-object to the AsynchronousSerial object that allows the output side of the serial stream to be treated distinctly. Further messages may be sent to the output buffer object:

sob := serial.OutputBuffer

IF sob.Free

[serial.Put(c)] ; send chars if there is room.

The output buffer object may also be used with ‘dot-chaining’. This is more readable but slightly less efficient.

IF serial.OutputBuffer.Free

[serial.Put(c)]


Put

obj . Put ( Int character )

The Put message sends a single character to the serial output buffer, waiting if the buffer is full.

LIMIT

character will be masked to the range 0 - 255

Obj.Put(array a [, Int start, Int size])

a | An array of 8 bit integers
start | (default 0) element number at which to start transferring data from array
size | (default whole array) how many bytes to transfer

This outputs a fixed number number of characters from an array very efficiently.


Queue

obj . Queue rarrow Int

Queue may be sent to the AsynchronousSerial object itself, or the InputBuffer or OutputBuffer sub-objects.

Queue returns the number of characters waiting in the serial input or output buffers. If it is applied to the AsynchronousSerial object itself, it returns the input buffer value.


Timeout

obj . Timeout lrarrow Int

This active variable controls the timeout for software handshaking. If an XOFF character shuts off the serial port's transmitter, and the subsequent XON is missed for some reason, the transmitter would stay off forever. However if timeout is set to a non-zero value, the transmitter will be turned on again after the timeout period.

Timeout defaults to 10,000 (10 Seconds) currently. It may be turned off entirely by setting it to zero. Its value is set in milliseconds, up to a bit more than 1,000,000 (~16 minutes).

Timeout is set and stored with a resolution of 64mS.

SeeAlso

See also: Handshake.


Valid

obj . Valid rarrow Int

Valid is used to detect errors in serial reception. It returns three error flags as bits in a binary number. The flags are all reset to zero once Valid has been read.

Bit | Value | Meaning | Description
0 | 1 | Parity Error | Incorrect parity in the received character
1 | 2 | Framing error | The STOP bit was 0 (should be 1)
2 | 4 | Overrun error | One or more characters lost by serial Rx

You should be able to use Valid to detect serial breaks, i.e. when the serial line is put into the 'active' state for a period (much) longer than the character frame. If Valid continuously indicates a framing error, and no new characters have been received then there is a serial break.


Accepting Print

PRINT TO obj , <print list>

Printing to the AsynchronousSerial object sends the printed characters out of the serial port. The following print keywords are supported; others are passed on unprocessed in their internal representation and so should not be used.

BEEP | ASCII 7
BS | ASCII 8
LF | ASCII 10
CLS | ASCII 12
CR | ASCII 13 & 10
CHR n | ASCII character n


Buffer

Object Types

Buffer

Buffers can be used to store lists of data: integers, floating-point values, text or even other objects. Buffers dynamically allocate as much memory as they need to store the data they hold, plus an overhead. They may be used to make FIFO and FILO structures.

Text Buffers

Text Buffers (buffers containing textual information) may be used for string or text operations in Venom-SC. See also String objects.

Buffer of Any

There is a special kind of Buffer known as 'Buffer of Any' that can hold lists of any kind of entity, including lists of other buffers, arrays, strings, etc.

Summary of messages

MAKE

Element

Empty

Find

Flush

Get

GetLast

Insert

Length

Put

Queue

ReadPoint

Remove

Reset

Value

PRINT

PRINT TO


Creation

MAKE obj Buffer (Any prototype)

The prototype specifies the type of data to be stored in the buffer; it must be one of those shown in the following table:

Value of prototype parameter | Element Type
8 | 8-bit unsigned integer
16 | 16-bit signed integer
32 | 32-bit signed integer
1.0 * | Floating point
“” ** | Text
NIL | Any type

*or any floating point number. **or any string value.

The following example creates a buffer with 8-bit integer elements:

-->MAKE buffer_object Buffer (8)

For text buffers, the string used for the prototype may be empty or may contain some initialising text, i.e.:

-->MAKE text_buffer_object Buffer (“”)

-->MAKE text_buffer_object Buffer (“Initialising text”)

The first of these commands creates an empty text buffer; the second creates a text buffer initialised with some text.

text.

memoryUse

Buffers use a minimum of 316 bytes of memory each. Each buffer has a header block of 54 bytes, and one or more data blocks of 262 bytes. Each data block can hold 256 bytes of data.

Buffers of integers hold data in 8-, 16-, 32-, or 64-bit elements (1, 2, 4 or 8 bytes). Buffers of floats use 32-bit elements. Buffers of Any use 64-bit elements.

Buffer of Any

A buffer that can hold any kind of entity is called a Buffer of Any. It is created using the value NIL as the prototype:

-->MAKE buffer_object Buffer (NIL)

You can use this kind of buffer to hold lists of objects, including lists of Buffers, Arrays or Strings, for example.

Using Buffer of Any

Because Buffers of Any can hold objects, you can use them to do things that would otherwise take a lot of coding.

For example to send a Value message to an object held in the nth element of a buffer of any, you can do this:

buf_of_any.(n).Value

You can find the data type of something held in a buffer of any using the TYPEOF operator:

PRINT TYPEOF(buf_of_any.(n))

Loading a Buffer of Any with new objects

Often when using a Buffer of Any you will wish to load it with a set of new objects, for example a set of String objects.

This code loads the buffer with 10 new strings, each with a capacity of 20 characters.

REPEAT 10

buf_of_any.Put(NEW String(20))

Removing the Buffer and it's objects

If at a later time you wish to remove the buffer and the strings it holds you can use this:

REPEAT buf_of_any.Length

buf_of_any.(INDEX0).Die

buf_of_any.Die

Memory leak examples

The following are all examples of how not to use the Buffer of Any, in that they will result in a memory leak.

buf_of_any.(5) := NEW String(20)

...; some other processing

buf_of_any.(5) := <anything else>

In the code above, the element (5) of the buffer was overwritten with a new value, but the original string wasn't removed, so the string is lost, together with it's memory.

REPEAT 10

buf_of_any.(INDEX0) := NEW String(20)

...; some other processing

buf_of_any.Die

This time all the strings in the buffer were lost.


Element

obj . Element (Int item_number) lrarrow Any

obj . (Int item_number) lrarrow Any

The Element() active variable allows both read and write random access to the contents of a buffer as if it were an array. Venom abbreviated syntax allows the use of .() to substitute for .Element().


Empty

obj . Empty

Empty throws away any data held in a buffer, freeing up all but the minimum memory used by the Buffer.

SeeAlso

See also Flush.


Find

The find message can be applied to text buffers or integer buffers.

Text Buffers

obj . Find (String str, Int start_pos) rarrow Int

obj . Find (Buffer buf, Int start_pos) rarrow Int

Find searches a text buffer for the search string specified by either a string (str) or another text buffer (buf) starting at the optional element specified by start_pos (or from the beginning of the buffer if no second parameter is supplied). If a match is found, the element position at which the specified text begins is returned, otherwise the value -1 is returned. The search string (str, or buf) is limited to 256 characters in length.

The following example finds the start position of the first occurrence of a string in the buffer:

MAKE b buffer("text text text")

pos := b . Find ("tex", 3) ; pos will be 5

The example below shows the Find message being used to locate the text contained in buffer b2 within buffer b:

MAKE b2 buffer("xt")

pos := b . Find (b2) ; pos will be 2

Integer Buffers

obj . Find (Int value, Int start_pos) rarrow Int

Find searches an integer buffer for a particular value, starting from beginning, or an optional start position.

It returns the position the value was found at, or -1 if it wasn't found.


Flush

obj . Flush

Flush discards buffered data that is behind the current readpoint. The memory it occupied is released back to the system.

The readpoint moves when data is read from the buffer using Get, or by directly writing to the buffer's ReadPoint.

SeeAlso

See also Empty, Get, ReadPoint.


Get

obj . Get rarrow Any

Get returns the data item from the buffer at the current readpoint and then advances the readpoint.

LIMIT | Attempting to read past the end of data will result in an 'Array index out of range' error.
SeeAlso | See also Put, ReadPoint, Flush


GetLast

obj . GetLast rarrow Any

GetLast removes one data item from the end of the buffer and returns it. It may be used to delete characters from the end of a text buffer, or to implement a FILO buffer, or ‘stack’: Put is used to push data on to the stack, and GetLast removes it. Length may be used to check how much data is left in the Buffer.

SeeAlso

See also Put


Insert

obj . Insert (String str, Int pos)

obj . Insert (Buffer buf, Int pos)

This message is only available for buffers containing text. It allows text to be inserted into the buffer at the element position specified by pos. The following example inserts a string into a buffer:

MAKE b Buffer(“text text text”)

b.Insert(“XXX” , 3)

RRINT b

texXXXt text text

The example below inserts the contents of buffer b2 into buffer b:

MAKE b2 Buffer(“YYYY”)

b.Insert(b2 , 5)

PRINT b

texXXYYYYXt text text

Note that a buffer cannot be inserted into itself. A Type Mismatch error is given if this is attempted.

SeeAlso

See also Remove


Length

obj . Length rarrow Int

Length returns the number of data items currently held by the buffer (equivalent to the position of the writepoint).

SeeAlso

See also Queue, Put.


Put

obj . Put (Any item)

Put stores the data item at the WritePoint and then advances the WritePoint. E.g.:

REPEAT 5 buff.put(index0)

The data item has to be of the correct type for the buffer to accept, else a Type Mismatch error is generated.

Large integer values sent to 8 or 16-bit buffers are simply truncated.

Buffers of Any will accept data of any type.

Put a block

obj . Put (string/array data , Int start, Int size)

This form efficiently appends a block of consecutive elements from an integer or float array to a buffer of identical element type, or from a string to a text buffer.

If the optional parameters start and size are not given, the whole array or string is copied.

MAKE b buffer("")

b.Put("Hello")

This form of Put is faster than repeated single element Put message, but for integers the element types must be the same size (8, 16 or 32 bit).

LockIcon | Note: if using the Buffer object in more than one task, you may with to lock it before a group of Put messages are issued, and unlock it afterwards.
SeeAlso | See also Accepting Print, Buffer.Get, and also Locking in the Tutorial Guide.


Queue

obj . Queue rarrow Int

Queue returns the number of data items in the buffer between the readpoint and the writepoint. This is essentially the number of data items queuing to be processed with Get.

SeeAlso

See also Put, Get.


ReadPoint

obj . ReadPoint lrarrow Int

The ReadPoint active variable holds the value of the buffer readpoint, allowing it to be read and set.

LIMIT | The readpoint may only be set between zero and the writepoint (buffer_object . Length)
SeeAlso | See also Reset, Get, Flush.


Remove

obj . Remove(Int start, Int size)

Remove will remove a section of text from any point inside a text buffer, starting from the position given by start, and number of characters given by size. If the section to remove exceeds the buffer boundaries, then an error is given.

SeeAlso Insert, GetLast


Reset

obj . Reset

Reset resets the readpoint of the buffer back to the start of the buffer.

SeeAlso

See also ReadPoint.


Value

obj . Value rarrow Int
obj . Value(Int or Float prototype) rarrow Int or Float

Value will convert the text in a text buffer to a numeric value. Beginning at the start of a buffer, it skips over any leading white space characters (space, tab, new line) and takes account of numbers prefixed with a '+' or a '-' sign. It stops reading numeric characters when it encounters a character that isn't valid for the kind of number being looked for.

If there are no parameters, Value looks for a decimal integer.

If a parameter is given then this is used as a prototype for the result, and indicates what number base is to be used:

Prototype | Kind of number found
10 | Decimal integer
2 | Binary integer
16 | Hexadecimal integer
1.0 | Floating point number

Notes

Value does not 'Get' any characters from the buffer, nor does it use or alter the ReadPoint of the buffer - it only looks at the text in the buffer and returns the numeric value of the first number it finds.

Integer prototypes from 2 to 36 may be used to read numbers in any base from 2 to 36. In bases above 10, the characters A-Z or a-z are used for the digits above 9.

If no numeric characters are seen, the value returned is zero, either integer or float.

If an integer value exceeds the maximum absolute value for an integer, the largest value that has the correct polarity is returned.

Any floating point value may be used for the float prototype.

Floating point numbers in the text buffer may include an exponent suffix, e.g. 1.0e+12

SeeAlso

See also ProtAnalyser


Accepting Print

PRINT TO <text buffer>, <print item>, ...

Text buffers are able to accept print. The print output is simply appended to any existing text in the buffer.

SeeAlso

See also Insert.


Printing

PRINT obj

PRINT obj : n

PRINT obj : start : n

Text buffers

Printing a text buffer prints out all the text in the buffer.

If the optional format parameters are used then any section of the buffer may be printed, just as with strings.

One format parameter specifies that the first n characters are to be printed, or the last n if n is negative.

Two format parameters specify printing of any portion of the string: the first parameter is the start position, and the second is the number of characters to print.

Parameter values that imply characters before the start, or after the end of the buffer will result in the print output being padded with spaces at the start or end.

Example:

MAKE b Buffer("The quick brown fox")
PRINT b:9
The quick
PRINT b:-9
brown fox
PRINT b:3:10
quick bro

PRINT b:-5:7

Th

Other buffers

PRINT obj : f1 : f2 : f3

Printing a numeric Buffer prints out each of its elements in a vertical column, with the format specifiers f1, f2 and f3 being used directly on each of the elements as if it were a single number being printed.

MAKE b buffer(1.0)
b.Put(1.324)
b.Put(100.0)
PRINT b:5:2
1.32
100.00

LIMIT

f1,f2 and f3 must be acceptable to all the items in the Buffer, else an error is generated.


CANBus

Object Types

CANBus

This object is currently in development – the following is provided for those users who would like to experiment with pre-releases of the software.

The CANBus object allows the VM-1 to communicate over CAN – the widely used networking standard for Controller Area Networks. CANBus implements low level CAN communication protocols. It does not implement any of the higher level protocols such as CAN Open, CAN Kingdom, etc, but it may be used to implement higher level protocols.

The CANBus object drives the MCP2515 CAN controller IC. The MCP2515 is connected to the VM-1’s SPI Bus. You will also need a CAN Bus driver IC.

There are currently two main modes of operation: polled and interrupt-driven.

Polled

In the polled mode the interrupt output of the MCP2515 is connected to a VM-1 Digital Input channel. The Venom application has to repeatedly poll this input to see if the MCP2515 needs servicing. While the input is asserted the Venom application should call the CANBus object's Update message to service the IC.

Interrupt-driven

In interrupt mode, the interrupt output of the MCP2515 is connected to an interrupt input on the VM-1. This input is on the same pin as the SCL2 signal, so the second I2C Bus can’t be used if this mode is selected for CANBus.

(Note: currently, when in interrupt mode, the CS\ signal for the SPI bus is on the SDA2 signal)

When using interrupt mode there is no need to poll the CANBus object at all – CAN frames are detected and automatically put into a frame input buffer for examination by the Venom program.

Hardware

For details of how to connect the MCP2515 to the VM-1 please contact technical support at Micro-Robotics.

Summary of messages

MAKE

Baud

Format

Free

Get

Look

Off

On

Put

Queue

Reset

Status

Update

Value

Window


Creation

MAKE obj CANBus (Int interface, Int division, Int extended) rarrow CANBus

MAKE creates a new CANBus object and carries out basic configuration.

Immediately after MAKE the device is left in configuration mode. To go to another mode use On.

Parameters

Interface: a number that indicates the CAN interface IC being used and also the detail of how it is connected to the VM-1.

Currently the only values that may be used are 0 and 1, both using the MCP2515 IC. 0 indicates a polled system, 1 an interrupt-driven system.

Division is an integer that represents the bit rate required on the CAN bus as a division of the clock frequency used to clock the device. For example, if you are using a 16MHz clock and require 250 Kbd bit rate then division is 64. See Baud for further discussion of bit timing.

Extended is an optional parameter that sets the default CAN frame type: 0: standard frames, 1: extended frames.


Baud

Obj.Baud lrarrow Int

Baud allows the effective clock division ratio to be read and set.

The value of Baud is an integer that represents the bit rate of the CAN bus as a division ratio of the clock frequency used to clock the device. For example, if you are using a 16MHz clock and require 250 Kbd bit rate then the division ratio is 64:

16,000,000 / 250,000 = 64

can.Baud := 64

LIMIT

The min and max division ratios achievable are 8 and 3200. The smallest practical division ratio is probably 16.

In order to gain write access to CNF (configuration) registers used here you have to use Off to set configuration mode.

Timing configuration

The bit-timing configuration is set according to the value of division in MAKE.

The object will use the division ratio to create a standard set of the bit timing settings in the device’s CNF1-CNF3 registers. The settings it comes up with may not be optimal for your application, but should work in most.

This is how it works:

Generally it aims to use 16 Tq in total over all 4 segments of the Bit Time.

This is assigned like so:

SynchSeg: 1 Tq

PropSeg: 3 Tq

PhaseSeg1: 8 Tq

PhaseSeg2: 4 Tq

[Note the register values should be 1 less than the actual number of Tq!]

It then works out what baud rate pre-scale (BRP) value should be used.

If the division ration is so high or low that the BRP bits can’t meet the requirement then the number of Tqs is adjusted up or down. In general the algorithm tries to keep the sample point within the bit time at 75%, but it also obeys the restrictions on all segment values.

If this still doesn’t work then a runtime error is issued.

The other settings in these registers are set to:

SJW: 0

BTLMODE: 1

SAM: 0

SOF: 0

WAKFIL: 0

If the settings that the object comes up with are not suitable then you can program the CNF registers yourself directly.


Debug

Obj.Debug

Note: the following functionality is not guaranteed to remain available - it may change or be removed.

Debug prints out the values of some of the internal registers of the MCP2515 IC.

This can be useful to see if the MCP2515 is connected to the VM-1 correctly.

Here is a typical printout from a working system:

-->can .debug

Registers:

0F CANCTRL: $00 %00000000

0E CANSTAT: $00 %00000000

2B CANINTE: $1F %00011111

2C CANINTF: $A0 %10100000

2A CNF1: $01 %00000001

29 CNF2: $BA %10111010

28 CNF3: $03 %00000011

30 TXB0CTRL: $18 %00011000

40 TXB1CTRL: $00 %00000000

50 TXB2CTRL: $00 %00000000

60 RXB0CTRL: $26 %00100110

70 RXB1CTRL: $20 %00100000


Format

[Not currently used]


Free

Obj.Free rarrow Int

The Free message reports the number of free frame spaces in the output frame buffer.

LIMIT The output frame buffer can hold 16 frames before it overflows.

SeeAlso Put


Get

Obj.Get

The Get message discards the current frame at the front of the frame input buffer. This is usually done after reading the frame contents with Look.

SeeAlso

Queue, Look


Look

Obj.Look(Int) rarrow Int

The look message is used to look at the first frame in the frame input buffer.

Look takes a single parameter and uses that to return different parts of the frame.

Can.Look(0) ; Frame ID
Can.Look(1) ; Frame data length

Can.Look(2) ; Extended frame?

Can.Look(3) ; Memory address of the CAN frame – ‘volatile’.

Can.Look(4) ; First byte of CAN data

Can.Look(5) ; Second byte of CAN data.

;… and so on to Look (11) – last byte of CAN data (if there are that many). Reading data that isn’t there yields undefined values.

SeeAlso

Get, Queue


Off

Obj.Off

Off will put the device into configuration mode. This is the same as Can.On(4).

SeeAlso

On


On

Obj.On

Obj.On(Int)

On will put the device into normal mode where it may take part in normal CAN interactions on the bus.

If a parameter is passed to On, then the MCP2515’s operating mode is set to the value of the parameter:

Can.On(3) ; set to mode 3: Listen-only.

SeeAlso

Off


Put

Obj.Put(Int ID, Int Addr, Int Nbytes, Int Ext)

The Put message is used to construct and send CAN frames. The outgoing frames are put in the output queue by Put.

For example:

Can.Put (canid, addr, 8) ; Send 8 bytes of data from an address.

ID is the ID field of CAN frame.

The Addr is usually the memory address of some data within an array (see Array Address).

Nbytes is the number of bytes to read from the array. The CAN specification allows up to 8 bytes of data per frame.

The frames are queued in FIFO order and are sent using just one of the device’s output buffers.

The optional Ext parameter allows the standard or extended state of the CANBus object to be over-ridden when required.


Queue

Obj.Queue rarrow Int

The Queue message reports the number of frames in the input frame buffer.

Later it will also be able to report the number of frames in the output buffer.

LIMIT The input frame buffer can hold 32 frames before it overflows.

SeeAlso Get


Reset

[Not currently used]


Status

Obj.Status(Int) rarrow Int

Status returns the error status of the device. See the MCP2515 datasheet for more information.

Can.Status (0) ;returns error flags register contents

Can.Status (1) ;Tx error count.

Can.Status (2) ;Rx error count.


Update

Obj.Update

Update is used with polled systems. When an ‘interrupt’ is detected (by polling the CAN controller’s interrupt output from a Digital input on the VM-1), Update should be called to deal with it. Update reads the interrupt priority register and processes the highest priority interrupt present, resetting the associated interrupt flag in the IC. It then returns, even if there are further interrupts pending.

Currently only Tx and Rx interrupts are enabled in the enable register in the IC.

Error and other interrupts are not enabled.


Value

Obj.Value (Int) lrarrow Int

Value allows direct access to the MCP2515’s register contents.

Can.Value (N) := X ; set register N with value X

X := Can.Value (N) ; read register N

Value(N,M) := (N) ; Bit modify a register value with mask M.

In order to gain write access some registers you have to use Off to set configuration mode.


Window

Obj.Window (Int Filt, Int Id, Int Value, Int Data)

The CAN message masks and filters are set using the Window message:

can.Window (filt, id, value, data) ;define a mask or filter.

Filt: a character parameter that says whether it’s a mask (‘M’) or filter (‘F’) being defined.

Id: which mask or filter (0 – 5)

Value: the value of the mask or filter bits (~32-bit integer)

Data: when present, this parameter indicates we are in standard mode, and supplies the data mask bits. (16-bit integer).

In order to gain write access to the mask and filter registers you have to use Off to set configuration mode.


CRCGenerator

Object Types

CRCGenerator

This object is a wrapper for two different CRC generators:

· A 16 bit generator using the standard CRC-CCITT polynomial and initializer
· A commonly used 32 bit CRC generator
· A 16 bit CRC generator compatible with MODBUS CRC

A CRC (Cyclic Redundancy Check) is a number computed from a block of data such as a stream of text or the contents of a buffer or array, in such a way that any change in the content of the data is likely to change the value of the CRC. This has applications in checking data for corruption when transmitted through an error prone medium. The computation is done is such a way that most forms of simple data corruption (small numbers of incorrect bits, missing bytes etc) are very likely to change the CRC value and thus be detected.

The CRCGenerator is from time to time enhanced to include specific CRC algorithms for other industry standard communications protocols. These could be coded in Venom, but a version implemented though the CRCGenerator object would be much faster.

Summary of messages

MAKE

Get

Put

Reset

Value


Creation

MAKE crc CRCGenerator (Int prototype) rarrow CRCGenerator

Creates a CRCGenerator of the indicated type.

prototype is:

16 | 16 bit generator using CCITT-CRC16
32 | 32 bit generator
'M' | MODBUS CRC - another 16 bit CRC using a different algorithm.
8 | simple sum truncated to 8 bits
'S' | simple sum truncated to 16 bits

The 8 and 'S' options offer a speed improvement over performing the same simple calculation in Venom code.


Get

crc.Get rarrow Int
crc.Get(buf, array or string data) rarrow Int

If a string, buffer or array is supplied as a parameter, the CRC of its contents are calculated and returned.

The element type of the buffer or array must be text or 8 bit.

With no parameter, the CRC resulting from data in previous crc.Put messages is returned.


Put

crc.Put(Int byte)

byte is an integer value used to update the current CRC. Only the lowest 8 bits of the parameter are used.

crc.Put(data[, Int start, Int length]

data | An array, buffer or string. Array element type must be 8 bit. Buffer element type must be 8 bit or text
start | (default 0) 1st element to process
length | (default all) number of elements to process

All or the selected part of the data is entered into the CRC calculation.

This message can be repeated to build up a CRC over selected fields of a block of data.


Reset

crc.Reset

Sets the generator to its initial state, the same as after MAKE.


Value

crc.Value

Value is a synonym for Get.


DateTime

Object Types

DateTime

DateTime objects may be used to convert between the date and time in the familiar calendar form, and an integer value of time in seconds. This ‘absolute seconds’ value may be used for calculations involving real dates and times.

SeeAlso RealTimeClock

Summary of messages

MAKE

Day

DayOfWeek

Hour

Minute

Month

Nudge

Second

Time

Update

Valid

Year

PRINT


Creation

MAKE obj DateTime

A DateTime object is created with its time set to zero, representing 00:00:00 on the 1st January 1990.

For example:

MAKE dt DateTime

memoryUse | Each DateTime takes a block of ~34 bytes from the heap.
SeeAlso | See also RealTimeClock


Day

obj . Day lrarrow Int

The Day active variable holds the ‘day of the month’ number for the DateTime object, counting from 1.

Day may be set to values too large for the particular month. It will be wrapped around to a real date if Update is called.

When printing a DateTime object, you can choose whether to print the date as you have entered it, or a guaranteed-real date. See Printing and Update.

LIMIT

Day can hold from 1 to 31.


DayOfWeek

obj . DayOfWeek rarrow Int

DayOfWeek returns the day of the week, in days since Sunday. It cannot be set because it is dependent on the date. The day numbers are as follows:

Sunday | 0
Monday | 1
Tuesday | 2
Wednesday | 3
Thursday | 4
Friday | 5
Saturday | 6


Hour

obj . Hour lrarrow Int

The Hour active variable holds the hours value of the DateTime object.

LIMIT

Hour can hold 0 to 23.


Minute

obj . Minute lrarrow Int

The Minute active variable holds the minutes value of the DateTime object.

LIMIT

Minute can hold 0 to 59.


Month

obj . Month lrarrow Int

The Month active variable holds the month-number of the DateTime object, counting from 1.

LIMIT

Month can hold from 1 to 12.


Nudge

obj . Nudge(Int part , Int increment)

Nudge allows you to implement ‘digital watch’ style methods to change the date in a DateTime or RealTimeClock object.

Every time Nudge is called it will increment or decrement a single part of the date or time, rolling over if the maximum or minimum value for that field is exceeded.

The part of the date (Day, Month, Year, Hour, Minute, Second) is specified by an integer parameter, or by a character constant (which is also an integer, actually).

Part of date | Number | Letter
Day – ranging 1-31 | 6 | ‘d’
Day – only correct date range | 0 | ‘D’
Month | 1 | ‘M’
Year | 2 | ‘Y’
Hour | 3 | ‘h’
Minute | 4 | ‘m’
Second | 5 | ‘s’

All other values are ignored.

For example

Date . Nudge(0,1)

Date . Nudge(’D’,1)

are the same – increment the day.

To decrement a part of the date, use an increment of ‘-1’.

If you use values of the increment larger than 1, then this value will be added or subtracted from the date element. However if the value rolls over, it will roll over to the exact maximum or minimum value for that part of the date.

Coping with leap years with Nudge

There are two main ways of dealing with Feb 29th when entering dates.

The first (the simplest to program) is to let the DateTime object deal with it. You just write code to Nudge the DateTime, and print out the result. The down side to this approach is that you won’t be able to enter invalid dates that you intend to correct later. Also if you enter, say 29th Feb 2008 (a leap year), and then increment the year, the DateTime object will print the new date as 1st March 2009.

The second method is to tell Nudge to allow invalid dates, and to make sure the date is valid after entry is complete.

To do this you will have to print out the date elements of the DateTime object with the special format that prints invalid dates.

Use the Valid message to check if the date is OK after entry is complete.

The following procedure demonstrates both methods using characters from the serial port to Nudge a date. To use the procedure, run it and then enter any of the following characters to change the date: D, d, M, Y, h, m, s. Use the + or – characters to set increment or decrementing of the date.

To use the legal-dates-only method, never type a lower case ‘d’, and use the first printing option. Leave both PRINTs in to compare methods.

TO date_entry
LOCAL increment := 1
LOCAL date := NEW DateTime
FOREVER
[
char := serial.Get
SELECT CASE char
CASE '-'
increment := -1
CASE '+','='
increment := 1
CASE 13 ;Escape on seeing Carriage Return.
[
IF date.Valid
BREAK
PRINT "Bad date - keep trying",cr
]
CASE ELSE
[
date.Nudge(char,increment) ;Increment the date.
; Use this PRINT if you don't
; allow invalid dates to be entered.
PRINT date:0," "
; -OR- this if you do.
PRINT date:0:1

    PRINT CR
]
]
END

SeeAlso

See also Valid, PRINT, Update


Second

obj . Second lrarrow Int

The Second active variable holds the seconds value of the DateTime object. This is the number of seconds in the time and date representation, not the ‘absolute seconds’ value, which is given by Time.

LIMIT

Second can hold 0 to 59.


Time

obj . Time lrarrow Int

The Time active variable holds the ‘absolute seconds’, the number of seconds since the datum: 00:00 on 1st January 1990.

The following example shows a DateTime being created and set to the current time from the RealTimeClock:

MAKE now DateTime
now.Time := clock.Time

LIMIT | Time can hold values representing the year 2089 and beyond. Currently other elements of the DateTime object make it unwise to use dates beyond 2089.
SeeAlso | See also RealTimeClock.Time.


Update

obj . Update

The Update message is for dealing with possible invalid dates. You can put invalid dates (such as 30 Feb 2009) into the Day, Month and Year values of a DateTime. However if you read Time then of course you will always get a value that represents a valid date. However, the Day and Month values will not have been updated to corrected values. Updating Day and Month only occurs when either Time is set, or Update is used. The following two lines are equivalent and will fix invalid dates:

Now . Update

Now . Time := Now.Time

SeeAlso

See also Valid, PRINT


Valid

obj . Valid rarrow Int

Valid returns TRUE if the DateTime contains a real date, i.e. not one like 30th Feb.

SeeAlso

See also Update, PRINT


Year

obj . Year lrarrow Int

The Year active variable holds the years value of the DateTime object.

-->MAKE big_year DateTime
-->big_year.Year := 2002
-->PRINT big_year.Year
2002

LIMIT

Year can hold from 1990 to 2089


Accepting Print

PRINT TO obj , <print list>

Printing to a DateTime sets the time and date. It works in the same way as RealTimeClock. Printing to the DateTime must obey these rules:

The date comes first

You may only use ‘:’ to delimit the time

You must provide all six elements of the date/time, using numbers

It can accept just about any separator for the date and can work with the ‘short’ year, e.g. “4-1-02”.

For example:

PRINT TO dt,"06-06-2001 10:56:00"

SeeAlso

See also RealTimeClock Accepting Print.


PRINT

PRINT obj : f1 : f2

Printing a DateTime object gives the current time and date in a variety of formats. The following examples all represent 1:50pm on 12 January 1990.

f1 | Description | Layout | Example
:0 | Day, Month, Year, H(24), M, S | DD-mmm-YY HH:MM:SS | 12-Jan-90 13:50:00
:1 | Day, Month, Year, H(24), M | DD mmm 'YY HH:MM | 12-Jan-90 13:50
:2 | Day, Month, Year | DD-mmm-YY | 12-Jan-90
:3 | Hours(24), Mins, Secs | HH:MM:SS | 13:50:00
:4 | Hours(12), Mins, Secs, am/pm | HH:MM:SSxx | 01:50:00 pm
:5 | Day, Month, Year | DD-MM-YY | 12-01-90
:6 | Month, Day, Year | MM-DD-YY | 01-12-90
:7 | Day of the week | ddd | Mon
:8 | Month | mmm | Jan

If a second format specifier of value 1 is used, then the date is printed in the same style, but instead of a fully validated date being printed, the contents of the date and time registers are printed as they are:

-->dt.month:=2

-->dt.day:=30

-->Print dt, " ",dt:0:1

02-Mar-90 00:00:00 30-Feb-90 00:00:00-->

This can often be useful when entering dates, especially for leap years.

LIMIT | Format 0 is used if f1 not is supplied or f1 is greater than 8.
SeeAlso | See also printing RealTimeClock.


Digital

Object Types

Digital

The Digital object controls both individual digital channels, and groups of channels. The output state maybe set and/or the input state read. Several different digital I/O devices are supported.

The input state is generally read using the Asserted message.

The output state is generally set using On and Off, or by setting Asserted.

Summary of messages

MAKE

Asserted

High

Low

NotAsserted

Off

On

Output

Pulse

Toggle

Value

PRINT

Each Digital object is created to control a specific I/O channel, or range of channels. Digital channels on the VM-1 controller itself are numbered from 1 to 47. Channels on PCF8574 ICs on the I2C Buses are detailed in the table below:

I2C Device | Address inputs: A2 A1 A0 | Channel Numbers I2C Bus 1 | Channel Numbers I2C Bus 2
PCF8574 | 000 | 128 - 135 | 384 - 391
PCF8574 | 001 | 136 - 143 | 392 - 399
PCF8574 | 010 | 144 - 151 | 400 - 407
PCF8574 | 011 | 152 - 159 | 408 - 415
PCF8574 | 100 | 160 - 167 | 416 - 423
PCF8574 | 101 | 168 - 175 | 424 - 431
PCF8574 | 110 | 176 - 183 | 432 - 439
PCF8574 | 111 | 184 - 191 | 440 - 447
PCF8574A | 000 | 192 - 199 | 448 - 455
PCF8574A | 001 | 200 - 207 | 456 - 463
PCF8574A | 010 | 208 - 215 | 464 - 471
PCF8574A | 011 | 216 - 223 | 472 - 479
PCF8574A | 100 | 224 - 231 | 480 - 487
PCF8574A | 101 | 232 - 239 | 488 - 495
PCF8574A | 110 | 240 - 247 | 496 - 503
PCF8574A | 111 | 248 - 255 | 504 - 511

Formula for channel number of a digital on a PCF8574 on an I2C Bus:

Bus * 256 - 128 + Address * 8 + PCF8574A * 64 + PCF8574_Pn

Where:

Bus is the I2C Bus number (1 or 2)

Address is the binary value of the address bits on the IC (A0 + 2*A1 + 4*A2)

PCF8574A is 1 if the IC is an ‘A’ suffix, else 0.

PCF8574_Pn the port number on the IC, 0 - 7.

Reading the input value of a device that is not present

Note: if digital channels are assigned to a PCF8574 device that is not present on the I2C Bus, then the MAKE will not give an error, but reading the input value of the channels will yield 1 or ‘not asserted’ because the default state of the bus is pulled high.


Creation

MAKE obj Digital(Int channel , Int channel2)

Single channels or groups of channels (ports) may be created on the different devices available. If only the first parameter is specified then a single channel digital I/O driver is created.

If the second parameter is also specified then a group of digital I/O channels from channel to channel2 inclusive, is created. These may be accessed as a single port. Port channels must be within the same 8-bit group, eg. 128 - 135 but not 129 - 136. Digital ports are not possible on channels 1 - 47 on the VM-1 itself.

Example makes:

MAKE channel Digital(17) ;A digital I/O on VM-1 Channel 17

MAKE port Digital(128,131) ;A 4 channel port on the 1st I2C bus

When accessing multiple channel ports, the Value message is the most useful.

TimingIcon | Channels grouped into a port are guaranteed to reach a new state with only as much skewing as the hardware of the digital I/O device itself introduces (often only nanoseconds).
memoryUse | Digital is a Zero-Memory object


Asserted

obj . Asserted lrarrow Flag

The Asserted active variable holds the state of the digital channel. The channel is turned on when Asserted is set TRUE and off when Asserted is set FALSE. When it is read, Asserted returns TRUE or FALSE depending on whether the channel is On or Off, respectively. Whether or not the channel is an input or an output, Asserted returns the state of the channel as if it were an input – i.e. it reads the actual voltage level rather than ‘what it ought to be’.

Example:

TO thermostat
MAKE heater digital(32)
EVERY 1000
heater.Asserted := temperature < 50
END

Groups

For groups of channels, setting Asserted will set the whole group to the requested state, and reading Asserted returns FALSE if any of the channels are in the Off state, TRUE if all the channels are in the On state.

SeeAlso | See also NotAsserted, On, Off, High, Low, Output
Hardware | On the VM-1 controller, The 'on' state of all the digital outputs is low - or 0V. This is also true for the PCF8574 digital I/O ports on the I2C Bus. However, on your Application Board the 'on' state could be high or low, depending on the logic of your output circuits.


High

obj . High

High sets the digital channel to its high voltage state - as seen at the output of the VM-1 or PCF8574. If the channel is not already specified as an output channel, this message sets it to be an output.

PCF8574 I/O are ‘pseudo tri-state’, so setting a channel to high is the same as setting it to be an input.

For groups of channels (ports), High sets the whole group into the high voltage state.

SeeAlso

See also On, Off, Low, Output, Asserted


Low

obj . Low

Low sets the digital channel to its low voltage state - as seen at the output of the VM-1 or PCF8574. If the channel is not already specified as an output channel, this message sets it to be an output.

For groups of channels (ports), Low sets the whole group into the low voltage state.

SeeAlso

See also On, Off, High, Output, Asserted


NotAsserted

obj . NotAsserted lrarrow Flag

The NotAsserted active variable holds the inverse state of the digital channel. When setting NotAsserted, the digital channel is turned on when NotAsserted is set FALSE and off when NotAsserted is set TRUE. When read, NotAsserted returns FALSE or TRUE depending on whether the channel is On or Off, respectively. Whether the channel is an input or an output, NotAsserted returns the inverse state of the channel as if it were an input.

For groups of channels, setting NotAsserted will set the whole group to the requested state, and reading NotAsserted returns TRUE if any of the channels are in the Off state, FALSE if all the channels are in the On state.

-->TO thermostat
MAKE d digital(32)
FOREVER
d.NotAsserted := temperature > 50
END

SeeAlso

See also Digital.Asserted.

Hardware

On the VM-1 controller, The 'on' state of all the digital outputs is low - or 0V. This is also true for the PCF8574 digital I/O ports on the I2C Bus. However, on your Application Board the 'on' state could be high or low, depending on the logic of your output circuits.


Off

obj . Off

Off sets the digital channel to its inactive state, which is high for all the devices presently supported. If the channel is not already specified as an output channel, this message sets it to be an output.

PCF8574 I/O are ‘pseudo tri-state’, so turning a channel Off is the same as setting it to be an input.

For groups of channels (ports) Off sets the whole group into the inactive state.

SeeAlso | See also On, High, Low, Output, Asserted
Hardware | On the VM-1 controller, The 'on' state of all the digital outputs is low - or 0V. This is also true for the PCF8574 digital I/O ports on the I2C Bus. However, on your Application Board the 'on' state could be high or low, depending on the logic of your output circuits.


On

obj . On

On sets the digital channel to its active state, which is low for all the devices presently supported. If the channel is not already specified as an output channel, this message sets it to be an output.

For groups of channels (ports) On sets the whole group into the active state.

SeeAlso | See also Off, High, Low, Output, Asserted
Hardware | On the VM-1 controller, The 'on' state of all the digital outputs is low - or 0V. This is also true for the PCF8574 digital I/O ports on the I2C Bus. However, on your Application Board the 'on' state could be high or low, depending on the logic of your output circuits.


Output

obj . Output lrarrow Flag

The Output active variable allows the I/O direction of a channel or port to be set or read. Setting Output TRUE makes the channel or port into an output, and setting Output FALSE makes the channel or port into an input. Output returns TRUE or FALSE depending upon whether the port or channel is currently an output or an input respectively. If there is a mixture of inputs and outputs in a port, Output will return TRUE. Digital channels on PCF8574 ICs on an I2C bus always return TRUE for Output because they are only ‘pseudo tri-state’ devices.

TimingIcon

The I/O direction of channels in a port are guaranteed not to be skewed, up to the limit defined by the hardware.


Pulse

obj . Pulse

Pulse momentarily pulses the channel or set of channels to their opposite state.

If the channel is not already specified as an output channel, this message sets it to be an output.

MAKE d digital(128)
d . Pulse

TimingIcon

The pulse width is guaranteed to be longer than 1 μS, but could be considerably longer than this, depending on how long it takes to write to the digital port.


Toggle

obj . Toggle

Toggle flips the state of a digital channel from On to Off and vice versa. For groups of channels, the states of all the channels are flipped.

If the channel is not already specified as an output channel, this message sets it to be an output.


Value

obj . Value lrarrow Int

Value holds the numeric representation of the state of the channels in a port made up from a single channel or group of channels. A high state is a binary 1 and a low state is a binary 0.

The least significant bit of the number is given by the state of the lowest numbered channel in the port.

When setting Value, if the channel is not already specified as an output channel, this message sets it to be an output. Also, reading Value will return the numeric representation of the levels actually on the channels, whether the port is inputs or outputs.

LIMIT | Usefully uses values in the range 0 to 2n - 1, where n is the number of channels in the port. Binary bits in the value that overflow the port size are masked off.
TimingIcon | Output to multi-bit ports is guaranteed not to be skewed up to the limit defined by the hardware.


Printing

PRINT obj :f1

If no format specifier is used, the state of the channel or port (as defined in Asserted) as "ON "or "OFF", always with 3 characters is printed

MAKE d Digital(128)
PRINT d
OFF

d.On
PRINT d
ON

If a format specifier greater than zero is supplied, then the object is printed like this, where the number is the value of Value.

PRINT d:3
[Digital: 0]

SeeAlso

See also Asserted, Value.


FileSystem

Object Types

FileSystem

FileSystem is a filing system manager. It can currently handle two different types of file system:

· (Venom release 20080116 and earlier only) on board RAMdisk using a proprietary filing system in the non-volatile RAM area.
· FAT file system compatible with DOS and Windows and suitable for MMC/SD memory cards. This currently supports a driver for memory cards that can use SPI mode: MultiMedia Card (MMC) and Secure Data (SD). Since Venom release 20080116 it is also used on RAM disk and it is designed to be adaptable in the future to other storage devices should the need arise.
· (Venom releases after 20080116) RAM disk using the DOS/Windows FAT file system.

The type of file system is automatically selected on creation by the device specified.

While the two types of file system handle many of the same messages in broadly compatible ways, there are many differences in their capabilities and limitations, hence the two types of FileSystem objects are described in separate sections.

Message to File objects are very similar for either file system and these are described in one section, with any differences mentioned where they apply.

SeeAlso

For all details of FileSystem and File creation and messages see:

Filesystem (RAM)

FileSystem (FAT)

FileSystem:File


FileSystem (Old RAMdisk)

Object Types

FileSystem (Old RAMdisk)

Note: this description only applies to Venom Releases up to and including 2008 01 16

The RAM file system device uses an area of memory reserved for use as non-volatile memory, and in releases of Venom up to and including 2008 01 16 implements a simple filing system with a single directory, allowing file names up to 15 characters long. In later releases the FAT file system is used: please go the FAT File System section

Summary of messages

MAKE

Count

Debug

Free

Find

Name

Open

Remove

Status

Reset

Time

PRINT

SeeAlso See also: Notes on Using RAM FileSystem


Notes on Using RAM FileSystem

Note: this description only applies to Venom Releases up to and including 2008 01 16.

For later releases see FAT Filing System when using RAM disk

Multiple access to same file

A file can be opened only once, so a file object has only one read and write point. It is an error to open a file that is already open, however there is nothing to stop you copying a fatfile variable or having multiple tasks access a file through the same global file variable.

If a file variable is copied to another variable and the file is then closed, access is no longer possible using either variable

Example

-->a := ramfs.open("aaa", "")

-->b := a

-->a.close

-->b.put(0)

Run-time error 20: Message to dead object

at $2652D6 in the command line (line~1?)

HELP filevar with a file variable will show the associated file name.

PRINT fs where fs is a FileSystem variable will show open files marked with '*' next to the name.

Keeping Track of Open Files

In a properly constructed Venom program, it should be known which files are open at any point. During debugging and experimentation at the command line, however, things can go wrong. Here are some ways out of trouble.

Open files with no Variable Attached

It is quite easy to open a file associated with a variable, then accidentally use that variable for something else, with the result that the file is still open, and cannot be used or closed because the file system forbids opening a file twice.

A FileSystem Reset message will force all files closed and is a temporary way of getting out of this situation from the command line. The file system initialization when the VM-1 is started also clears this condition.

Of course a variable should not be re-used in this way in a well-written program.

Timing Information and Numerical Limits

General Limits

LIMIT | Maximum Ram disk size | Memory limit or 16Mb
 | Number of files | Memory limit
 | Number of files open at once | 50
 | File size | Memory limit or 16Mb
 | File name Length | 15 characters
 | Block Size | 512 bytes
 | File system overhead in RAM disk | 1.5Kb
 | File creation overhead | 0.5Kb for empty file 0.5Kb for each 512 bytes of file data
 | Larger system overheads | An extra block (0.5Kb) per extra 18 files An extra block (0.5Kb) per extra 128 bytes of file size

Timing

These timings are averages measured by timing multiple transfers.

TimingIcon | Operation | Approx. Time (µs)*
 | put 1 byte | 195
 | get 1 byte | 175
 | put 16 bit word | 200
 | get 16 bit word | 177
 | put 20 char string | 382
 | put 60 char string | 684
 | lock + unlock | 230
 | fs.free | 140

*note: all timings are subject to change.

Errors

Run Time error messages generated in the FileSystem are listed here.

Code checking error - Error number 25

Please report this to Micro-Robotics: it means that an internal consistency or bounds check has failed.

File Access error - Error number 26

This typically covers Venom Programming errors, for example:

· Read past end of file
· Access a closed file
· Attempt to delete an open file
· Access a file when the filing system has been destroyed
· Opening too many files (the limit is currently 50)
· Opening the same file twice
· File name too long (max 15 characters)

Resource Error - Error number 27

Problem with allocating memory, e.g.

· Asking for a RAM disk too big to fit into the area reserved for non-volatile memory. Either request a smaller disk or resize the non-volatile area (see The System.Free(2) message for details)
· Not enough system memory to allocate storage for file control information. This simply means you have used all the memory up with your program and data.


Creation

Note: this description only applies to Venom Releases up to and including 2008 01 16

For later releases see FAT Filing System when using RAM disk

MAKE ramfs FileSystem("RAM", Int size)

When "RAM" is specified as the device, a proprietary file system is created, which minimizes memory overheads and only has one directory.

size Specifies the size of memory in bytes to be used by the file system.

memoryUse

Before a file system can be created, an area of non volatile memory must be reserved using the System.Free(2) message. These two statements would normally follow each other in the init procedure. (see example below)

As a rough guide, the size required is 1536 bytes + 512 bytes per file + space for data in the files themselves. The smallest file system that can be created is 5 blocks, 2560 bytes, which allows 1 very small file.

If the size requested is not a multiple of 512 bytes, the nearest such multiple below the requested size is used. It is guaranteed that if the size requested is the same as the memory size specified when setting Free(2) the file system will just fit into the reserved memory, and if that size is a multiple of 512 there will be no wastage. For example:

; file system fits in 50k

Free(2) := 50 * 1024

MAKE fs FileSystem("RAM", free(2))

SeeAlso

See also System.Free(2)

If a file system of the specified size already exists, the object is associated with it.

If no file system previously existed, one is created with the size specified.

If an existing file system in RAM has a different size, it is silently destroyed and replaced with a new one.

If the size is specified as 0 and a previous file system existed, the previous file system is used. Note that this option should only be used manually at the command line in an emergency i.e. if the size of the old file system is unknown and data needs to be retrieved from it. Production programs should not rely on this feature.

Example

MAKE fs FileSystem("RAM", 40960)


Count

ramfs.Count rarrow Int

Returns the number of files in the file system.


Debug

The Debug message is usually reserved for internal use by Micro-Robotics, but the Venom command line user may find the debug message to file system useful. For each open file in the system, it lists the name, size, read point and write point.

Example

-->ramfs.debug

Open files:

name "aaa" size=20 r=0 w=20

name "bbb" size=20 r=0 w=20

name "ccc" size=40 r=0 w=40

-->


Find

ramfs.Find(str name) rarrow Int

name is a string or text buffer.

Returns true (-1) if the name file exists, or false (0) if not. It does not matter whether the file is open or not. The file name must match exactly: it is case sensitive and wildcards are not supported.


Free

ramfs.Free rarrow Int

Returns the amount of free space in the file system. Note that the space available for file data is less than this because creating files uses some space for housekeeping information.


Name

ramfs.Name(Str old, Str new) rarrow Int

Renames file from old name to new name. Returns logical true if successful, meaning that a file with the old name existed. If the new name is invalid, a “File Access” runtime error occurs.

old and new can be strings (constant or object) or text buffers.

It does not matter whether the file is open or not when renaming.


Open

ramfs.Open(Str name, Any Prototpye [, Int maxlength]) rarrow file object

Creates a file variable

SeeAlso

See also FileSystem:File sub-object for more information on files.

name - is the name of the file and can be either a string or a text buffer. Upper and lower case letters and numerals are allowed in the file name, as are the following punctuation characters:

! $ % - _ + ~ . / #

The maximum file name length is 15 characters.

File names are case sensitive.

Note that '/' and '.' are not interpreted in any special way, and that this file system does not support subdirectories.

Prototype denotes the data type of the file contents and is one of the following:

prototype | Element Type
0 | Run length compressed data
8 | 8-bit unsigned integer
16 | 16-bit signed integer
32 | 32-bit signed integer
1.0 * | Floating point
“” ** | Text

*or any floating point number. **or any string value.

If a file with the same name exists, it is opened with the read pointer set to the beginning of the file and the write pointer set to the end of the file. If no file existed, an empty file is created.

If a third parameter maxlength is given, it sets a maximum length for the file. If created this way, any write to the file that results in its length exceeding that value will cause the first 512 bytes to be removed from the file. This is useful for log files where only recent data is of interest, and in such cases can remove the need for extra housekeeping code to prevent the file system from running out of space. Note that the maxlength parameter is in bytes and is mainly intended for use with text files. This parameter, if specified, must not be less than 1024.

Example

a := fs.open("abcde.txt", "") ; a text file

b := fs.open("numbers", 1.0) ; a float file

Empty file is created with read and write pointers at 0.


Remove

ramfs.Remove(str Pattern) rarrow Int

pattern is a string or a text buffer.

Files with names matching the pattern are deleted. The pattern may include '?' which matches any character in that position in the file name, and '*' which matches any characters from that position onwards in the file name.

The value returned is the number of files removed in the operation.

A file must not be open when the Remove message applies to it.

If the Remove message is sent to a file system with a wildcard filename specification and some of the files whose names match are open, there will be a run time error when the first such file is encountered.

Example

-->PRINT fs.remove("temp*"), " files deleted", CR

3 files deleted

-->


Status

fs . Status rarrow Int

Returns a bitmapped value with bits set as follows:

1 - valid ramdisk

4 - the last MAKE statement created a new RAM disk

8 - error were encountered when the RAM disk was initialised

Errors during initialisation include:

· error in free space allocation (doesn't complement space occupied by files)
· error in file navigation (file is deleted)
· cross linked files


Time

ramfs.Time(str name) rarrow Int

name

String or text buffer holding name of file

Returned value is time in seconds, compatible with DateTime and RealTimeClock objects.

The value corresponds to the time and date when the named file was created or last modified.

If the file does not exist, a value of 0 is returned.

If there was no real time clock hardware present when the file was created or last modified, the result will be 0.

This message allows the creation/modification time of a file to be found without having to open it.

The timestamp of a file cannot be changed using this Time message. If you want to force a change to a file's timestamp, open the file and use the file's Time message.


Reset

ramfs.Reset

When a FileSystem variable is created and a previously existing FileSystem is found, a check is performed, which forces closed any files marked open, rebuilds the free space list by counting the space occupied by files and management data and deletes any cross-linked files.

The FileSystem Reset message runs the same check. Note that any open files are forced closed, which makes this message useful when debugging in a command line session if a file has become open without a variable associated with it, as it is then the only way (short of a system reset) to close the file.


PRINT

Print ramfs[:Int n [: Str separator]]

Lists the files in the system in various formats dictated by the optional colon and number. If no format code is used the result is the same as :3.

:0 - list file names only, one per line, separated by CR LF

:0:str - list files separated by separator string other than new line

:1 - list file names and size in bytes, one entry per line

:2 - List size in bytes if less than 10000, else size in kilobytes

:3 (default) - As :2, add heading and tail line showing free space, and marking with a '*' any files that are open.

:9 - produces a UNIX-style listing (used internally for FTP)

Note that the format code of 0 used when printing to a buffer results in a list of file names that can easily be used by a program.

Example

-->print ramfs

RAM Filesystem files:

aaaaa * 23k

bbbbb 456

cccc 126k

Free space 488 blocks = 249856 bytes

-->print ramfs:1

aaaaa 24000

bbbbb 456

cccc 130000

-->print fs:0:" "

aaaaa bbbbb cccc-->


FileSystem (FAT)

Object Types

FileSystem (FAT)

The FAT file system is used on devices that are expected to support it: currently MMC and SD memory cards, and RAM disks in Venom Releases after 2008 01 16

It is compatible with the Windows VFAT file system for both FAT16 and FAT12 formats.

Please read Notes on Using FAT FileSystem before using.

Summary of messages

MAKE

Count

Empty

Free

Name

Open

Remove

Reset

Time

Valid

PRINT


Notes on Using FATFileSystem

File Names

File names in the FAT system are Windows compatible as long as the ASCII or ISO-8859-1 (Latin-1) 8 bit character sets are used.

There is no support for 16 bit characters in either UTF16 or UTF8 encodings.

Directory Separator

In filenames that specify directories, the character '/' is used to separate directory names from each other and from the final file name. This is the same convention as used in UNIX. Use of "\" as in DOS/Windows would be inconvenient in Venom as it is a special string escape character and would have to be written as "\\" every time it was used.

Any path may optionally include a '/' character at the beginning. The root directory is assumed regardless.

The maximum length of a file name including path information is 260 characters.

Wildcards and File Name Matching

Several of the file system and file messages can use wildcard specifications in file names. The special wildcard characters are:

"?" matches any single character

"*" matches zero or more of any character

For example, the pattern "*" will match any file name.

"*.txt" will match any file name that ends in ".txt".

"abcd.???" will match any file name that consists of "abcd." followed by exactly three more characters.

"*2*" will match any file name that contains a "2" anywhere.

Names are stored with case of letters preserved, but file name matching is case-insensitive.

Root Directory Limitation on Number of Files

Programs which create files dynamically and are liable to create a large number of files, especially with long names, should create them in a subdirectory.

The reasons for this are:

· A single entry will hold the directory information for a file with a DOS compatible name in 8.3 format with all letters uppercase.
· For longer names or anything with lower case or non-ASCII characters, an extra entry per 13 characters of file name is used.
· Frequent renaming, deleting and adding files can fragment the directory.
· The root directory is fixed as 512 entries for hard disks and memory cards, much less for RAMdisk
· Subdirectories can contain more file entries, to a maximum of 65535 (theoretically) or as limited by RAM or memory card space.

Multiple access to same file

BugAlert A file should be opened only once, so a file object has only one read and write point. No run time error is generated if you attempt to open the same file in two variables. You can copy a file variable or have multiple tasks access a file through the same global file variable. If one task is writing to a file and the other is reading, all updates and additions to the file can be seen by the reading task immediately.

If a file variable is copied to another variable and the file is then closed, access is no longer possible using either variable

Locking

The FAT file system is locked internally during the processing of any message that is likely to involve reading or writing the media, in order to serialize access to the media. This enables separate tasks to access files in the same system with no data corruption. You can lock the whole filing system, for example if you need to guarantee that the contents of a directory will not be changed by another task during a sequence of operations. Locking a file is more often useful, so that different tasks can write to the same file. Printing to a file locks the file automatically for the scope of the PRINT statement..

Storage Media Considerations with MMC/SD cards

The FAT file system works with a block device driver to access the physical media. Because reading and writing the physical media can be time consuming the file system implements block cacheing so that recently and frequently used data blocks are retained in memory. Blocks that have been modified are always written to the media when a file is closed. The programmer has facilities to force writing to media at other times in order to ensure that the data is safe from loss by power failure or physical media removal.

With removable storage media, the device driver can inform the file system of media removal and the file system takes appropriate action including invalidating all the cached blocks.

The driver can also tell the file system if the media is write protected and will block any attempt to write to the media.

Removable Media

Special considerations apply to removable media such as memory cards.

A FileSystem object can be created with no media present. Similarly there is no problem if the media is removed or changed while no file is open. When the card is replaced or changed, the next access to the file system will silently reset and reload its parameters from the card.

If a memory card is removed while a file is open, even if the card is subsequently replaced or a different card inserted, the next attempt to access any open file will have the following results:

· all open file variables will die
· The block cache will be destroyed
· A "Device Not Found" run time error 12 will be generated

The presence of a card can be detected without generating runtime errors by use of the Status or Valid messages.

If supported by the hardware, the file system will illuminate an indicator light whenever a file is open or data is being transferred, warning the user not to remove the media.

Power Loss

When writing to a file, media removal or power loss can result in loss of data.

Closing a file and re-opening it will guarantee that the data is written to the medium and that the directory entry is updated with the file's size. The Flush message achieves this without the need for closing the file. Either method involves time-consuming extra media access, so the programmer must make a judgment about how often and when to use the Flush message.

For RAM disk based file systems, the Flush message is still useful for updating the directory entry, but other data is written directly.

Errors

Run Time error messages generated in the FileSystem are listed here.

Code checking error - Error number 25

Please report this to Micro-Robotics: it means that an internal consistency or bounds check has failed.

File Access error - Error number 26

This typically covers Venom Programming errors, for example:

· Read past end of file
· Access a closed file
· File name too long (max 260 characters) or contains illegal characters
· Attempt to open a file in a non-existent subdirectory
· Attempt to open too many files in root directory

Device Not Found - Error number 12

This is generated:

· if MAKE specifies a device with the wrong interface type or a non-existent partition number
· on the first attempt to access a file if the media was removed and/or replaced

Note that MAKE will succeed on a removable media device like a memory card holder even if there is no media present.

The media must be present before the software attempts to open any file.


Creation

For MMC/SD Cards

MAKE fatfs FileSystem("MMC"[, Int unit[ ,Int partition[, Int cachesize]]])

"MMC" | specifies a device driver for SPI compatible memory cards: MMC (Multi Media Card) or SD (Secure Data).
unit | (default: 0) selects a bus or specific card slot if there is more than one. Default value 0.
partition | (default: 0) selects a partition if the device has a partition table. Most MMC cards are formatted with a partition table and a single partition which is selected as partition 0.
cachesize | Specifies the amount of memory in bytes to use for block cacheing. The default is half the largest single block of free memory (as reported by System.Free(1)). The minimum allowable value is 2048; if less is specified the default is used instead.

Hardware

The details of device selection depend on fitted hardware. Currently unit 0 is the VM-1's standard SPI bus connection and unit 1 is a high speed implementation that uses serial port 2. Both connections are available on the Micro-Robotics memory card interface, product code 5815.

If a memory card is present, a file system must already exist on the memory card. Both FAT12 and FAT16 formats are supported, but currently not FAT32.

If a memory card is not present, a file system framework will still be created, but a card must be present before any I/O is performed or a run time error will then result.

Example

MAKE fatfs FileSystem("MMC", 0, 0)

memoryUse

Creating a FAT Filesystem initially uses 1174 bytes of memory.

The block cache additionally uses half the available free memory by default, or the amount specified.

For RAM Disk

MAKE ramfs FileSystem("RAM", Int size)

"RAM" | Indicates that we are using a RAM disk for storage
size | Size of RAM disk in bytes. Minimum 2048, Maximum 1048064. For predictable results, make this a multiple of 512

Rough Guide to allocating RAM disk space

Table of approximate filing system overheads versus RAM disk size.

Overhead | RAM disk size | Root Directory Entries
2k | 2k - 20k | 16 or 32
3k | 20k - 50k | 48 or 64
4k | 50k -150k | 80 or 96
5k | 150k - 500k | 96

Notes:

· File data is allocated in 512 byte blocks, so allow extra space for "slack" in unfilled blocks at the end of files.
· Space for the root directory is fixed for a given RAM disk size, as shown in the table.
· A file may use more that one directory entry - see Root Directory Limitation


Count

fatfs.Count [(string pattern)] rarrow Int

pattern specifies a subdirectory and optionally also a filename or wildcard pattern. It can be a text buffer or fixed string.

Return value: the number of files in a directory. If none is specified the root directory is counted.

Both plain files and subdirectories are counted.

If the pattern specifies a directory all entries in that directory are counted.

If the pattern specifies a plain file name or a wildcard, the number of matching names is returned.

SeeAlso See also: Wildcards and File Name Matching


Debug

fs.Debug(Int a, Int b) rarrow Int

a | b |  |
1 | block number | Read a block from MMC card and display on screen |
2 | - | Display filesystem information: size, cluster size, position of FAT and root directory etc. |
4 | 1 | Return no. of blocks in cache | MMC/SD cards only (not RAM disk)
4 | 2 | Return memory used by cache
4 | 3 | Return number of cache hits
4 | 4 | Return number of cache misses
12 | 0 | Return no. of block reads from card
12 | 1 | Return no. of block read errors
12 | 2 | Return no. of block read resets
12 | 3 | Return no. of block writes to card
12 | 4 | Return no. of block write errors
12 | 5 | Return no. of block write resets

Notes on block read/write statistics for MMC/SD cards:

If a read or write operation fails, an error is counted and the operation is retried up to six times.

After the third failed attempt, the card is reset (re-initialised) and a "read reset" or "write reset" is counted.

We have found that some cards occasionally get a read error which recovers on the second attempt, and a rare instance of a write failure that required a reset. These count values may help to indicate the reliability, compatibility or state of wear of a particular card.

The counts are reset when the file system is created or recreated, including after sending a reset message to the file system or if the card is removed and replaced.


Find

fatfs.Find(string name) rarrow Int

name is a string or text buffer.

Returns true (-1) if the named file or directory exists, or false (0) if not. It does not matter whether the file is open or not.

The name can also be a wildcard specification, testing for the existence of at least one matching file.

SeeAlso See also: Wildcards and File Name Matching


Empty

fatfs.Empty

This message wipes the FAT and root directory of the file system, leaving it empty.

It is like a DOS/Windows "quick format".

Use of this message guarantees restoration of a valid file system if it has become corrupted by a program crash, card removal or power failure while the file system was in use, at the cost of loss of all files.


Free

fatfs.Free rarrow Int

Returns the amount of free space in the file system, in bytes.

It is calculated from the number of FAT entries marked free.


Name

fatfs.Name(Str old, Str new) rarrow Int

Renames or moves file from old directory and name to new. Returns logical true if successful, meaning that a file with the old name existed. If the new name is invalid, a “File Access” runtime error (error no. 26) occurs.

old and new can be strings or text buffers.

BugAlert

The file must not be open for writing when renamed in this way. The programmer is responsible for this - the condition is not detected automatically by the file system.

Note that the full path of the new file name must be specified even if it is in the same subdirectory as before.

The old and new names can be in different directories in the file system, resulting in the file being moved without its data having to be copied. A directory can also be copied to a new location, in which case all files and lower directories under it appear in the same structure under the new location.

A directory obviously cannot be moved to a subdirectory of itself and an attempt to do so results in a run time error.


Open

fatfs.Open(Str name, Any Prototpye [, Int maxlength]) rarrow file object

Creates a file variable

SeeAlso

See also FileSystem:File object for more information on files in the FAT file system.

name is the name of the file and can be either a string or a text buffer. Upper and lower case letters and numerals are allowed in the file name, as are all characters with code values over 127 and the following special characters:

! $ % - _ + ~ . / # ' @ ( ) { } & , ; = [ ]

The maximum path and file name length is 260 characters.

The case value of letters in the file name is stored unchanged when the file is created new, but the process of matching for an existing file name is not case sensitive.

A file can be created in a subdirectory by specifying its full path. The subdirectory must exist first. You can create a subdirectory by using the special element prototype 'd' or "D" (see below).

When specifying a file in a subdirectory, the character '/' is used to separate directory names. This is the Unix convention as opposed to the Windows/DOS convention and is more convenient as '\' is used as an escape character in Venom strings.

Prototype denotes the data type of the file contents and is one of the following:

prototype | Element Type
0 | Run length compressed data
8 | 8-bit unsigned integer
16 | 16-bit signed integer
32 | 32-bit signed integer
1.0 * | Floating point
“” ** | Text
'd' or 'D' | File is a subdirectory.

*or any floating point number. **or any string value.

If a file with the same name (ignoring case) exists, it is opened with the read pointer set to the beginning of the file and the write pointer set to the end of the file. If no matching file existed, an empty file is created.

If a third parameter maxlength is given, it sets a maximum length for the file. If created this way, writing beyond that length will cause data to be removed from the beginning of the file. This is useful for log files where only recent data is of interest, and in such cases can remove the need for extra housekeeping code to prevent the file system from running out of space.

LIMIT

Note that the maxlength parameter is in bytes and is mainly intended for use with text files. This parameter, if specified, must not be less than 1024. In the FAT file system the actual file size may be considerably bigger than specified as it is truncated to a whole non-zero number of FAT clusters, and a cluster can be as big as 32k.

Example

a := mmc.open("abcde.txt", "") ; a text file in the root directory

b := mmc.open("/data/numbers", 1.0) ; a float file in the subdirectory /data

Empty file is created with read and write pointers at 0.

Errors When Opening a File

Following are some possible reasons while opening a file could fail:

· Invalid file name - must only contain valid characters. See above.
· Too many slots in root directory. This can happen when you create many files with long names, especially in a RAM disk where root directory size is limited. see Creation (RAM disk) and table of root directory sizes. For solutions to this problem, try (a) fewer files, (b) shorter file names, (b) putting files in a subdirectory where directory size is limited only by total ramdisk space.
· Subdirectory does not exist. When creating a file in a subdirectory, you must create the subdirectory first if it did not exist.
· Trying to open an existing plain file as a directory or vice versa.
· File system full.


Remove

fatfs.Remove(str pattern) rarrow Int

pattern is a string or a text buffer.

Files with names matching the pattern are deleted.

If the pattern matches a directory, the directory and all its contents, including subdirectories, are removed

The value returned is the number of files removed in the operation.

BugAlert

A file must not be open when the Remove message would apply to it. This condition is not detected and it is the programmer's responsibility to avoid it.

Example

-->PRINT fs.remove("temp*"), " files deleted", CR

3 files deleted

-->PRINT fs.remove("data/logs") log files deleted", CR

10 files deleted

-->

(it is assumed that /data/logs is, for example, a directory containing 9 files)


Reset

fatfs.Reset

This performs the same actions as when the memory card or other removable media are removed and re-inserted (or a different card inserted)

· Any open files are forced closed and become "dead" objects
· The memory used by the file system is freed
· The file system is recreated by detecting and reading the card or media

For RAM disks, only the first of the above actions is performed.


Status

fatfs.Status rarrow Int

(FAT file system only)

The value returned is a bit mapped combination of the following values:

1 Valid media and file system
2 Media write protected (e.g. SD card 'lock' tab)
4 New media (removed and replaced)

For RAM disks, only the first of the above bit values is applicable.


Time

There are two distinct uses of the File System Time message

Getting a File's Time and Date

fatfs.Time(str name) rarrow Int

name

String or text buffer holding name of file

Returned value is time in seconds, compatible with DateTime and RealTimeClock objects.

The value corresponds to the time and date when the named file was created or last modified.

If the file does not exist, a value of 0 is returned.

If there was no real time clock hardware present when the file was created or last modified, the result will be 0.

This message allows the creation/modification time of a file to be found without having to open it.

The timestamp of a file cannot be changed this way. If you want to force a change to a file's timestamp, open the file and use the file Time message.

SeeAlso See also: File Time message

Defining the Source of Time/Date Information

fatfs.Time(Int source)

source

code defining sources for time and date

0 : set time and date to zero

1 : use internet time servers only

2 : use RTC only

3 : try both (the default state)

Rarely, this message should be used after creating the filesystem.

By default, when the file system needs to write a time and date setting to a directory entry, it will attempt to get a timestamp based on internet time servers, or failing that using the VM-1 Real Time clock/calendar if fitted. The absence of a network interface or real time clock is detected easily and quickly.

An unusual configuration is possible, however, where an ethernet connection exists and a DNS server is defined, but there is no connection to the internet. In such a system, the attempt to get the internet time can take 30-40 seconds to fail. To prevent this, use the Time message with a parameter of either 0 or 2 to skip any attempt to use internet time servers.

SeeAlso

See also:

File Close

RealTimeClock object

UDP Time message


Valid

fatfs.Valid rarrow Int

(FAT file system only)

The returned value is True (-1) if the file system is valid. In particular this tests for the presence of removable media such as memory cards.

For MMC/SD, if a memory card was removed and replaced, the Valid message will return a value of 0 at least once.

SeeAlso See also Status which returns more information about the file media.


PRINT

Print fatfs[:string pattern] [: Int format]

Lists the files matching pattern in various formats dictated by the optional colon and number.

pattern (default: root directory) | If this specifies a directory, the contents of that directory are listed. If it specifies a plain file or wildcard, only matching entries are listed.
format (default: 2) | Specifies the listing format, as described in the table below.

Listing Formats

code | Description | Example
0 | One file name per line, separated by CR LF | test.txt test.8 dir1
1 | Full path and name of file, including directories, one per line | dir1/test.txt dir1/test.8 dir1/dir2
2 | size, date, time, file name (default) | 1280 11/02/1990 19:46:38 test.txt 100 11/02/1990 13:38:34 test.8 <DIR> 11/02/1990 15:13:48 dir1
3 | As 2 but full path and name of file | 1280 11/02/1990 19:46:38 dir1/test.txt 100 11/02/1990 13:38:34 dir1/test.8 <DIR> 11/02/1990 15:13:48 dir1/dir2
4 | Recursive listing (i.e. lists all subdirectories) of full paths | test.txt test.8 dir1 dir1/test.txt
5 | Recursive listing with size, date, time, full path | 1280 11/02/1990 19:46:38 test.txt 100 11/02/1990 13:38:34 test.8 <DIR> 11/02/1990 15:13:48 dir1 1280 11/02/1990 20:30:02 dir1/test.txt
6 | As 2 but also show file attributes | 1280 A 11/02/1990 19:46:38 test.txt 100 A 11/02/1990 13:38:34 test.8 <DIR> D 11/02/1990 15:13:48 dir1
7 | Recursive listing with attributes | 1280 A 11/02/1990 19:46:38 test.txt 100 A 11/02/1990 13:38:34 test.8 <DIR> D 11/02/1990 15:13:48 dir1 1280 A 11/02/1990 20:30:02 dir1/test.txt
8 | Windows command line default DIR format: date, time, size or <DIR>, name | 11/02/1990 19:46 1280 test.txt 11/02/1990 13:38 100 test.8 11/02/1990 15:13 <DIR> dir1
9 | UNIX "ls -l" style listing (used internally by FTP server) | -rw-rw-rw- 1 vm1 vm1 1280 Feb 11 1990 test.txt -rw-rw-rw- 1 vm1 vm1 100 Feb 11 1990 test.8 drw-rw-rw- 1 vm1 vm1 2000 Feb 11 1990 dir1
10 | DOS-compatible short file names | TEST TXT 1280 11/02/1990 19:46:38 TEST 8 100 11/02/1990 13:38:34 DIR1 <DIR> 11/02/1990 15:13:48


FileSystem:File

Object Types

FileSystem:File

A file object controls a file in a file system. A file is a sequence of data items of one of these types:

· 8 bit unsigned integer
· 16 bit signed integer
· 32 bit signed integer
· 32 bit floating point
· Text

Data can be written to the end of a file, and can be read in sequence from the beginning of the file or from any selected point.

Any element of a file can be accessed by its numerical position in the file and read or changed.

Any file can be printed, in a format that depends on the data type, and a text file can also be printed to.

The interface is designed to be as similar as possible to that of the Buffer object type.

Summary of messages

Creation

Close

Element

Empty

Find

Get

Length

Name

Put

Queue

Readpoint

Reset

Time

Help

PRINT TO

PRINT

LockIcon | The Lock and Unlock messages can be sent to a file, however it is important to note that the normal file access functions (e.g. get and put) ignore locks. Printing to or from a file always locks it for the duration of the PRINT statement. If multiple tasks are writing formatted sequences of data to the same text file, using a single PRINT statement for each unbroken output record will keep it intact. For other file types, or where a single PRINT statement is not possible, use the Lock and Unlock messages. Note that one task may write to a file while another reads it without any need for locking at all.
SeeAlso | See also Locking in the Tutorial.


Creation

The only way to create a file variable is by sending the Open message to a FileSystem object. This is documented in the FileSystem Open message and for RAMdisks on old version of Venom in File System(RAM) Open.

fs.Open(Str name, Any Prototype [,Int maxlength])

rarrow file object

name is the file name, subject to restrictions which depend of the file system in use.

SeeAlso See FileSystem (FAT) Open and FileSystem (RAM) Open for details.

prototype denotes the data type of the file contents and is one of the following:

prototype | Element Type
0 | Run length compressed data
8 | 8-bit unsigned integer
16 | 16-bit signed integer
32 | 32-bit signed integer
1.0 | Floating point
"" | Text
'd' or 'D' | File is a subdirectory. Only valid in FAT file system

The Run length compressed data type is only for use with Put and Get messages with array parameters and is intended for data such as Graphics LCD images that may contain long runs of the same data value. The file otherwise behaves as 8 bit unsigned integers.

If a file with the same name exists, it is opened with the read pointer set to the beginning of the file and the write pointer set to the end of the file. If no file existed, an empty file is created with read and write pointers at 0.

If a third parameter maxlength is given, it sets a maximum length for the file. If created this way, any write to the file that results in its length exceeding that target will cause the first 512 bytes (RAM) or 1st cluster (FAT) to be removed from the file. This is useful for log files where only recent data is of interest, and in such cases can remove the need for extra housekeeping code to prevent the file system from running out of space.

LIMIT

Note that the maxlength parameter is in bytes and intended for use with text files. This parameter, if specified, must be at least 1024. In the FAT file system the actual file size may be considerably bigger than specified as it is truncated to a whole non-zero number of FAT clusters, and a cluster can be as big as 32k. For Venom releases after 2008 01 16 where FAT is used on RAM disks, note that the cluster size for FAT on RAM disk is always 512 bytes.

Example

a := fs.open("aaa.txt", "")

b := fs.open("temp", 1.0)

c := mmc.open("/log/error1.log", "", 10000)


Close
.

f.Close

The file remains in the file system but is no longer associated with any variables that referred to it and no messages can be sent to it.

Closing a file updates the file's directory entry with the file's size. If a source of current date and time information is available, the directory entry is timestamped accordingly; if not the Venom time value of 0 results in a timestamp of 01/01/1990 00:00:00.

On MMC/SD cards, closing a file also results in buffered unwritten data being written to the physical media.

Time Source

By default the system attempts to get the time and date from an internet time server, and failing that from the VM-1's optional real time clock/calendar chip. Either of these sources can be suppressed using the second form of the file system Time message.


Element

f.Element(Int Elementnumber) lrarrow Any

f.(Int Elementnumber) lrarrow Any

Sets or returns a single data element of the file.

For a text file the value is treated as an integer.

The file starts at Element 0.

It is relevant to know that in a text file created by PRINT TO, a line break takes up two character elements (CR=13 and LF=10).


Empty

f.Empty

Removes all the data in the file, leaving read and write pointers at zero. The file is then in the same state as if it had been newly created.


Find

f.Find(String or Buffer pattern [, Int startpos]) rarrow Int

Searches a text file for a string supplied either as a fixed string or as the contents of a text buffer.

Find returns an integer showing the element position of the beginning of the first instance of the search pattern if found, or -1 if not found.

The search starts at the character position startpos in the file if specified, or else at the beginning of the file which is equivalent to a startpos value of 0.

The search pattern has a maximum size limit of 255 characters.

The Boyer-Moore search algorithm is used, which is very fast, especially with a long search pattern.


Flush

f.Flush

(FAT file system only)

In the FAT file system, sending a file the flush message will force writing of all buffered data to the storage medium and updating the directory entry as if the file had been closed and re-opened. After the flush message a power failure or removal of the media will not result in any loss of data written prior to the Flush message.

Venom Version 2006 03 22 and Later

In Venom versions 2006 023 22 and later, the file is automatically flushed after a timeout period (but only on the next filesystem access). By default this is every 10 minutes. This timeout period can be altered:

f.flush(Int period)

Period

Sets the time in milliseconds after which another flush will be performed on the next write to the file

SeeAlso

See also: Application Note "Data Logging with Memory Card File System" available from the Micro-Robotics website, which discusses the issues of file data integrity and memory card wear.


Get

f.Get rarrow Any

Returns a value from the current read point in the file and advances the read pointer to the next element. It is an error to attempt to read past the end of the file. (See Queue Message for how to avoid this)

The type of data returned is:

Integer for all types of integer file

Float for a float file type

Integer value of a single character for a text file

Note that a text file created with PRINT TO and containing line breaks will return the sequence 13, 10 at the line breaks (ASCII CR and LF).

Arrays

f.Get(Array a[, Int n]) rarrow Int

Where a is an array of the same data type as the file, this will read data from the file into the array. The transfer stops when either the end of file or end of array is reached. The optional parameter n limits the number of elements transferred. The file readpoint is left pointing to the next element after the last transferred, if there is any data remaining in the file.

The value returned is the number of elements transferred.

Run time error if types do not match.

XMODEM Transfer

f.Get(AsyncSerial s) rarrow Int

Returned value: true (-1) or false (0) indicating success of file transfer

This special form of Get transfers data from the file to the serial port using the XMODEM protocol. The transfer begins at the current read position of the file and stops at the end of file. The file read position (f.Readpoint) is left at the end of the file. Note that the XMODEM protocol uses fixed blocks of 128 bytes, so if the data transferred is not an exact multiple of 128 bytes it will be forced so by padding the end with zeros.

Note that an XMODEM Protocol object need not be created explicitly: in fact this transfer will fail if such an object already exists associated with the same serial port.


Length

f.Length rarrow Int

Returns the length of the file in elements of the file's specified type.

For text files, this is the number of characters, counting each line separator as the two characters CR, LF.


Name

f.Name rarrow string

Gets the file name.

The returned value is a fixed string whose physical address is the file name in the directory entry. As with any message returning a fixed string, great care should be taken if assigning it to a variable, as the string represented by that variable will only be valid as long as the file is open.

Completely safe and useful operations include:

Printing a file name: PRINT f.name

“Printing” a file name to a text buffer or a String object: PRINT TO buf,f.Name

In the FAT file system, the string returned is the full pathname of the file, i.e. including the directory containing it if not the root directory.

In the FAT file system, assigning a new name to an open file is not possible and results in a run time "message not recognized" error. For all file systems, closed files can be renamed by sending a message to the file system object.


Put

f.Put(Any value) rarrow Int

The data type of the parameter depends on the file type.

A value is returned only if the parameter is a serial port (see below)

The data is written to the end of the file.

Integer values must be written to a file of one of the integer types. Values will be truncated if necessary to the size of the file data type.

For the floating-point file type, the value must be a floating-point type.

For a text file, the data can be a single character, fixed string or an entire text buffer whose length must not exceed 256 characters.

The parameter can also be an array of elements with the same data type as the file. All the array contents are appended to the file unless a second parameter is given as described below.

Arrays

f.Put(Array a, Int n)

If the parameter is an array, an optional second parameter specifies the number of array elements (starting with the first) to be transferred.

XMODEM File Transfer

f.Put(AsyncSerial port) rarrow Int

If the parameter is an AsyncSerial object, the XMODEM protocol is used to transfer data from the serial port to the file. The value returned is TRUE (-1) if the transfer was successful and zero if it failed. Note that an XMODEM Protocol object need not be created explicitly: in fact this transfer will fail if such an object already exists.


Queue

f.Queue rarrow Int

Returns the number of elements remaining to be read from the file. For a text file, an element is a single character.


Readpoint

f.Readpoint lrarrow Int

Gets or sets the point at which the next Get message will read data from the file. The file starts at position 0.


Reset

f.Reset

Resets the read pointer to the beginning of the file.

This is equivalent to f.Readpoint := 0.


Time

f.Time lrarrow Int

Returns or sets a time value in seconds, compatible with the DateTime and RealTimeClock objects (i.e. time in seconds since 00:00 on January 1, 1990)

The time value returned corresponds to the date and time when the file was created or last modified.

Modification times are updated only when the file is closed or flushed.

If there was no internet connection or real time clock hardware present when the file was created or last modified, the returned value will be 0.

BugAlert

Note that to set the time and date successfully to a different value from the current time, this must be done immediately before closing the file or sending it a Flush message. Any further write to the file would cause the current date and time to be applied when the file was closed of flushed.

SeeAlso See also: File Close, File Flush


Help

HELP file f

It is worth noting that the standard help message, which shows the type of a variable, additionally shows the file name for a file variable.

Example

-->HELP a

It is a text file named "abc.txt"

-->


PRINT TO

PRINT TO f, list

A text file can be the destination of a print operation. The print output is appended to the end of the file in exactly the same way as by a series of Put messages.


PRINT

PRINT f[: Int n1[: Int n2 [: Int n3]]

Lists the contents of the file.

Text Files are displayed in their normal text format

Other file types are displayed one item per line.

If the colon(s) and format code(s) are present they are interpreted in the same way as when printing buffers of various types:

File type | 1st format parameter | 2nd format parameter | 3rd format parameter
Text | If positive, print first n1 characters of file If negative, print last (-n1) chars of file | Not present | Not used
Text | First char position in file to print | Number of chars to print | Not used
Text | “+” - print entire file adding CR in front of any LF encountered (UNIX -> Windows conversion) | Not present | Not used
All Integer types | Minimum field width (number of characters to print per number) | Not used | Not used
Float | Minimum field width | Number of decimal places | Exponential format

In the FAT file system, a file opened as a directory can be printed. A numerical colon operator can be used to control the display format in the same way as when .printing a FileSystem object


FrequencyIn

Object Types

FrequencyIn

FrequencyIn measures the frequency of pulse inputs with an arbitrarily high precision in a relatively short time.

The measurement uses either the internal crystal oscillator or an external stable clock source for its time base. The potential measurement accuracy is the same as the accuracy of the clock source.

Normally, measuring a frequency involves counting the number of input pulses in a pre-determined time slot. This can involve long measurement periods to get any useful precision with low input frequencies.

FrequencyIn uses a more sophisticated method illustrated in the diagram below.

In this method, the time between the first and last pulse of a train of N pulses is recorded, measured against the clock source. From the Period (first edge till last edge) and the Count (number of whole pulses) the frequency may be calculated:

Frequency = Count / Period * clock frequency

The clock frequency is derived from the controller’s clock crystal or you can use an external clock if you need more accuracy.

Measurement takes place from the first negative edge to the last negative edge.

Maximum frequency

The maximum input frequency measurable is limited by the interrupt-handling capacity of the controller. See the table below. If your input frequency is higher than this you can simply use a binary counter IC (such as the 74HC4060, etc.) to divide the input signal down to a measurable level. Because of the nature of the measurement process, this does not necessarily mean the measurement period has to increase.

It is also possible to use a PulseWidthOut object as a frequency divider by using your input signal as its clock source. Its output frequency is then the input frequency divided by its Period.

Characteristics of FrequencyIn
Hardware Input channel | VM-1 Ch 19
TimingIcon Max frequency input | 5 kHz (Guaranteed operation)
TimingIcon Min frequency | Limited by waiting time to 0.016 Hz
LIMIT Max precision | 0.1 ppm
Using 16MHz internal oscillator
TimingIcon Time to reach 10 ppm precision | 6.25 mS, or 2/F when F <320 Hz.
LIMIT Accuracy | [TBA]
Using external stable clock source
Hardware External clock input | VM-1 Ch 1, Ch 2, Ch 16, Ch 17
TimingIcon External clock max frequency | 5.33MHz (1/3 of the internal oscillator frequency)
TimingIcon Time to reach N ppm precision (Seconds) | 1,000,000 / (N * Fclock), or 2/Fsignal, which ever is longer.

Summary of messages

MAKE

Count

Format

Go

Period

Value

PRINT


Creation

MAKE obj FrequencyIn (Int chan , Int precision , Int wait)

A new FrequencyIn object is created.

Chan is the channel number. Currently only Channel 19 supports FrequencyIn but it might be made available on all the pulse I/O channels if there is demand.

Precision and wait are optional parameters.

Precision gives the minimum precision required in the result. E.g. if precision is set to 1,000,000 then the result will have a precision of 1ppm, or one part in a million.

Precision is equivalent to the minimum number of clock pulses, or the minimum value of Period.

Precision defaults to 1,000,000.

Note that setting precision to a higher value means the measurement process will take longer. The minimum time needed to take a measurement is

T min = Precision / clock frequency

So for a 16 MHz clock, and a precision of 1 million, it will take at least 0.0625 seconds to take a measurement.

The maximum time needed to take a measurement is

T max = 2/Input Frequency

So for low input frequencies it may take longer to measure them. E.g. measuring a signal of 1Hz can take up to 2 seconds.

Wait is the maximum time in milliseconds to wait for a measurement to complete. If the measurement does not complete in wait mS then it is aborted. You should set wait longer than the expected maximum measurement time.

Even if there is no signal present when the measurement process starts, then the measurement will still succeed so long as it completes in wait mS.

Wait defaults to 100mS. The maximum value it may be set with is 65,536 mS.

The 16 MHz internal clock is used as the measurement clock by default. See the Format message for how to change this.

Examples

MAKE f FrequencyIn (19) ;use default precision and wait

MAKE f FrequencyIn (19, 100000 , 1000) ; precision of 10pppm and max wait of 1 second.

Hardware | The VM-1 channel 19 may be used by other objects. See Digital, PulseCounter, Shaft and I/O channel table in the VM-1 Datasheet.
LIMIT | Care should be taken to ensure that the creation of a FrequencyIn object does not use the same internal counter register as a PulseCounter or Shaft object. See PulseCounter or Shaft for details.
SeeAlso | See also PulseWidthIn, PulseCounter and Shaft.


Count

obj . Count rarrow Int

Count returns the number of input pulses that occurred during the measurement process. If the measurement was aborted, then this will be zero.

The measured frequency is given by

Count / Period * Clock Frequency

Example:

Frq := f.Count / f.Period * 16E6

SeeAlso

See also Period, Value, Go


Format

obj . Format := Int

Format sets the clock source to be used for the measurement process.

If the controller’s clock is not accurate enough for your measurement then you can use your own clock source.

The value passed to the Format message consists of a bit field. The lower three bits (bits 0 – 2) determine the source of the clock pulses.

The table shows the VM-1 channel or clock rate selected depending on the input channel and bits 0 – 2. The clock rate is shown as Ø/N where Ø is the VM-1 clock crystal frequency (normally 16Mhz) and N is a division ratio. The column in bold is the default setting.

There is normally no advantage to using one of the Ø/N internal clocks, though there may be rare circumstances when they would be useful.

VM-1 channel/ Bits [2:0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
19 | Ø | Ø/4 | Ø/16 | Ø/64 | Ch 2 | Ch 1 | Ch 17 | Ch 16

The next two bits (bits 3 & 4) determine which edges of the clock signal to count on.

Counting on both edges effectively doubles the frequency of the clock, allowing Ø/2, Ø/8, Ø/32, etc.

Bits 4,3 | Count on edge
00 | Rising
01 | Falling
10 | Both
11 | Both

You can’t count on both edges when Ø is selected as the clock source.

You can’t count on a single edge of an external clock source unless its frequency is less than Ø/3.

You can’t count on both edges of an external clock source unless its frequency is less than Ø/5.

Example:

f.Format := %110 ; use channel 17 as the input clock.


Go

obj . Go rarrow Int

Go starts a measurement of frequency. It waits for the measurement process to complete, or for a timeout on the wait parameter. It returns a non-zero value if it was successful, or zero if it failed.

TO measure_frequency

IF f.Go

[

RETURN f.Value

]

PRINT “Measurement failed”,CR

END

SeeAlso

See also Value, Period, Count


Period

obj . Period rarrow Int

Period returns the number of clock pulses that occurred during the measurement process. If the measurement was aborted, then this will be zero.

The measured frequency is given by

Count / Period * Clock Frequency

Example:

Frq := f.Count / f.Period * 16E6

SeeAlso

See also Count, Value, Go


Value

obj . Value rarrow Float

Value returns the frequency measured the last time Go was called, assuming a 16MHz clock source. For other clock rates you will need to calculate the frequency using Count / Period * Fclock, or Value * Fclock / 16E6.

Example:

PRINT f.value:13:6

4000.000000-->


Printing

PRINT obj

Print prints out the text [FrequencyIn].


GraphicsLCD

Object Types

GraphicsLCD

GraphicsLCD manages text and graphics on many types of graphical LCD displays.

It supports

· Several fonts, both proportional and monospaced
· User defined fonts
· Word wrapping
· Scrolling
· Text justification (left, right and centred)
· Bit map images (‘sprites’)
· Graphical primitives (lines, rectangles, etc.)
· ‘Active’ graphical display objects (see Display, Marker, Bar)
· Multiple ‘windows’

The drivers support monochrome images of 1 bit per pixel – i.e. not colour or greyscale.

Windows

All output to the LCD is contained within windows that are assigned a fixed size and position on the display. Often only one window will be defined: one that covers the whole of the display area.

Overlapping windows are not supported in a sophisticated way – windows are just a convenient way of dividing up the screen and maintaining local values of cursor position, pen colour, etc.

The GraphicsLCD object takes care of high-level functions – like managing windows and the physical device. All text and graphic operations are done on Window objects.

Update

In order to optimise the speed of creating and modifying images on the LCD device, graphic primitives (lines, text, etc) to be drawn on the windows are first written to internal 'scratchpad' RAM, and only transferred to the actual display device when the Update message is called.

Summary of messages

MAKE

FontData

Reset

Sprite

Update

Value

Window


Creation

MAKE obj GraphicsLCD (Int controller, Int xpixels, Int ylines)

MAKE obj GraphicsLCD (Int type)

Most GraphicsLCD objects are created using three parameters - a number indicating the type of controller (see table below) and the size of the display in pixels horizontally and vertically.

Controller Type no. | Manufacturer (Controller) | Controller
0 | Hitachi / Sanyo | HD61830B / LC7981
1 | Toshiba | T6963C
2 | Device removed | Device removed
3 | Epson | S1D13705 (QVGA, etc)*
5 | Epson | SED1565

The following statement creates a 240 column x 128 row graphicsLCD, driven by an LC7981 controller chip.

MAKE glcd GraphicsLCD(0, 240, 128)

On creation, the LCD display is initialised and cleared.

memoryUse

The amount of memory used is dependent upon the display size. There is one byte taken per 8 pixels on the display, plus around 640 bytes. Further memory will be required to create windows, sprites, fonts and other sub-objects. See the relevant sub-sections for details.

*QVGA on the S1D13705 – Extra notes

You may need to use the On message some time after MAKE to turn on the LCD panel.

The MAKE command for controller type 3 (S1D13705) also takes an optional 4th parameter that specifies the value of the device select lines (channels 34-37 of the VM-1). If you use these lines to decode the S1D13705 device within the ‘OFF_BOARD’ address space, then you may need to use this parameter. When not supplied, this value defaults to that needed for the 5811 ‘module board’: $E.

Note that the hardware specification for connecting modules to the VM-1’s system bus reserves VM-1 channels 30-37 as extra address lines. Channels 30-33 are used to select more addresses within each module, and Ch 34-37 are used to select between modules. Consequently channels 30-37 may only be used for module addressing purposes if any module is connected to a VM-1.

Backwards compatibility

For the purposes of backwards compatibility and for some special types of graphics LCD, a single parameter Make statement may be used instead:

Single Parameter in MAKE | LCD Manufacturer | Controller IC | Device | Display size
4 | Hitachi / Sanyo | HD61830B / LC7981 | LMG640X, LMG740X, etc | 240 x 128
8 | Toshiba | T6963C | MGLS12864T | 128 x 64
24 | TRI-T | SSD1815B | TMGG13264-08 | 132 x 64
28 | Batron | SED1565 | COG-BTHQ12864-04 and similar | 128 x 64

The example below creates an Hitachi LMG640X/740X series GraphicsLCD.

-->MAKE panel GraphicsLCD(4)

For other types of GraphicsLCD contact Micro-Robotics for details.


On

obj . On

For QVGA Driver Module 5809 / S1D13705 only.

This will turn on the LCDPWR signal (which is the same as the LCDPWRON signal coming out of the 5809) at any time after the MAKE for the LCD.

It is intended to allow correct LCD power sequencing to be followed.

The suggested code sequence for the S1D13705 attached to a 5811 Application Board (Issue B), driving the Hitachi SP14Q006-ZZA QVGA Graphic LCD is as follows:

TO init

MAKE bias_control Digital(22) ; Controls power to lcd bias cct.

bias_control.On ; Switch on bias

MAKE p GraphicsLCD (3 320 240)

WAIT 50 ; Wait at least 50mS.

p.On ; Turn on the LCDPWR signal.

;Other initialisation...

END

SeeAlso Off, Creation


Off

obj . Off

For QVGA Driver Module 5809 / S1D13705 only.

This will turn off the LCDPWR signal (which is the same as the LCDPWRON signal coming out of the 5809). The LCD display signals will not turn off immediately, but will follow the S1D13705's power saving mode sequence timing.

This message is intended to allow correct LCD power sequencing to be followed.

SeeAlso On


FontData

obj . FontData (Int Font_no) := Int font_ptr

The FontData message allows extra fonts to be defined.

The GraphicsLCD object comes with several fonts pre-defined – FontData allows you to define more of your own.

We list several additional fonts on our website that are available free for you to download.

Parameters

font_no is the new font’s font number. It must be in the range 10-17. font_ptr is the address (in memory) of the font-definition data. This data may be created using a Venom ARRAY. The format of the font-definition data is:

Byte # | Function
0 | Font type. 0: Monospaced, 3: Proportional. (Values 1 & 2 are used internally)
1 | Font character width (maximum 16; used for Monospaced only)
2 | Font height (Total number of pixel lines in a character)
3 | ASCII code of first character to be defined (e.g. 33 if first character is ‘!’. Must be in the range 33 - 255)
4 | ASCII code of last character to be defined in the font
5 | Ascent: Number of pixels above the baseline. The baseline is the pixel row above any decenders in the font.
6 | Inter-character spacing: Number of pixels between each printed character.
7 | Width of the space character in pixels – only used in proportional fonts.
8 | ‘Extra ascent’: blank lines printed above the font (use 0 to start with)
9 | Reserved – set to 0
10 onwards | Character map & font bit-map data. This differs depending on whether the font is monospaced or proportional.

The first 10 bytes (0-9) list general data about the font. After this are the character map (that indexes each character in the font), and the font bitmap data itself.

Character map

A character map is only used in proportional fonts. Monospaced fonts simply miss out this section of the data structure and run straight into the font bitmap data.

Each entry in the character map is as follows:

Byte # | Function
0 | Character width in pixels
1 | Reserved – set to zero.
2 | Character data offset - MSB
3 | Character data offset - LSB

The character map allows each proportional font character to be found within the bitmap data. Each map entry holds the character width and the offset of the bitmap data. The offset is relative to the start of the array.

Because there is one character map entry for each character in the font, the start of the bitmap data, and so each offset, may be determined:

For a font in which 100 characters are defined, the first character bitmap has an offset of 10 + 4 x 100 = 410, or $01, $9A as two hex bytes.

Font bitmap data

This is organised as most-significant-bit (msb) on the left; top-most row first; each character left justified within the bytes; if characters are more than 8 bits wide then the right hand side of the character follows after the left hand side data is complete. The number of rows in each character is given by the font height in the font array data above.

Any character set can be created in this way, although in the case of some (such as Chinese, Arabic etc.) the characters created will not relate directly to the ASCII code used to print them. You can define any group of consecutive characters between 33 and 255. Characters are restricted to a maximum width of 16 bits at present.

With a little work it is possible to convert fonts from the .FON file format to the format given above. There is also a program called Softy that can be used to create/modify bitmap fonts. It’s available at http://users.breathe.com/l-emmett/.

LIMIT | Up to 18 user-defined fonts can be created.
SeeAlso | See also Array, GraphicsLCD:Window.

The following example sets up a font containing only the digits 0-9. The actual font data has been omitted from the text, as it would be too large to reproduce here:

ARRAY my_font_data(8,110)

0, ;monospaced font

8, ;8-bits wide

10, ;10-bits high

48, ;first character is ascii ‘0’

57, ;last character is ascii ‘9’

7, ;7 pixels above base-line

1, ;1 pixel between chars

8, ;8 pixels in a space

1, ;1 blank line above bitmaps

0, ;Spare byte

…font data bytes … ;100 bytes of font data

END

panel.FontData (10) := my_font_data.Address

PRINT TO w, FONT 10, "0123456789”; print all 10 characters

It can be useful to create a separate file containing your font data array. This can then be downloaded to the VM-1 separately from the code. It will stay in RAM so long as you don’t clear the memory, just like the code.


Reset

obj . Reset

The Reset message re-initialises the registers in the graphics LCD and refreshes the display. You will only need to use this message if your graphics LCD is subject to adverse external conditions.


Sprite

obj . Sprite (Int sprite_no) := Int address

Defines a bit-mapped ‘sprite’ to be used in any window on the graphics LCD.

The sprite bit map data is usually supplied in the form of an array. The data should contain two bytes defining the width (in pixels) and number of rows respectively for the sprite; then two unused bytes, which should be set to 0. The remaining bytes define the sprite pattern. The user must assign a sprite number to the sprite when it is created.

LIMIT | Up to 256 sprites may be defined. Each sprite may be up to 255 by 255 pixels.
SeeAlso | See also Array.

The following example sets up a triangular sprite using a macro to define the sprite number:

;Define some constants:
#DEFINE XSZ 320 ;x length pixels
#DEFINE YSZ 240 ;y height pixels
#DEFINE TRIANGLE 0

Array bitmap(8,12)
;8 = 8-bit data
;12 = size of array (8 bytes of sprite data + 4)
8 ;sprite is 8 pixels wide
8 ;sprite is 8 rows high
0 ;unused
0 ;unused
1,3,7,15,31,63,127,255 ;sprite pattern data
END

TO init
MAKE glcd GraphicsLCD(3,XSZ,YSZ)
WAIT 50 ;Power sequencing
glcd.On ; --"--

win := glcd.Window(0,0,XSZ,YSZ,0) ;full screen window

glcd.Sprite(TRIANGLE) := (bitmap.Address) ;define sprite

START EVERY 100 glcd.Update ;task to update display
END

TO main
win.Sprite(30,30,TRIANGLE) ;plot it at (30,30)
END

It can be useful to create a separate file containing your sprite data arrays. These can then be downloaded to your terminal window when required. They will stay in RAM so long as you don’t clear the memory, just like the procedures.

It can be useful to use binary representation when defining sprites. The least significant bit of each element represents the right-most pixel of the bit pattern. To left-justify a bit pattern, pack the right hand side of the data elements with zeros to a byte boundary as shown in the examples below. Sprites are plotted with their top left hand corner at the specified coordinates. The following two sprites are defined as shown below:

Array a1(8,7)

8

3

0

0

%11111000,%10001000,%11111000

END

;the following uses 16-bit sprite data (the least significant bits ;are set to 0s to left-justify the pattern).

ARRAY a2(16,12) ;12 = 10 elements of sprite data + 2

$100A, ;sprite is 16 pixels wide x 10 pixel rows

$0000, ;unused

$ffc0, ;start of sprite pattern data

$ccc0,

$a140,

$9240,

$ccc0,

$ccc0,

$9240,

$a140,

$ccc0,

$ffc0

END

Note that Sprites are written to the GraphicsLCD using the GraphicsLCD:Window:Sprite message.

SeeAlso

See also GraphicsLCD:Window.Sprite.


Update

obj . Update

The Update message forces all the changes that have been made (to the local-memory copy of the display data) to be sent to the display itself. Nothing will be displayed on the physical display device until an Update message is issued. Whilst individual Update messages can be used, e.g.:

PRINT TO w, "Hello"
panel.Update

it can be useful to start a separate task to keep the LCD updated:

START EVERY 100 panel.Update

TimingIcon

Most of the GraphicsLCD driver objects will only update the rows of the display that have been written to since the last Update. The speed of display activity can therefore be improved by confining fast changing graphics to small groups of rows.


Value

obj . Value(Int address, Int data) lrarrow Int

The value message may be used to set internal registers in an LCD controller.

Address is the address of the register, and data is the data to send to it.

Only the following controllers have the Value message implemented so far:

SED1565

Here, address should be 0 for the display data, and 1 for the control registers.

For example you may alter the contrast:

panel.value(1,$81) ;Set up the contrast command.

panel.value(1,val) ;Write contrast value.

Or invert the pixel colour of the display:

panel.value(1,$A6)

Note: be careful when altering the values of the internal registers as some values may possibly damage the LCD display device.


Window

SeeAlso See GraphicsLCD:Window.


GraphicsLCD:Window

Object Types

GraphicsLCD:Window

All text and graphics operations are performed on Windows. Each window has it’s own coordinate system with the origin inside the border at the bottom left.

Each window has it’s own independent text cursor and line cursor positions, current font, current pen ‘colour’, etc.

Note that nothing is displayed on the physical display device until a GraphicsLCD.Update message is issued.

Summary of messages

MAKE

Bar

Box

Display

Graticule

Line

Marker

Pen

Sprite

Value

PRINT TO


Creation

Obj . Window (Int xl, Int yb, Int xr, Int yt, Int border) rarrow Window

Creates a new window on the GraphicsLCD in which text and graphics may be displayed.

xl,yb and xr,yt are the coordinates of the bottom left and top right corners of the window on the LCD display. (The bottom left pixel of the GraphicsLCD is location (0,0)).

The border parameter sets the border style of the window. The styles are based on binary patterns (e.g. 5 decimal is 101 in binary which would produce a border consisting of 2 black lines separated by a white line as shown in the example border patterns below). The least significant bit (bit 0) controls the innermost border line. Window borders are drawn inside the (xl,yb / xr,yt) boundary, and the origin for the window coordinates is the bottom-left-most pixel inside the border.

Example

The following example creates a window that would fill the screen of a 240x128 pixel display:

MAKE panel GraphicsLCD(4)
START EVERY 100 p.Update
w := panel.Window(0,0,239,127,1)
PRINT TO w,"Hello World"

If windows overlap they will draw over each other on the display, as there is no concept of one window being in front of another. It is possible, by judicious programming, to create the effect of a more advanced windows system.

Note that windows and their contents are not displayed until a GraphicsLCD.Update message is issued.

memoryUse | Windows use around 182 bytes of memory each.
SeeAlso | See also GraphicsLCD Creation


Bar

Bar is a sub-object of GraphicsLCD:Window that displays active bar graphs.

SeeAlso

See separate section GraphicsLCD:Window:Bar


Box

obj . Box (Int xl, Int yb, Int xr, Int yt, Int border)

Draws a box on the window with a border in the current line pen colour, and filled with the current fill pen colour. The first four parameters specify the coordinates of the bottom left and top right corners of the box. border is a binary pattern (as for the window border) which will be drawn inside the box boundary.

SeeAlso

See also Pen


Display

Display is a sub-object of GraphicsLCD:Window that displays ‘active’ numeric or text values.

SeeAlso

See separate section GraphicsLCD:Window:Display


Graticule

obj . Graticule
(
Int x_pos,
Int y_pos,
Int axis_dirn,
Int length,
Int minor_repeat,
Int major_repeat,
Int tick_style,
Int line
)

Draws a graticule on the window, i.e. an axis for a graph (either x or y) with major and minor ticks marked on it.

x_pos and y_pos give the starting point of the graticule, axis_dirn governs which way the it extends from the start point (see table). length gives the total pixel length required of the graticule. minor_repeat gives the number of pixels between minor ticks on the graticule, and major_repeat gives the number of minor ticks between major ticks. Zero indicates that no major ticks should be drawn. tick_style is one of three options, giving the relation of the ticks to the axis (see table). line, if TRUE indicates that a line along the axis should be drawn. The line and all the ticks are drawn in the current pen colour.

Axis code | Direction
0 | Right
1 | Left
2 | Up
3 | Down

Tick style code | Description
0 | Ticks centred on axis
1 | Ticks above or to the right of the axis
2 | Ticks below or to the left of the axis

LIMIT | Coordinates are clipped to the size of the window.
SeeAlso | See also Pen, GraphicsLCD:Update


Line

obj . Line (Int x1, Int y1, Int x2, Int y2)

Draws a line from the end of the previous line to the window coordinates (x1, y1), or if the optional parameters x2 and y2 are present, from (x1, y1) to (x2, y2). The line is drawn in the current window graphics pen colour.

LIMIT | Coordinates outside the edge of the window are individually limited at the edge of the window, i.e the gradient of the line is not preserved.
SeeAlso | See also Pen


Marker

Marker is a sub-object of GraphicsLCD:Window that moves bitmap sprites a long a track automatically.

SeeAlso

See separate section GraphicsLCD:Window:Marker


Pen

obj . Pen ( Int line_col , Int fill_col )

Pen changes the colours with which all lines and boxes are drawn and filled, on the window to which the message is sent.

Colour code | "Colour"
0 | Transparent
1 | Black
2 | White
3 | Invert

Pen does not affect the colour in which text is drawn.

SeeAlso

See also Line, Box.


Sprite

obj . Sprite( Int x, Int y, Int n )

Draws a sprite on to the window in the invert 'colour'. The x and y coordinates specify the position of top left-hand corner of the sprite. n is the sprite number defined by the user in the GraphicsLCD Sprite message when the sprite was created.

Partial sprites will be drawn where parts of the sprite would lie outside the boundaries of a window. However, this feature does not currently work where parts of the sprite would lie outside the boundaries of the display itself.

SeeAlso

See also GraphicsLCD:Sprite.


Value

obj . Value(Int ordinate) rarrow Int

The Value message may be used to find the position of the text cursor.

Ordinate is 0 for the x value, and 1 for the y value. For example:

#define XPOS Value(0)

#define YPOS Value(1)

PRINT wind . XPOS ; find the x-position of the text cursor

PRINT wind . YPOS ; find the y-position of the text cursor

Note the use of macros to make the message name more meaningful.

This may be used to help move the text cursor around the window in conjunction with printing GOTOXY.


Accepting Print

PRINT TO obj , <print list>

Windows print everything sent to them in the current font. The current font defaults to FONT 0 when the window is created. Print output is word-wrapped: the necessary breakpoint location, carriage-return, and scrolling is taken care of automatically.

Font changes within a single PRINT statement are handled cleanly so that sections of text in different fonts are aligned correctly and don’t overwrite previous lines.

Special printing keywords understood by windows are:

CLS

Clears the window, (re-drawing the border in the process so that it will overwrite other windows if they overlap). A HOME operation is done. The font does not change.

PRINT TO w, CLS

HOME

Positions the text cursor at the top left of the window, ready for a new page of text.

Resets both the justification and the margin to the left.

PRINT TO w, HOME

CR

Positions the text cursor at the beginning of the next line down, according to the current font size and margin. If the cursor overflows the bottom of the window then the window is scrolled up.

Note: it is often best to change font before a CR rather than after it.

PRINT TO w, "Hello", CR

LEFT, RIGHT, CENTRE

These set one of these justification styles until the next justification command or CLS/HOME. They also put the cursor at the left, centre or right of the window and reset the margin there. If you wish to justify text at a point in the window, use GOTOXY after the justification command.

PRINT TO w, RIGHT, "Some text", CR

FONT (Int font)

Set the font for printing to the window. Fonts supplied are shown in the table below, and you can add more fonts. The monospaced fonts are useful for printing columns of numbers. Fonts may be changed at any point in a print statement.

PRINT TO w, FONT 0, "Number: ", FONT 2, n

Note: it is often best to change font before a CR rather than after it.

Font Number | Font | Proportional / Monospaced | Height (pixels)
0 | Geneva | Proportional | 11
1 | Times | Proportional | 19
2 | Courier | Monospaced | 16
3 | AlphaLCD | Monospaced | 7
4 | Courier for numbers | Monospaced | 16

GOTOXY (Int x, Int y)

Positions the text cursor at the window coordinates x,y. Note that the point (0,0) is at the bottom left of the window.

Additionally the x coordinate is used to set a vertical ‘margin’ so that all carriage returns thereafter move back to that x coordinate (you can reset the margin with LEFT, RIGHT or CENTRE).

PRINT TO w, GOTOXY(10,20), "Indented", CR, "text"

GOTOXY (0,0) refers to the bottom left hand corner of the window, inside the border. If the coordinates supplied lie outside the window the closest position inside the window is used.

If you specify a position with GOTOXY low in the window, and the font of the characters printed has decenders that would print outside the lower window border, then the window is scrolled up.

If you specify a negative y coordinate then the window is scrolled up by –y. This feature may be used to force a scroll of any number of pixel lines.

Sprites

Strings printed to a window may contain escape codes. The most useful of these is for sprites, which allows you to create extra characters of your own design, e.g. accented characters, bullet points, etc. (You can also create complete fonts).

Sprites are embedded in a string constant by placing \^hh in the text at the point at which the sprite should appear (where hh is the sprite number represented as a 2-digit hexadecimal number). These sprites might be used to display symbols such as bullet points or characters with accents. For example, the following would write ‘café au lait’ to the graphics LCD provided that an ‘e’ with an acute accent had been previously defined as sprite number 3.

PRINT TO obj,”caf\^03 au lait”

When used with monospaced fonts the sprite width should be the same, or less than, the character width.

SeeAlso

See also GraphicsLCD:Sprite, GraphicsLCD:Window:Sprite.


Die

obj . Die

Die kills the window object. It does not remove any graphics from the display.


GraphicsLCD:Window:Bar

Object Types

GraphicsLCD:Window:Bar

Bar objects automatically update the length of a bar graph on a window according to the value of a global variable.

Summary of messages

Creation

Pointer


Creation

Obj . Bar
( Pointer pointer,
Int/Float min,
Int/Float max,
Int x1,
Int y1,
Int x2,
Int y2,
Int axis,
) rarrow Bar

Creates an active display object on the window that automatically updates the length of a bar graph on the window according to the value of the variable pointed to by the pointer parameter. pointer must point to either an integer or floating point value.

min and max give the limits of the value over which the length of the bar is made to correspond to the value. (Note they must be of the same type as the value). (x1,y1) and (x2,y2) give the coordinates of the rectangle which contains the maximum extent of the bar. axis gives the direction the bar will expand and contract in (horizontally or vertically, see table). The fixed end of the Bar is the one containing the point (x1,y1).

Axis code | Direction
0 | Right - Left
-- | --
2 | Up - Down
-- | --

The following examples show bars being created to follow integer and float variables:

v := 100 ; v an integer
b1 := w.Bar(@v,0,200,30,30,40,60,0)
z := 99.0 ;z a float

b2 := w.Bar(@z,0.0,200.0,30,30,40,60,0)

Note that max may be defined less than min, in which case the bar grows shorter as the value gets more positive.

All Bars are removed from the window when a CLS is printed. They cannot be removed from the window by sending them Die.

memoryUse | Each Bar uses around 46 bytes of memory.
LIMIT | The maximum length of a Bar is 255 pixels, not 256.
SeeAlso | See also GraphicsLCD:Marker, GraphicsLCD:Display.


Pointer

Obj . Pointer lrarrow Pointer

Allows the pointer to the value that the Bar follows to be read and changed.

LIMIT

The Pointer must point to a variable of type Int or Float or else a type mismatch error will occur on the GraphicsLCD.Update message.


GraphicsLCD:Window:Display

Object Types

GraphicsLCD:Window:Display

Display objects automatically update a number or other text in a window according to the contents of a variable or object.

Summary of messages

Creation

Pointer


Creation

Obj . Display
( Pointer pointer,
Int f1,
Int f2,
Int f3
) rarrow Display

Creates an active display object on the window that automatically updates the text displayed according to the value pointed to by pointer.

The effect of a Display object is similar to repeatedly executing the code

PRINT TO W, FONT f, GOTOXY (xcur, ycur), !pointer : f1 : f2 : f3

f1, f2, f3 are optional format specifiers to be applied to the value to be Displayed. The font and position of the Display are taken from the current font and current text cursor position of the window. It is advisable to use a non-proportional font with Displays.

Only values or objects that may be printed in a single line may be displayed. No Display updates will be seen until the Update message is sent to the GraphicsLCD object.

If the number of characters in the string to be displayed grows longer than it was when the display was first created, a row of ###’s is displayed instead.

The following example shows two displays being set up; the first of these will display the current value of the variable n at position (100, 50) in the window with a fieldwidth of 10; on the line below, the second display variable will show the current value of the real-time clock using format 0.

n := 100 ; an integer
PRINT TO win, gotoxy(100,50)

d1 := w . Display(@n,10)

PRINT TO w,cr
d2 := w . Display(@clock,0)

All Displays are removed from the window when a CLS is printed. They cannot be removed from the window by sending them Die.

memoryUse | Each Display uses around 70 bytes of memory.
SeeAlso | See also GraphicsLCD:Bar, GraphicsLCD:Marker, RealTimeClock.


Pointer

Obj . Pointer lrarrow Pointer

Allows the pointer to the variable or object that the Display follows to be read and changed. Note that the format parameters set in the creation of the Display object remain the same.

LIMIT

The Pointer must either point to a variable of type Int, Float, String or to an Object.


GraphicsLCD:Window:Marker

Object Types

GraphicsLCD:Window:Marker

Marker objects automatically update the position along a horizontal or vertical track, of a sprite (bitmap) according to the value of a variable.

Summary of messages

Creation

Pointer

Sprite


Creation

Obj . Marker
( Pointer pointer,
Int/Float min,
Int/Float max,
Int x,
Int y,
Int length,
Int axis,
Int under_sprite,
Int normal_sprite,
Int over_sprite,
) rarrow GraphicsLCD:Window:Marker

Creates an active display object on the window that automatically updates the position of a sprite on the window according to the value pointed to by pointer. pointer must point to either an integer or floating point variable.

min and max give the limits of the value over which the position of the sprite is made to correspond to the value. (Note they must be of the same type as the pointer variable). x and y give the position the sprite will appear at when the value is at min. length gives the track length over which the sprite can move. axis gives the direction from (x,y) that the track takes:

Axis code | Direction
0 | Right
1 | Left
2 | Up
3 | Down

normal_sprite is the sprite number of the sprite that is displayed while the value lies in the range given by min and max.

If the value lies below min then under_sprite is displayed at the start of the track, and if the value lies above max then over_sprite is displayed at the end of the track.

GraphicsLCD.Sprite is used to define sprites. A number of sprite bitmaps are available on request, including arrows, tick boxes, radio buttons and sliders.

Any of the sprite numbers may be defined as zero, so that nothing is displayed over certain ranges of the value. Also length may be defined as zero so that the sprite does not move, but may change appearance as the value changes. Note that max may be defined less than min, in which case the sprite moves away from (x,y) as the value gets more positive.

No marker updates are seen on the window unless the Update message is sent to the GraphicsLCD object. Markers may take further messages themselves, allowing their sprites and variable pointers to be changed.

The following examples show two markers being created; the first is based on an integer variable while the second follows a float:

v := 100 ; v is an integer
m1 := w.Marker(@v,10,100,30,40,70,0,0,1,0)

f := 99.9 ; f is a float
m2 := w.Marker(@f,0.0,100.0,50,70,50,0,0,1,0)

All Markers are removed from the window when a CLS is printed to the window. This is the only way of removing them.

memoryUse | Each Marker uses around 48 bytes of memory.
SeeAlso | See alsoGraphicsLCD:Window:Bar, GraphicsLCD:Window:Display, GraphicsLCD.Sprite


Pointer

Obj . Pointer lrarrow Pointer

Allows the pointer to the value that the Marker follows to be found and changed.

LIMIT

The pointer must be a Pointer to a variable of type Int or Float.


Sprite

Obj. Sprite (Int under_sprite, Int normal_sprite,
Int over_sprite)

Allows the set of sprites used by the marker to be changed.

SeeAlso

See also GraphicsLCD:Sprite.


I2CBus

Object Types

I2CBus

This object allows communication with devices on an I2C Bus. Usually you won’t have to use this object, as individual driver objects will often handle the I2C Bus for you. For example, communication with PCF8574 digital I/O ports is handled entirely by the Digital object type. You will only need to use the I2CBus object to communicate with devices that don’t have drivers, or to find out which devices are connected to the bus.

Summary of messages

MAKE

Get

GetLast

Put

Off

On

PRINT

Dot chaining

The following I2C Bus messages return the I2C bus object itself when they are called. This allows them to use Venom’s ‘dot-chaining’ syntax for convenience or speed of execution:

On, Put, Off.

For example

net . On

net . Put(160)

net . Put(0)

net . Put(1)

net . Off

could also be written

Net . On . Put(160) . Put(0) . Put(1) . Off

Clearly, any I2CBus message that returns a ‘real’ result cannot be used in this manner.


Creation

MAKE obj I2CBus (Int bus_no)

The I2C Bus is initialised and an I2CBus object returned.

Note: an I2CBus object called net is created in the default startup procedure.

bus_no can take the value 1 or 2.

LIMIT

Two I2CBuses are available on the VM-1, numbered 1 & 2.


Locking

I2CBus objects have a lock built into them.

If you are only using an I2C Bus indirectly (e.g. with Digital on the I2C Bus) the client object (Digital) will handle locking for you.

You will need to use the lock if both the following are true:

· You are using an I2CBus object directly with code like net.On

~ AND ~

· You are using the same I2C Bus, either directly, or indirectly through a client object, in another task.

For the sake of good programming practice, we recommend that all transactions using I2CBus objects be locked, even if you only have one task accessing the bus: you may add another one later. See the typical code examples in the paragraphs below.

SeeAlso

See also Locking in the Tutorial

The table below defines allowable sequences of operations on the bus.

Bus Operation | May be followed by
On | Off, Put
Off | On
Put | On, Off, Put, Get, GetLast
Get | Get, GetLast,
GetLast | On, Off

A typical sequence of operations on the bus (including locking) is shown below:

TO write
net . Lock
net . On
net . Put (160) ;device's write address
net . Put (20) ;the first data byte sent
net . Put (64) ;the second data byte sent
net . Off
net . UnLock
END

TO read
net . Lock
net . On
net . Put (161) ;device's read address
b1 := net . Get ;get the first data byte
b2 := net . Get ;get the second data byte
b3 := net . GetLast ;get the last data byte
net . Off ;and turn off
net . UnLock
END

If only one data byte is being read from the bus, then GetLast is used immediately after setting up the read address.


Find

obj . Find (Int address)

This checks for the presence of a device on the network, returning TRUE or FALSE. It addresses the device and checks for an acknowledge pulse. This message should not be used inside net.On / net.Off, as it does it’s own On/Off. Find does its own locking, so explicit locking is not necessary.


Get

obj . Get rarrow Int

Reads a data byte from the bus.

The table below defines allowable sequences of operations on the bus.

Bus Operation | May be followed by
On | Off, Put
Off | On
Put | On, Off, Put, Get, GetLast
Get | Get, GetLast
GetLast | On, Off

SeeAlso

See also GetLast


GetLast

obj . GetLast rarrow Int

Gets a byte from the bus and terminates communication with the bus after a zero or more Gets.

The table below defines allowable sequences of operations on the bus.

Bus Operation | May be followed by
On | Off, Put
Off | On
Put | On, Off, Put, Get, GetLast
Get | Get, GetLast
GetLast | On, Off

SeeAlso

See also Get


Off

obj . Off rarrow I2CBus

Generates the stop condition on the bus to terminate communication with a device.

The table below defines allowable sequences of operations on the bus.

Bus Operation | May be followed by
On | Off, Put
Off | On
Put | On, Off, Put, Get, GetLast
Get | Get, GetLast
GetLast | On, Off


On

obj . On rarrow I2CBus

Generates the start condition on the bus to initiate communication with a device. If the bus was not in the stopped state, then it generates a repeated start.

The table below defines allowable sequences of operations on the bus.

Bus Operation | May be followed by
On | Off, Put
Off | On
Put | On, Off, Put, Get, GetLast
Get | Get, GetLast
GetLast | On, Off


Put

obj . Put (Int byte) rarrow I2CBus

Sends a data byte to the bus.

The table below defines allowable sequences of operations on the bus.

Bus Operation | May be followed by
On | Off, Put
Off | On
Put | On, Off, Put, Get, GetLast
Get | Get, GetLast
GetLast | On, Off

LIMIT

byte will be masked to the range 0 - 255


Printing

PRINT obj

Printing an I2CBus object generates a list of all the devices connected to bus:

MAKE net2 I2CBus(2)

PRINT net2

Devices on the I2C network No.2:

Number Channels Device Description

------ -------- ------ -----------

124 496-503 PCF8574A 8 digital I/O lines

126 504-511 PCF8574A 8 digital I/O lines

162 PCF8582/83... RTC/EEPROM...

Note that this feature can only guess the devices attached to the bus, as there are some devices that map onto the addresses of the more common devices.


Keypad

Object Types

Keypad

The Keypad object is used to interface to a variety of keypads. Most keypads consist of one or more PCF8574 ICs on the I2C Bus scanning a key matrix. However, one type of keypad scans ‘virtual’ keys on a TouchScreen object.

Keypad has a sub-object, InputBuffer, that automates some of the functions most applications need a keypad to perform.

Summary of messages

MAKE

Asserted

Get

GetLast

InputBuffer

Key

NotAsserted

Nudge

Update


Creation

MAKE obj Keypad (Int type, Int chan1, Int chan2)

MAKE obj Keypad (TouchScreen ts)

There are two forms of the MAKE command for Keypad, one for matrix keypads, and one for use with a TouchScreen ‘virtual keypad’. In operation the two types of keypad are very similar.

Matrix Keypads

The parameters are as follows:

type: keypad type; see the table below.

chan1: Channel number indicating a PCF8574 IC

chan2: Channel number indicating a second PCF8574 IC (only for 8 by 8 and 12 by 4 matrixes)

Matrix | Type Parameter | No. of PCF8574 needed | How rows and columns map onto PCF8574(s)
4 by 4 | 0 | 1 needed | First four channels: columns Last four channels: rows
8 by 8 | 1 | 2 needed | First PCF8574: columns Second PCF8574: rows
12 by 4 | 2 | 2 needed | First 4 channels of the 1st PCF8574: rows Remaining 4 channels of the 1st PCF8574 and the 2nd PCF8574: columns

Key numbering starts at 0 (zero) for the key at the first row/column position. The first row (or column) is the one with the lowest channel number. Key 1 is on the same row, next column along, and so on.

Any subset of a matrix may be supported, for example a 12 by 3 matrix may be implemented by the 12 by 4.

Examples:

MAKE kpd1 Keypad (0,168) ;4x4 keypad, 1st I2C bus, PCF8574

MAKE kpd2 Keypad (0,248) ;4x4 keypad, chip 1, 1st I2C bus, PCF8574A

MAKE kpd3 Keypad (0,240) ;4x4 keypad, chip 2, 1st I2C bus, PCF8574A

MAKE kp Keypad (1,504,496);8x8 keypad, chips 1 & 2, 2nd I2C bus,PCF8574A

MAKE kpd Keypad (2,496,504);12x4 keypad, chips 1 & 2, 2nd I2C bus,PCF8574A

Touchscreen Keypad

In this case there is only one parameter to the MAKE: the TouchScreen object. See TouchScreen for details of how to define the Touchscreen object and its virtual keys.

MAKE kpd Keypad (ts)

memoryUse

Each Keypad uses around 152 bytes of memory. Any InputBuffers will use an extra small amount of memory.


Asserted

obj . Asserted rarrow Int

Asserted returns TRUE if any of the keys on the keypad are currently being pressed. The GetLast message will tell you which key it was.

SeeAlso

See also Key, GetLast, Get


Get

obj . Get rarrow Int

Waits for no keys to be pressed on the keypad, then waits for a key to be pressed, and returns the logical key number of the key pushed.


GetLast

obj . GetLast rarrow Int

Returns the key number of the key that caused the last Asserted message to return TRUE.

SeeAlso

See also Asserted.


InputBuffer

InputBuffer is a sub-class of Keypad used to implement higher-level functions such as detecting distinct key presses, key buffering, and auto-repeat.

SeeAlso

See separate section Keypad:InputBuffer


Key

Key returns the number of any key that is currently being pressed, or -1 if no keys are being pressed.

Example:

Every 30

[

SELECT CASE kpd.Key

CASE 0

[

; Do key 0 action

]

CASE 1

[

; Do key 1 action

]

CASE ELSE

[

; 'No key' action

]

]

SeeAlso

See also Keypad.InputBuffer.


NotAsserted

obj . NotAsserted rarrow Int

NotAsserted returns TRUE if none of the keys on the keypad are currently being pushed.

Note: If a key was being pressed then GetLast is set.


Nudge

Nudge is a sub-class of Keypad.

SeeAlso

See separate section Keypad:Nudge


Update

obj . Update

This message is only relevant if an InputBuffer or any Nudges have been defined. Update checks the keypad for key presses and uses them to update the InputBuffer and process the Nudges.

Update should be called regularly, say from within an EVERY loop. The loop may contain other code, so long as it doesn’t upset the loop timing. A typical loop period is 50mS though you should experiment with your set up to determine the optimum period.

See here for example code.


Keypad:InputBuffer

Object Types

Keypad:InputBuffer

An InputBuffer to a Keypad object provides higher functions that the basic Keypad doesn’t have: Auto Repeat and Key Buffering, for example. These can help to simplify your keypad input routines.

Auto repeat is achieved by holding a key down. Normally holding a key down would result in a single key press being detected, but with auto-repeat, holding the key down is interpreted as repeated key presses.

Key buffering is used to detect and store key presses for later use. When the key buffer is full, new key presses are ignored.

For the InputBuffer to work correctly, the parent Keypad must be given regular calls to its Update message. This may be done either within the task that uses the key presses, or in a separate 'keypad scan' task. Either way it is important that the keypad is scanned regularly by sending Update to the Keypad, say from inside an EVERY loop.

Currently the key buffer holds up to one key press - this is usually the most that is needed.

Summary of messages

Creation
Get

Key

Flush

Period

Queue

Time


Creation

To create a Keypad InputBuffer, a message is sent to the Keypad object.

kib := kpd . InputBuffer(Int rpt_pd, Int rpt_del)

This message takes two parameters: the auto-repeat period, and auto-repeat delay.

rpt_pd is the time between each auto-repeat of the key when a key is held down, measured in multiples of the Keypad’s Update period. If this parameter is not present, then it defaults to zero. If the repeat period is set to zero auto-repeat is turned off.

rpt_del is the time taken before auto-repeat starts, also in multiples of the Update period. If this parameter is not present, then it defaults to the repeat period.

The example below uses an InputBuffer to provide auto-repeat on some keys that alter the value of the variable target_temp.

Note that the keypad scanning (kpd.Update) is done in the same task as the key actions here. It could have been done in a different task if the key actions needed to take longer than the scan period allowed.

MAKE kpd Keypad(0,496)

key_buff := kpd.InputBuffer(2,15)
...

#define DN_KEY 0
#define UP_KEY 1
#define EXIT_KEY 3

EVERY 50 ;Keypad scan period
[
kpd . Update ;Scan the Keypad
the_key := key_buff.Key
IF the_key >= 0 ;Any key pressed?
[
SELECT CASE the_key ;Select an action for each key
CASE DN_KEY
[
IF target_temp > MIN_TEMP
target_temp := target_temp - 1
]
CASE UP_KEY
[
IF target_temp < MAX_TEMP
target_temp := target_temp + 1
]
CASE EXIT_KEY
[
BREAK ;Drop out of this menu
]
CASE ELSE
[
buzz_wrong_key
]
]
]


Get

obj . Get rarrow Int

Returns a key from the buffer if there is one, or waits for a distinct key press on the keypad.


Flush

obj . Flush

Clears out the key buffer.


Key

obj . Key rarrow Int

Returns a key number from the key buffer, or –1 if no key in the buffer; never waits.


Period

obj . Period lrarrow Int

Period allows the value of the auto-repeat period to be set and read. Note that the new value of Period won’t take effect until the next auto-repetition.

This may be used to implement an accelerating auto-repeat function, for example:

MAKE kpd Keypad (0,496)
ib := kpd.inputbuffer(10,20)

START EVERY 30 kpd.Update

EVERY 10
[
IF ib.Time >= 50
ib.Period := 2
ELSE
ib.Period := 10

SELECT CASE ib.Key
CASE 0
PRINT "key0",ib.Time, CR
CASE 1
PRINT "key1",ib.Time, CR

]

SeeAlso

See also Time


Queue

obj . Queue rarrow Int

Returns the number of keys in the buffer: only zero or one currently.


Time

obj . Time rarrow Int

Time returns the number of Update cycles the current Key has been held down for. This doesn’t get reset when the key is released, so it is also the time the last key pressed was held down for.

This may be used to implement an accelerating auto-repeat, as well as other useful functions.

SeeAlso

See also Period


Keypad:Nudge

Object Types

Keypad:Nudge

Nudge is not recommended for new designs. It has bugs in it that we will not fix. InputBuffer may be used much more flexibly, though with a little more coding, to do the same job.

One or more Nudge objects may be created via a Keypad object to automatically increment and decrement the contents of integer variables using pairs of keys on the Keypad.

Summary of messages


Creation

obj . Nudge

(

Int mode,

Pointer pointer,

Int min,

Int max,

Int key_up,

Int key_down,

Int wait,

Int increment,

Int initial_wait,

) rarrow Nudge

A Nudge is formed by sending the Nudge message to a Keypad object. Nudge takes nine parameters:

mode is always zero (0).

pointer points to the integer to be nudged.

min and max are the limits that the Nudge is allowed to take the variable between.

key_up and key_down are the key numbers of the two keys controlling the nudging of the value in positive and negative directions. The value of the variable is incremented (or decremented) by increment every time one of the keys is pressed.

initial_wait is the number of Update cycles the Nudge waits while one of the keys is held down before the it starts adding increment to the value every wait Update cycles.

For Nudges to work correctly, the parent Keypad must be given regular calls to its Update message. This may be done either within the task that created the Nudges or in a separate keypad scan task. Either way it is important that the keypad is scanned regularly by sending Update to the Keypad, say from inside an EVERY loop.

MAKE kpd Keypad(0,496)
a := 0
n := kpd.nudge(0,@a,-10,10,0,1,10,1,20)

LIMIT

wait, increment and initial_wait must be in the range 0 - 255.


Pointer

obj . Pointer lrarrow Pointer

Pointer allows the integer variable that the Nudge modifies to be changed. The pointer value may also be read.

n . Pointer := @b

Changing Pointer leaves the values of all the other parameters of the Nudge unchanged.


Die

obj . Die

Die will remove the Nudge from the Keypad object’s list of Nudges. It is important to ‘kill’ Nudges when they are no longer required as otherwise they will continue to alter the value of whatever variable they are pointed at when their keys are pressed.

LIMIT

Pointer must be a pointer to an integer variable.


NIL

Object Types

NIL

NIL is a special object that is used as a placeholder for any other type of object, or to represent ‘no object’.

NIL will accept any message, and will return FALSE to all of them.

It is useful for situations where, in the normal course of events, an object is used but sometimes you wish to allow for situations where ‘no object’ needs to be represented.

The most common example of this is substituting the value NIL for an output stream object, for when you want PRINT output to be discarded:

lcd := NIL ;all PRINT TO lcd will now be discarded.

Testing for NIL is done with = or <>, as follows:

IF lcd = NIL

[

…

]

Summary of messages

All messages are accepted


Creation

obj := NIL

The value NIL is defined in Venom so you don’t need to use MAKE or NEW to get a NIL object.

memoryUse

NIL is a Zero-Memory object


NumberReader

Object Types

NumberReader

NumberReader is for entering numbers using a keypad, as on a calculator. For visual feedback the digits of the number may be displayed on a display device (e.g. an LCD) while the number is being assembled.

It is easy to create number-entry routines to enter integer, floating-point, or hexadecimal numbers. The displayed text may be initialised to any text string to prompt the user – either with a default value, or with any other text.

There are two distinct ways of using a NumberReader: Put Mode, and Get Mode.

Of these, Put Mode is the easiest to understand and gives the greatest flexibility. There is some example code under the Put message.

Get Mode requires less coding and may be useful in some circumstances.

Summary of messages

MAKE

Conversion

Get

GetLast

Put

Reset

Value

Width

PRINT TO

PRINT


Creation

MAKE obj NumberReader (Ptr source, Int base, Int max_width)

source is a pointer to any object that understands the message Get, often a Keypad.

If you are going to only use the NumberReader in 'Put' mode, then the value of this parameter is ignored.

base determines whether to read decimal or hexadecimal numbers:

base | Number type
0 | Decimal
1 | Hexadecimal

The optional third parameter max_width allows a maximum number of digits in the number (including any decimal point and minus sign characters) to be specified. The default width is 10 digits.

Once the NumberReader is full, further key presses will be ignored.

The first of the following examples creates a decimal NumberReader with the default maximum field width; the second example creates a hexadecimal NumberReader that will only accept numbers to a maximum of 4 digits.

MAKE kpd Keypad(0,496)

…

MAKE n1 NumberReader (@kpd,0)
MAKE n2 NumberReader (@kpd,1,4)

SeeAlso

See also Conversion, Width, Accepting Print; the Keypad object


Conversion

obj . Conversion
(
Int Enter_key,
Int Decimal_key,
Int Minus_key,
Int Delete_key,
Int Cancel_key,
Int Dig0, Int Dig1, Int Dig2, Int Dig3, Int Dig4,
Int Dig5, Int Dig6, Int Dig7, Int Dig8, Int Dig9,
Int DigA, Int DigB, Int DigC,
Int DigD, Int DigE, Int DigF
)

The conversion message sets the logical key numbers for each of the digits and special function keys on the particular keypad you are using.

The NumberReader then knows how each physical key is to be used in entering a number.

The logical key number is the number returned by Keypad.Get when you press that key. On a 4 x 4 matrix logical key numbers range from 0 - 15.

The 15 or 21 parameters to Conversion are explained here:

· The first five parameters list the logical key numbers of special function keys.
· The next ten parameters list the logical key numbers of the decimal digit keys.
· The last six (optional) parameters list the logical key numbers of any hexadecimal digit keys.

The five special functions are listed, in parameter-list order, in the table below, together with details of their actions:

Function | Action
Enter | Exit from Get. Only used in the Get message
Decimal | Enter a decimal point; only one will be allowed
Minus | Adds or removes a minus sign to the left of the number
Delete | Removes the last digit; may be done repeatedly
Cancel | Re-instates the default text – and exits if in the Get message.

If any particular special function is not required then the entry in the Conversion parameter list should be ‘-1’ to indicate 'no key'.

Conversion may be re-sent at any time to change the functions of the keys.

Here is an example of the use of Conversion. Note how the Delete function is disabled by being assigned to key ‘-1’:

#define ENTER_KEY 7
#define DELETE_KEY -1
#define CANCEL_KEY 15
#define DECIMAL_KEY 3
#define MINUS_KEY 12
nr . Conversion ;Assign functions to keys on the keypad.
(
ENTER_KEY,
DECIMAL_KEY,
MINUS_KEY,
DELETE_KEY,
CANCEL_KEY,
;Digits 0-9 on these keys:
13,0,1,2,4,5,6,8,9,10
)


Get

obj . Get rarrow Int or Nil

Note: Using Get is not the recommended mode of operation. See Put.

Get fetches a complete number from the NumberReader. The NumberReader object repeatedly sends a Get message to the source object set in MAKE. Get does not return until the Enter key is pressed, or the operation is cancelled with the Cancel key. Because Get does not return until the number is finished, any visual feedback can only be handled by a separate task. If you want to have more control while the number is being entered, use the Put message.

Get gets key presses from the Keypad object and uses the conversion list to assemble these into a number. Get returns when it receives the Enter or Cancel keys, at which point it returns the value of the number. This is either a floating-point value or an integer.

GetLast may be used to determine whether Enter or Cancel terminated the process.

SeeAlso

See also Put, GetLast


GetLast

obj . GetLast rarrow Int

Note: Using GetLast is not the recommended mode of operation.

GetLast returns the value of the last key press the NumberReader received. This allows the application to determine whether the user exited from Get with Enter or Cancel.


Put

obj . Put (Int Key)

Put is used to send key numbers to the NumberReader, which it interprets as digits or special functions.

Put takes one parameter: the key number to be sent to NumberReader. Key numbers are usually read from a Keypad object, or Keypad InputBuffer, but can come from any other source if desired.

To provide visual feedback of the number being entered, the partially assembled number should be displayed by printing the NumberReader to an output device.

Example Code

An example of using Put to drive NumberReader appears below. This code will work with the VM-1 starter kit.

; Keypad:
; Logical Key number
; 0 1 2 3
; 4 5 6 7
; 8 9 10 11
; 12 13 14 15
; Associated Function
; 1 2 3 'Float' (dec point).
; 4 5 6 Enter
; 7 8 9 Delete
; Neg 0 B Cancel
; Key Legend
; 1 2 3 F
; 4 5 6 E
; 7 8 9 D
; A 0 B C

;DEFINE some key numbers.
#define ENTER_KEY 7
#define DELETE_KEY 11
#define CANCEL_KEY 15
#define DECIMAL_KEY 3
#define MINUS_KEY 12

TO init
MAKE lcd AlphaLCD (20 2 0) ;The display device
MAKE kpd Keypad (0,248) ;The keypad device
MAKE nr NumberReader (@kpd,0,8)
nr . Conversion ;Assign functions to keys on the keypad.
(
ENTER_KEY,
DECIMAL_KEY,
MINUS_KEY,
DELETE_KEY,
CANCEL_KEY,
;0-9 on these keys:
13,0,1,2,4,5,6,8,9,10
)
END

TO test_num_reader
LOCAL key_num

LOCAL def := 123.45 ;Our default value
PRINT TO nr, def:5:2 ;Set default value text

; nr.Reset ;[use this if line above not used]
DO
[
PRINT TO lcd, HOME, nr ;Visual feedback on LCD
key_num := kpd.Get ;Get a key number
nr . Put(key_num) ;Give it to the NumberReader
]

UNTIL key_num = ENTER_KEY

OR key_num = CANCEL_KEY ;Exit when 'Enter' or 'Cancel' key seen

PRINT nr.Value , CR ;Report the result
END

The code reads digits at the keypad and displays them on an LCD. When the ENTER key is pressed the code reports the value of the number entered.

The number is given a default value of 123.45.


Reset

obj . Reset

Resets the digit-string currently held by the NumberReader to the default text (‘0’ unless another default has been set using PRINT TO).

SeeAlso

See also Accepting Print


Value

obj . Value rarrow Int or Float

Returns the value of the number currently held in the Number Reader buffer. This value is valid at all stages of number entry.

Value will return an integer if there was no decimal point in the assembled number, otherwise it will return a floating-point value.

· If you only want integers then don’t assign a decimal point key.
· If you only want floating-point values then use obj.Value AS FLOAT to read the value.
· If you want to detect the type of the returned value use the TYPEOF function:

IF TYPEOF nr.Value = TYPEOF 1.0 ;is it a float?

[

…

]

By detecting the type of the value it is possible to prompt the user to enter a decimal point if you require them to do so.

For visual feedback it is better to print the number reader object itself, rather than Value.

SeeAlso

See Printing


Width

obj . Width lrarrow Int

Sets (or reads) the maximum number of characters allowed in a number, including any minus sign or decimal point. Any key presses that would increase the number of characters beyond this width are ignored. If the Minus or Decimal keys are defined, then a space is always reserved for each of these digits: numeric digits won’t be allowed to fill the whole width.

Setting width may truncate any currently assembled number, and any default value text.

LIMIT | The maximum value for width is 18.
SeeAlso | See also: Creation, Put, Accepting Print


Accepting Print

Printing to a NumberReader will set the initial string (a number, or any other text) displayed by the object when it is printed. This may be used as a ‘default value’ prompt to the user, or it could indicate the name of the parameter.

Examples:

def_val := 123.45

nr . Width := 8

PRINT TO nr1,def_val:4:2

…

-->PRINT nr

123.45

Or…

PRINT TO nr1,”Power”

…

-->PRINT nr

Power

If a digit, minus or decimal point key is pressed when the initial text is shown then the initial text is replaced by the digit or sign.

If the Delete key is pressed first, then one character is deleted from the right of the initial text, and any subsequent digits will be added to the right.

Printing to the NumberReader also sets its internal default text – the string of digits or other text that is re-instated when CANCEL is pressed or the Reset or Get message is sent.

Text printed to a NumberReader is processed as follows:

· Space characters at the start of the text are stripped off.
· If the text exceeds the current fieldwidth of the NumberReader then the rightmost characters are lost.
· The resulting text will print displayed right justified when the NumberReader is printed.

Note: the default text is initialised to ‘0’ (a single numeric zero character) when the NumberReader is first created.


Printing

PRINT obj :fw

Printing a NumberReader prints the current number it has assembled. If a fieldwidth (fw) is supplied then it will print in the given fieldwidth.

NumberReader holds the digits it has assembled in a buffer so that the number may be printed as it is being assembled, and afterwards. This buffer is not cleared until either Get or Reset is sent, or the NumberReader is ‘printed-to’.

SeeAlso See also: Value, PRINT TO, Reset


OnBoardLED

Object Types

OnBoardLED

OnBoardLED controls the behaviour of the LED mounted on the VM-1 board, and also channel 15, which the LED is attached to.

The LED may be told to turn on or off, flash various patterns and at various rates, so it may be used to signal the current state of the VM-1 to users.

Summary of messages

MAKE

Asserted

Flash

Off

On

Toggle

Value

PRINT


Creation

MAKE obj OnBoardLED

The OnBoardLED object is created with the LED turned off. (Note that in the default startup routine, the OnBoardLED object is created, and then set to flash pattern 10 if the VM-1 is in run mode).

memoryUse

OnBoardLED is a Zero-Memory object


Asserted

obj . Asserted lrarrow Int

An active variable that allows the state of the OnBoardLED object to be read or set. It returns TRUE if the LED is on, and FALSE otherwise. When setting the OnBoardLED via Asserted - TRUE turns the LED on, and FALSE turns it off.


Flash

obj . Flash (Int flash_num)

Makes the LED flash:

Flash Number | Description
0 | Off
1 | On
2 - 9 | --Not used yet--
10 | Short flash approximately once a second
11 | Two short flashes approximately once a second
12 | Three short flashes approximately once a second
13 | Signals "SOS" in Morse Code
14 | Signals "OK" in Morse Code
15 | --Not used yet--

LIMIT

The maximum flash number is 15.


Off

obj . Off

Turns the LED off.


On

obj . On

Turns the LED on.


Toggle

obj . Toggle

Inverts the state of the LED.


Value

obj . Value lrarrow Int

An active variable that allows the state of the OnBoardLED object to be read or set. It gives the logic level of the channel the LED is connected to. It returns 0 if the LED is on, and 1 otherwise. When setting Value - 0 turns the LED on, and 1 turns it off.


Printing

PRINT obj

Prints "ON " or "OFF" (always three characters) depending on the state of the LED.


OneWire

Object Types

OneWire

The OneWire object is a Dallas 1-Wire™ Bus driver. This bus uses a single wire to carry power and data to a distributed network of devices. The communication protocol is detailed in Dallas documents and device datasheets.

Summary of messages

MAKE

Checksum

Find

Get

High

Low

Put

Reset

PRINT

One of the most important features of the 1-Wire bus is that every device manufactured for the bus has a completely unique 64-bit serial number burned into it’s ‘ROM’. This means that any device connected to your application can always be addressed uniquely.

The first 8 bits of the 64-bit serial number are the family code that indicates what capabilities the device has; i.e. what commands it will obey, and maybe what memory capacity it might have.

The last 8 bits of the serial number are a CRC (Cyclic Redundancy Check) of the previous 56 bits. This provides a high level of data-validation when using the serial number to address devices.

Hardware

The data channel should be pulled up with a resistor of the correct value. ~5K may be used generally, but see the Dallas datasheets for discussions about long cables and large numbers of devices.

If you need the active pull-up a ‘logic level’ P-channel MOSFET should be used. Connect source to 5V; drain to the data channel; and gate to the pullup channel.

1-Wire Protocol

Briefly, the 1-Wire bus master (VM-1) reads and writes data on the bus by pulling the bus low for long or short pulses to indicate 1’s and 0’s. Timing is not very critical.

1-Wire bus communications always follow a very simple sequence:

Reset

This initiates a communication by putting all the devices on the bus into the initial state. Reset will elicit a response from every device on the bus called the ‘presence pulse’. This may be used to determine whether there are any devices connected.

ROM command

This addresses a unique device on the bus – either by assuming it is the only device present, or by addressing a device by its unique serial number.

SEARCH ROM and MATCH ROM should be used when more than one device could be connected to the bus.

Command | Code | Decription
SKIP ROM | $CC | Address all the devices on the bus at once – or just one device if only one is present.
MATCH ROM | $55 | Address just one device by sending its ROM data to the bus after this command.
READ ROM | $33 | The next 8 bytes read are the ROM data of the one device on the bus.
SEARCH ROM | $F0 | [Use the Find message to do this for you, as SEARCH ROM can’t be used directly]

Transport layer command

This is generally a data transfer operation where one or more bytes of data are transferred either to or from the bus.

Command | Code
READ MEMORY | $F0
WRITE SCRATCHPAD | $0F
READ SCRATCHPAD | $AA
COPY SCRATCHPAD | $55

The details of how to use these commands are beyond the scope of this help file. Please read the Dallas 1-Wire bus documentation or the device datasheet for further information.

The bus communication can end at any point in this 3-stage sequence. For example you may just want to issue the Reset command to determine whether any devices are present.

New Device on the bus

When a device is first connected to the 1-Wire bus it will issue a presence pulse without being prompted by a reset from the bus master.

If you want to detect these new device presence pulses then it is possible to use a PulseWidthIn object to detect them. This simple application prints out the devices it finds on the bus every time a new one is added.

TO init
MAKE detect PulseWidthIn(3, 0)
MAKE b OneWire(3 4)
END

TO main
FOREVER
[
detect.go
AWAIT detect.Done
WAIT 5
PRINT b
]
END

High-current Pull-up

Some 1-Wire devices need a high-current pull-up during certain parts of the 1-Wire communication in order to function correctly. See the messages High and Low.

Limitations

This implementation of the 1-Wire bus does not cover 1-Wire interrupts of either type.

It has not been determined whether it covers the programming of 12V EPROM devices.


Creation

MAKE owb OneWire(Int data , Int pullup )

data is the channel to use for the data line.

pullup is the optional channel to control the high-current pull up required by some 1-Wire devices such as temperature sensors.

Currently the only valid values for data and pullup are 3 & 4:

MAKE owb OneWire (3)

MAKE owb OneWire (3 , 4) ; use active pull-up.


Checksum

Checksum (Int type) lrarrow Int

Checksum is an active variable that sets and reads either of two CRC accumulators kept by the OneWire object.

The 1-Wire bus uses two types of CRC extensively in its operation. These are an 8-bit CRC and a 16-bit CRC.

owb . Checksum(0) ; returns the 8-bit CRC value

owb . Checksum(1) ;returns the 16-bit CRC value

owb . Checksum(0) := 0 ; sets the 8-bit CRC value

owb . Checksum(1) := val ;sets the 16-bit CRC value

Every Put to the bus or Get from the bus using the OneWire object updates both these CRCs with the value of the data byte read or written. This can then be used to implement the protocols for data validation described in the Dallas literature.

In particular, when reading the 64-bit ROM data from a device, the last 8-bits are an 8-bit CRC of the previous 56 bits. The definition of the Dallas 8-bit CRC is such that the total CRC of all 64-bits will be zero.

The Find message and PRINT use this CRC internally to determine the validity of the data they are reading.

The 16-bit CRC (or CRC-16) is generally used for validating the larger amounts of data transferred during data storage/retrieval operations on the 1-Wire bus.

The CRC-16 is normally used in an inverted form, where the two bytes of CRC value sent after the data is the equivalent to

NOT owb . Checksum(1) AND $FFFF

[The least significant byte is sent first.]

When reading a block of data including the inverted 16-bit CRC, the final CRC value read will be $B001.

The CRC-16 is also normally initialised to the value of the page number of the memory being addressed to provide security of addressing as well as data.

See the Dallas literature for a deeper explanation of these issues.


Find

Find uses the 1-Wire bus SEARCH ROM command to get each unique 64-bit ROM serial number for each of the devices connected to the 1-Wire bus. The 1-Wire bus’s MATCH ROM command can then be used to address any one device individually.

Find ( Int max_devices , Int data_addr) rarrow Int

data_addr is an address in RAM to put the ROM data. The best way to get some memory is to create a writable Array and use its Address message.

Take care when passing the value of data_addr as getting it wrong will cause the system to misbehave in an unpredictable manner.

max_devices is the maximum capacity of the array. Since a 1-Wire ROM is 8 bytes long, max_devices should be less than the array capacity divided by 8.

Find will return the number of device ROMs it has found, even if that number exceeds max_devices. If there were no devices present, or there was a CRC error in any of the data then Find will return zero.

After a successful Find, the Array will have each device’s unique ROM data in successive 8-byte blocks.

The order of bytes in within the 8-byte block is least-significant byte first. The ordering of devices within the whole array is based on the 1-Wire bus SEARCH ROM algorithm, where zero-bits in the least significant bit positions take the highest priority. This will automatically tend to sort devices according to family type, though not in normal numerical order.

TO init
MAKE b OneWire (3)
MAKE data_store array (8, 64, 0)
END

TO main
roms_found := b . find(8 , data_store . pointer )
PRINT "found:",roms_found,cr
END

SeeAlso | See also PRINT, Put
LIMIT | Find is currently limited to 255 devices.


Get

Get will read one byte, or a block of bytes, from the 1-Wire bus:

Get rarrow Int

… reads a single byte from the bus.

Get (Int n_bytes , Int data_addr)

… reads n_bytes from the bus and puts them in memory at address data_addr.

Every byte read from the bus is combined with both CRC accumulators held by the object to keep a running total of the overall CRCs.

The data_addr parameter is usually found by taking the Address of an Array. Take care when passing the value of data_addr as getting it wrong will cause the system to misbehave in an unpredictable manner.

SeeAlso

See also Checksum


High

High will turn on the active pull-up channel immediately after the next byte written to the bus. If a suitable MOSFET is connected then a high current pull-up is applied to the bus until the Low message is issued.

b . High ;high-current pull-up on after …

b . Put(byte) ; … this byte.

WAIT 11 ;wait for a minimum of 10 ms.

b . Low ;pull-up off.

SeeAlso

See also Low


Low

This immediately turns off the high current pull-up channel.

SeeAlso

See also High


Put

Put will write one or many bytes to the 1-Wire bus.

Put (Int byte)

… writes a single byte to the bus.

Put (Int n_bytes , Int data_addr)

… writes n_bytes from the memory address data_addr to the bus.

You can use both of these when building up commands, such as MATCH ROM:

TO match(n)
b.reset ;initiate communuication.
b.put($55) ; ‘$55’ is the MATCH ROM command.
b.put(8 , data_store.pointer + 8*n) ;send the ROM id

;for the device.
;we have now addressed a single device…

END

Every byte written to the bus is combined with both CRC accumulators held by the object to keep a running total of the overall CRCs.

SeeAlso

See also Checksum


Reset

Reset puts a reset pulse on to the 1-Wire bus and returns a positive number if there was a ‘presence pulse’ detected – i.e. there were one or more devices detected on the bus.

If there were no devices then Reset will return zero.

Reset rarrow Int

MAKE b OneWire(3)

If b . Reset

[

…

]

Reset is used to initiate all command sequences on the 1-Wire bus.

May be implemented later: Reset detects if bus is short-circuited.


PRINT

Printing the OneWire object tells you the object type and lists all the devices connected to the bus. The format emulates the CRC, family code and serial number stamped on to the stainless steel can on Dallas iButtons:

MAKE b OneWire(3)

PRINT b

One Wire Bus:

00 14

000000ABCE06

7F 14

000000AC3B4D

17 01

0000082413C4

2F 01

00000822DB02

AD 23

000000175AAA

1A 23

0000000283B1

C1 23

0000001760C3

7 Devices found.

If there was a CRC error during the print, then this will be indicated:

PRINT b

One Wire Bus:

00 00

000000000000

CRC-error - try again.


OperatingSystem

Object Types

OperatingSystem

The OperatingSystem object system, defined in the default startup routine, provides access to system-wide features of the hardware, operating system and compiler.

Note that Venom-SC allows all system messages to be called by just typing the message name alone, e.g.

Reset

Is the same as

system.Reset

Summary of messages

MAKE

Checksum

Copy

Debug

ErrorAction

Free

Output

Protect

Reset

Run

RunMode

UserSwitch

Valid

PRINT


Creation

MAKE obj OperatingSystem

An object called system of type OperatingSystem is made by the default startup routine:

MAKE system OperatingSystem


Checksum

Checksum rarrow Int

This is used to find the checksum of all the bytes in the Venom-SC system code.

SeeAlso

See also Valid


Copy

Copy(Int mode, Int flags)

Copy is used to

· Copy the flash device in its entirety: Venom system and any application code
· Download a new version of Venom-SC from the Micro-Robotics website www.microrobotics.co.uk
· Create a distribution flash for use with VM-1e.

The syntax of the flash programming commands is:

Copy(0,flags) ; to copy the current flash

Copy(1,flags) ; to download a new version

Copy(2,flags) ; to create a distribution flash for VM-1e

The instructions and progress reports for each operation will appear at the terminal. The flags parameter is a binary pattern that tells the Copy message which optional operations to perform in sequence. In general use a value of TRUE (-1) for the most comprehensive operation. See the table for the meaning of individual flags.

Flag | Flag Value | Action
SHOW ID | 1 | Print ‘Silicon signature’ ID
ERASE | 2 | Erase the device
PROGRAM | 4 | Program the device
VERIFY | 8 | Verify the program
CHECK ID | 16 | Check the flash ID is supported, halt if not supported

Example:

Copy(0,TRUE) ; Print flash ID, erase, program, verify, check ID

Code that has been downloaded from the website can’t be verified by Copy, but you can verify the new code by calling the Valid message when you first use it.

Hardware | In order to use the Copy message you will need the correct hardware. This is currently a VM-1 or VM-1e Control Computer and the Application Board 2 (Product Code 5805 - free with the Starter Kit).
SeeAlso | ROMing

Important note: If the device has not been erased before programming, then the copy or download operation may fail ungracefully. The controller will reset on the watchdog. You will probably have to reset the controller and you may have to exit from the terminal emulator.

SeeAlso

See also Valid


Count

Count lrarrow Int

This system variable is incremented every time the system restarts. It is used internally to make sure that certain processes do not initialise identically each time the VM-1 is restarted or reset, and it can also be used to count the number of times the VM-1 has been restarted.

Count is a 16 bit value.


Debug

Debug ( Int n, … )  lrarrow  Any

The debug operating system message has options allowing the internal state of the Venom-SC compiler & OS to be viewed and modified, as well as other more sophisticated functions.

As with all OperatingSystem messages, there is no need to use the object name - simply using the message name is enough.

Typing Debug with no parameters will list all the available options:

-->Debug

System Debug Command

Debug (0) Heap Dump

Debug (1 , flgs) Garbage scan

Debug (2) Dump Venom stack

Debug (3) Runtime debug flags

Debug (4,addr,lines) Mem Dump Addr

Debug (5) Keywords

Debug (6) System Version

Debug (7) Compile code from object

Debug (10) Analyse code

In detail:

Debug(0) | Dump a listing of the system heap to the main serial port. Not likely to be very useful to Venom programmer.
Debug(1, flags) | The Venom Garbage Scanner. See below for details.
Debug(2) | Dump the Venom Stack from the point at which this is called from within your program.
Debug(3) | Set and read the value of the Runtime Debug Flags as a 32-bit binary number. The flags values are listed below.
Debug(4, addr, n) | Dump memory contents starting at addr, optionally listing n lines of 16 bytes, in Hex and ASCII formats. List is dumped to main serial port.
Debug(5) | Keywords: list all the Venom-SC keywords, class names, message names, etc.
Debug(6) | Return the system version number as an integer representing a reversed date, e.g. 20060615 is the 15th June 2006.
Debug(7) | Compile code from a source of text during Runtime. See below for details.
Debug(10) | Analyse the compiled code for procedures and variables that are redundant or uninitialised.
 | Higher Debug options are not currently public. Do not use them as they may break the system.

Garbage Scanner

The Garbage Scanner finds memory blocks that have been lost to the system due to memory leaks. A memory leak is where your application program loses track of an object and so can never delete it.

During normal operation of both the Venom-SC compiler and your application, memory is requested from, and later returned to, the memory management system or 'Heap'. However, in some circumstances memory can be lost. This kind of bug can be latent in your application, only showing itself after the system has been running for some time, or when it does certain operations.

The most common causes of this kind of 'memory leak' are

1. When you assign a new value to the only variable that refers to an object
2. When you create a temporary object that needs memory (within a procedure, say) then forget to remove it (explicitly with .Die, or AUTODESTRUCT) before returning from the procedure.

If you do this enough times then the system will eventually run out of memory. A memory leak, typically, only becomes apparent when your application code stops or resets on a RAM Full runtime error. Initially you may not know it's a runtime error as you might not be there to observe it, so it may appear as random resetting of the controller.

We recommend that if your program is at all complicated, that you use the Garbage Scanner as part of your code validation process. To do this, put in a call to the Garbage Scanner somewhere in your code (in the main task only). Let your system run for some time, and exercise as much of it's functionality as you can. Then signal to your code to run the Garbage Scanner.

Operational details

Debug (1) returns the number of leaked blocks found, and if you include the optional 2nd parameter with a value of 1, it will list out the details of the lost blocks. The block listing looks like this:

-->Debug(1, 1)

Garbage block list:

30 bytes at $200AD8: Buffer?

262 bytes at $200AFC: <Unknown>

46 bytes at $2020BE: Sub-class of GraphicsLCD?

Found 3 Garbage blocks

The list of garbage blocks indicates the size and address of the block, and also a good guess as to what kind of object may have used the block.

Note: the 'Unknown' block is actually a second block used by the Buffer object that didn't contain enough information for the garbage scanner to identify it.

There are legitimate heap blocks that sometimes get into the garbage list:

1. Entering a command at the --> prompt that contains a string constant (e.g. -->PRINT "a string" , CR). The command line is saved on the heap until the next reset.
2. CTRL-C breaking out of a program while it is running - any temporary objects that were held in local variables will show up as garbage as even if you wrote code to destroy them after use, this won't have been called.
3. CTRL-C breaking out of a procedure definition part way through compilation. This leaves compiler 'garbage' in the system that is harmless but will show up in a garbage scan.
4. Sometimes, in a multi-tasking system, an object may use some heap blocks temporarily and then free them after a short while. You may see these blocks in the garbage list. Only blocks that consistently appear in the garbage list need to be taken seriously.

Make sure that none of these is giving you false indications of a memory leak.

Also note that Debug(1...) will NOT respect task swap timing, so don't use it as part of a normal application unless you take this into account.

Runtime Debug Flags

The runtime debug flags enable debug options in the runtime system. The flags are arranged as a set of binary bits, within the value of Debug(3).

Bit value | Operation | Description
1 | Stack Dump | Whenever a runtime error occurs, dump the Venom stack.
2 | List Error Bytecode | Whenever a runtime error occurs, list the exact code address and bytecode at that address.
4 | C Stack Dump | Whenever a runtime error occurs, dump the C stack. Probably not useful to the Venom programmer.
8 | Mask Error 19 | Turn off Attempt to lock object held by dead task runtime error. See below.

Mask Error 19

Error 19 occurs when there is an attempt to lock an object that was held locked by a task that is now dead. You can prevent this error from being generated. We only recommend this for situations where there is no time to remove the source of the underlying error. When the error is masked and the failure occurs, the operating system silently unlocks the object and normal operation resumes. However the locking task may wait for around 255 * Number of Tasks mS before the situation is resolved.

Runtime compiler

The runtime compiler allows you to compile code from any text stream, from within a running application. This may be useful to temporarily change the behaviour of an application to suit particular circumstances.

The source text can come from any object that returns characters from a Get message. Compilation can be done from any task (though for compiling larger procedures it is recommended that the main task be used as it has a larger stack, and it's important to make sure that two tasks are not compiling at the same time). The syntax for compiling is currently:

Debug(7,obj)

obj is an object containing the text for new procedures. The Debug(7...) call has to be done once for each procedure in obj.

Notes

1. This feature is on Beta release; it is not fully tested and guaranteed but provided for use 'as-is'.
2. When an application is stored in flash, any newly compiled procedures will be held in RAM. Newly compiled procedures will temporarily overlay existing ones that have the same name. At the next startup all new procedures will be deleted and the originals will be restored from flash.
3. The maximum line length allowed in Venom is 255 characters. Lines can be broken by using the '\r' (13) character. The last line should end with '\r' to make sure no attempt is made to read past the end of the object's text.
4. Any syntax errors that occur in the code will be sent out of the main serial port - it's best to make sure there are none before compiling code in this way. Any runtime errors that occur when accessing the object will result in a runtime error report but program execution will continue.


ErrorAction

ErrorAction lrarrow Int

If ErrorAction is 0 then control returns to the command line prompt when a runtime error occurs.

If it is set to the value ‘1’ a runtime error will force Venom to reset the controller hardware.

Meaningful error action values may be expanded beyond 0 and 1 in future releases.

Note: The default startup procedure sets ErrorAction depending on the state of the program mode switch, to give the runtime error behaviour most commonly required. You can override this safe, default behaviour by setting ErrorAction in your code if you need to.

BugAlert If the default ErrorAction behaviour is changed, your application may not reset on runtime errors when it is in the field.


Free

Free  rarrow  Int

Returns the amount of free RAM in the controller (in the system heap, actually).

Using a parameter, it will also report on, and control, other areas of the controller’s memory:

Free(Int n) lrarrow Int

Free (0) | Heap memory free, total
Free (1) | Largest free block in the heap
Free (2) | Total NV RAM size. More on non-volatile RAM...
Free (3) | NV RAM free

The size of the NV RAM area may be set using something like

Free (2) := 10 * 1024

If you change this size Venom has to reset itself, as it is a major upset internally.

For the security of your application, all applications should include a line early on in the init procedure to set the NV RAM size to zero, or a constant value large enough to supply all the non-volatile RAM needed by your application:

TO init

Free (2) := 0 ; or what ever size you need.

... ;your other code

END


Output

Output lrarrow Any

Output(Int n) lrarrow Any

Redirecting text

Output(n) hold the various output streams associated with the OperatingSystem object. Changing their values allows these text streams to be redirected.

Output | Text redirected | Default output stream
Output | Text from PRINT, LIST and HELP | serial
Output(0) | Same as above | serial
Output(1) | Runtime Error reports | system

Redirecting normal text

Setting Output(0) redirects the text from PRINT, LIST and HELP:

Output(0) := new_output_device

If you redirect the output to NIL then the output is simply discarded:

Output(0) := NIL

Redirecting runtime error text

Setting Output(1) redirects the text from runtime error reports, for example to an error logging file. It is usual to use the ‘maximum size’ feature of error logging files to prevent them becoming to large.

Output(1) := err_file

When redirecting error output try to use an object that is not used by other parts of the system: if the object you are redirecting text to is locked by another task then the text output will stall waiting for the object to become unlocked. This could prevent you from seeing error reports or from using control-C to break out of a program.

To get around this problem in normal use, error text is directed by default to the system object, which simply sends it directly out of the main serial port without respecting the serial object’s locks.

It is possible to redirect any print to the system object but this is not normally recommended, as applications normally require locking to be respected.

Reading

Reading Output returns the value of the output stream object.

Later, the redirection of terminal sessions, e.g. command lines and procedures, may be possible.


Protect

Protect (Int flags)  rarrow  Int

The protect controls the ‘ROMing’ of Venom application code. It is used to create a protected application in the Flash memory. It is also used to clear out an application from flash memory.

The table details the function of the Protect message.

Protect (0) | Erases the Application area of the Flash
Protect (1) | Programs the application code into the Flash
Protect (2) | Report the application area statistics to the serial port. To get a reliable result, currently, this should be called after Protect(1) and before the next reset.
Protect (4) | Return the device code for the flash device found. Returns 0 if no compatible, write-enabled flash found.

Note: you must link pins LK3 with the shorting link on the VM-1 in order to access the Flash Memory.

It is normal to use Protect by typing it in as a command at the command line prompt, rather than as part of a program.

It is possible, and sometimes useful, to compile procedures into RAM after protecting code in flash – the system will use the newest version of each procedure. However, any newly created procedures in RAM will be removed at startup if a ROMed application is present.

LIMIT

There is 192K of application area available in the standard VM-1. Venom-SC is very efficient with application memory, so this should be enough for most large applications.

If you have an application that needs more room than this you can use the VM-1e. This has 512K of application space.

SeeAlso

ROMing, Copy


Reset

Reset
Reset(Int hard)

Resets the controller. If it is in run mode then the application will run, else you will get the startup banner.

Normally a soft reset is done: just the Venom Language and Operating System software are reset.

If the optional parameter hard is present and equal to 1 then the controller will do a hard reset (i.e. the RESET\ signal goes low for a time which will reset any external circuits connected to it). This takes around 1.6 seconds – the time it takes for the watchdog to time out.

BugAlert

Note that some of your external circuits may not be connected to the RESET\ signal, and some circuits may only be reset by the removal of the power supply.


Run

Run
Run(Int hard)

Runs the application as if in Run Mode, even if the Program Mode switch is on.

Normally a soft reset is done before running the code: just the processor IC is reset.

If the optional parameter hard is present and equal to 1 then the controller will do a hard reset (i.e. the RESET\ signal goes low for a time which will reset your external circuits). This takes around 1.6 seconds – the time it takes for the watchdog to time out.


RunMode

RunMode rarrow Int

Returns TRUE if the system is in Run Mode, i.e. if the Program Mode switch is off, or if you typed ‘Run’ at the command line.


Valid

Valid rarrow Int

When a new version of Venom-SC is released, a checksum is taken over all the bytes of code in the Language, Operating system and Objects. This checksum value is written into the code, enabling you to validate your copy of Venom-SC.

Valid will return TRUE (-1) if the checksum is good, FALSE (0) otherwise.

Of course, if your Venom-SC code is highly damaged then you won’t be able to call Valid.

PRINT Valid

-1-->


UserSwitch

UserSwitch (Int switch) rarrow Int

Reports the state of the two switches on the controller: -1 (TRUE) if the switch is on, 0 (FALSE) if it's off.

The message takes an optional parameter that specifies which switch: 1 for the program mode switch (labelled RUN - PRG), and 2 for the user switch (labelled 9K6 - 38K).

If no parameter is supplied it defaults to 2: the user switch (9K6 – 38K).


PRINT

PRINT system

Printing the system object gives the size of the symbol table and global area, and the amount of the heap memory free. Other general system information may be added from time to time.

-->PRINT system

Symbol table 55 bytes

8 Global variables

99814 Heap bytes free (biggest block 99700)

NV RAM area 0 bytes (0 unused)

-->


ProtAnalyser

Object Types

ProtAnalyser

The ProtAnalyser object is used to extract meaningful numbers, words, strings, etc from an input stream of characters.

N.B. Venom versions before 2007 07 03 had a ProtAnalyser with a different specification and more limited capabilities. This help file documents the ProtAnalyser for the above and later versions of Venom. Not all usage of the old Protocol Analyser is compatible with the new version.

Summary of messages

MAKE

Find

Get

GetLast

InputBuffer

Look

Queue

Reset

Valid


Creation

MAKE obj ProtAnalyser (source, Int queuemode)

A new ProtAnalyser object is created.

Parameters

source

An object which accepts a Get message with no parameters and returns a character.

If queuemode is 1 or 2, the object must also accept a Queue message

This object is the source of data for the Protocol analyser.

queuemode

0 - Don't send a Queue message before sending a Get message to the source object. If there is no data available, the result depends on the source object: a serial port will wait for input; a file or buffer will give a run time error.

1 - send Queue messages to source object. If the queue value is 0, Protanalyser recognises an "end of input" condition which will return a character value of -1 and terminate reading of a delimited value.

2 - send Queue message to source object. If queue value is 0, repeat Queue message until non-zero before sending Get message. This is suitable for reading from a shared buffer or file being written to by another task.

Examples

MAKE p1 ProtAnalyser (serial)

Use serial port 1, wait for input if none.

MAKE p2 ProtAnalyser (my_buff, 1)

Use a buffer, treat end of buffer as a delimiting condition.

memoryUse Creating a ProtAnalyser Object uses 50 bytes of memory.


Find

obj.Find(str pattern , Int uncased)

Returns -1 (true) if pattern found, 0 (false) if end of input reached without finding pattern

pattern | string containing pattern to find. Must be no more than 255 characters.
uncased | (default = 0) optional boolean flag to make matching case insensitive

Find reads the source until a string of characters matching the input has been found

If found, the next character to be read from the source will be the first character following the matched string.

If not found, all input from the source will have been used.

Example

Input: 123456ABC789

pa.Find("ABC") will return -1; "789" will be next characters processed.

memoryUse The Find message temporarily allocates 512 bytes of heap memory while it is processing.

LIMIT The search string can be no longer than 255 characters


Get

obj . Get  rarrow  Int

obj . Get (prototype , Int n) rarrow Int or Float

obj . Get ('s' , Str delimiters) rarrow Int

obj . Get (stringobj dest , Str delimiters) rarrow Int

obj . Get ('S', Str pattern) rarrow Int

obj . Get ('x', Str delimiters) rarrow Int

obj . Get (Array list , Str delimiters) rarrow Int

Get is used to read characters from the input stream and return a result. The first parameter to Get is a mode character or prototype. This tells Get what you want to extract from the next lot of input stream characters. See the table below for the list of modes.

Get repeatedly sends Get messages to the input stream object to read characters from it, one at a time. It uses these characters to build up the item you have asked it for. It can read tokens of these types:

· Single characters
· Numbers (Integer, hexadecimal or any other base up to 36, floating point)
· Numbers of fixed length
· Specific strings
· Strings ending with any delimiter
· One string from a list you provide
· CSV values as strings (by use of a special delimiter code)

The table below lists the various modes to use:

Kind of item to get | First Parameter | Second Parameter | Return type
Character | None or ‘c’ | None | Int = character value
Decimal integer | ‘d’ or 10 | length (optional) | Int = value of number
Hexadecimal integer | 'h' or 16 | length (optional) | Int = value of number
Number in any base | base (2 to 36) | length (optional) | Int = value of number
Floating point number | ‘f’ or 'e' or any float value e.g. 1.0 | length (optional) | Float
Skip delimiters | 'x' | delimiter list | Int = no. of chars skipped
String ending with delimiter | ‘s’ | optional delimiter list | Fixed string
Read in a specific string | ‘S’ | String | Int: TRUE (-1) or FALSE (0)
Identify string from list | Array of strings | optional delimiter list | Int: Index of name in list, or -1 if not found
String | string object | optional delimiter list | Int: count of characters stored

Numerical Types

ASCII blanks (spaces) are skipped until a valid character or '-' or '+' is encountered.

For number bases up to 10 , only numerals are valid characters.

For number bases over 10, numerals and all letters are read as valid characters

For base-n numbers, the letters A-Z or a-z (not case-sensitive) are used for digit values above 9.

For float values, '.', 'E', 'e', '-' , '+' and numerals are accepted as part of the number; any other character is a delimiter.

Floating point values may include an exponent which may be signed e.g.

876.432 -1.2 1.23E6 -4.0E-10 4.85e+5

If a length is specified in the second parameter, it sets the maximum number of valid characters to read after skipping initial spaces.

If the first non-blank character encountered is not a valid number character, a value of 0 or 0.0 is returned and the ProtAnalyser's Valid state is set to false.

The first delimiter character encountered is consumed from the input and stored where it can be retrieved by a GetLast message.

Specific string ('S' mode)

This is the only mode in which no terminating delimiter is used. Reading stops as soon as the whole string is matched or on the first character that fails to match. The first non-matching character remains available to the next Look or Get message. The ProtAnalyser's Valid state is also set according to whether the string matched or not.

Strings

If the first parameter is a string variable, its contents are replaced by the string read by the Protocol Analyser.

If the first parameter is 's', the value returned is a fixed string.

For string variables:

· The string's ReadPoint is set to 0.
· If the string's capacity is reached before a delimiter is encountered, reading stops and the remaining source characters are available for the next Get message.

For fixed strings:

· The contents of the string remain valid until the next ProtAnalyser Get message is sent. If you want to keep the string value you should copy it e.g. by PRINTing it to some other object.

For string variables or fixed strings:

· The string is terminated by the first delimiter character (see below).
· If the first character read is a delimiter, an empty string results.
· The terminating delimiter is removed from the input stream and will not be seen by the next Get or Look message but can be retrieved by GetLast

Delimiter Lists for Strings

By default, string delimiters are any control (non-printing) character, i.e. characters with an ASCII value of less than 32.

Common examples found in text are CR (13), LF (10) and TAB (9).

If a delimiter string is supplied, generally any character in the string is a delimiter, but there are some shorthand codes:

"-" between two characters indicates a range e.g. "a-zA-Z0-9"

"^" at the start of the string inverts the meaning: a delimiter is anything NOT in the list

",," is a special delimiter list string that interprets the input as CSV (comma separated values). The delimiter string must consist only of two consecutive separator characters, which are usually commas but can be anything . See below for details.

Examples

" /:," | space, slash, colon, comma are delimiters
"^-0-9" | Anything except '-' sign and numerals is a delimiter
"^0-9a-zA-Z" | Delimiter is anything non-alphanumeric
",," "||" | CSV mode and similar (see below)

CSV - Comma Separated Variables

This is a widely used file and data format, though there is no fixed official standard for it.

CSV can be exported by many spreadsheet programs and is also the data format used in NMEA data from GPS units and other navigational aids.

CSV mode is selected by specifying a delimiter list as the exact string ",," (two consecutive commas) or any other pair of the same character which is used as the separator.

The protocol analyser makes the following interpretations in CSV mode:

· Input fields are terminated by comma ',' (or other chosen separator character), a line feed '\n' or end-of-input condition.
· Unquoted leading and trailing spaces are ignored
· All unquoted control characters except linefeeds are ignored.
· Any data enclosed in double quotes may contain leading and trailing spaces, commas and non-printing characters which are copied into the data string.
· Within double quotes, a pair of consecutive double quotes inserts a double quote character into the field.
· The comma or other delimiter is consumed and is not seen by to a subsequent Look or Get message but can be retrieved by a GetLast message.

Note that CSV mode will correctly return empty strings if there are consecutive commas, or commas separated by nothing but unquoted space.

Examples of Use

Reading Numbers

Input: 123 123.4 1BCF 12345678

-->print pa.get(10), CR

123

-->print pa.get(1.0), CR

123.400

-->print ~pa.Get('h'), CR

1BCF

-->print pa.get(10, 4),CR

1234

-->print pa.get(10, 4), CR

5678

-->print pa.get, CR

-1

-->

Reading Strings and Characters

Input: "ABC:DEF:GHI"

-->print pa.get('s', ":"),CR

ABC

-->print CHR pa.GetLast, CR

:

-->print CHR pa.Look, CR

D

-->s := new string(100)

-->print pa.get(s, ":"),CR

3

-->print s,CR

DEF

-->print pa.get('S', "GHI")

-1-->

Using an Array as a list of names

Input: "Bill Brewer;Jan Stewer;Uncle Tom Cobley"

-->names := new array("", 3, "Bill Brewer", "Jan Stewer", "Uncle Tom Cobley")

-->print pa.get(names, ";"),CR

0

-->print pa.get(names, ";"),CR

1

-->print pa.get(names, ";"),CR

2

-->

Reading CSV

Input: 123, "Micro-Robotics Ltd.,135 Ditton Walk, Cambridge", "A ""Quoted"" string"

-->s := new string(100)

-->while pa.queue [ pa.get(s, ",,") print s, CR ]

123

Micro-Robotics Ltd.,135 Ditton Walk, Cambridge

A "Quoted" string

-->


GetLast

obj . Getlast rarrow Int

This message retrieves the character that terminated the last string or numeric read.

Typically this is:

',' comma or other specified separator between items in a line

10 LF in CSV mode if string was at end of line terminated with CRLF

13 CR in string (not CSV) mode if line ended with CRLF

-1 If an end-of-input condition was met


InputBuffer

obj . InputBuffer (Object ,Int Queuemode)

This resets the Protocol analyser to use a different source of data from that specified when first created..

This includes the effect of a Reset message so the next character to be read will always be from the new source.

By default the end-of-input policy remains unchanged; this can be overriden with the Queuemode parameter which, if present, has the same values as the Queuemode parameter when a new ProtAnalyser is created.


Look

obj.Look rarrow Int

Returns the next character to be processed.

If there is no more input and the object was created with queuemode value of 1 (see Creation), -1 is returned.

By definition this returns the same value that Get would, but without consuming the character from the input stream.


Queue

obj . Queue  rarrow  Int

The Queue message returns the numbers of characters known to be available in the input stream. It uses the Queue message to the input object, and adds any character buffered by the protocol analyser itself.


Reset

obj . Reset

Reset is needed when the input stream source has changed. This could occur if the input stream object has a readpoint that has been changed or if the data inside the input stream object has been overwritten.

The ProtAnalyser object caches a single character from the input stream when it reads a delimiter character that is not subsequently used. Reset clears out this cache.


Valid

obj . Valid  rarrow  Int

Returns TRUE (-1) or FALSE (0) depending on whether the last Get was successful.

In particular, a return value of 0 means:

· an empty string or numeric value was read (end of input or delimiter)
· a string didn't match (string match and array modes)


Protocol

Object Types

Protocol

The generic Protocol class covers a set of objects that control different communication protocols.

This section includes:

· XMODEM Protocol which is for file transfer over a serial line
· SMS Protocol for text messages over GSM mobile phone networks

SeeAlso

Many other Protocol object types are related to TCP/IP networking and are documented in a separate section of this help file. See TCP/IP Networking.


XMODEM

XMODEM is a very simple and widely supported file transfer protocol for use on direct serial links. It does not use TCP, IP or PPP. It is useful for transferring files between a VM-1 and a host computer such as a PC using a terminal program like Tera Term Pro or Hyperterminal, or a UNIX or Linux system using rx and tx (rz and sz with the -X option).

File sizes

XODEM transfers files in fixed size blocks of 128 bytes. If a file is not an exact multiple of 128 bytes long, the last block is padded with data to make it up to 128 bytes. The VM-1 XMODEM protocol uses zero (ASCII NUL) for this purpose when sending a file. Some implementations use Ctrl/Z (chr 26 or ASCII SUB) as padding for text files. The XMODEM protocol itself has no means of specifying exact file length.

File Names

XMODEM does not transfer any file name or data type information. The program or user must supply a file name and determine the type if the destination or source is a file.

Checksums, CRC and YMODEM

There are numerous extensions to XMODEM, notably XMODEM-CRC which uses a 16 bit CRC instead of an 8 bit checksum for better error detection, and variations with larger packet sizes and the ability to transfer file names and perform batch transfers. This implementation attempts to use the more robust CRC method, dropping back automatically to checksum mode if the other end of the link does not support CRC.

Using XMODEM with the VM-1 File System

Note that the File objects can use XMODEM directly to send or receive a VM-1 file through a serial port. In order to do this, it is NOT necessary to create an XMODEM protocol object; in fact doing so will result in a conflict causing a run time error.

SeeAlso

See File.Put, File.Get

Summary of messages

MAKE

Flush

Free

Get

Put

Queue

Reset


Creation

MAKE x Protocol("XMODEM", AsyncSerial serial)

serial is an AsyncSerial object already created. It must be set for 8 bits, no parity before using the XMODEM protocol.

The protocol is created in an initial state where it is neither transmitting nor receiving. The first Put or Free message puts it into transmit mode, and the first Get or Queue message puts it into receive mode.

Some Examples of use

1. Simple blocking send

MAKE x Protocol("XMODEM", serial)

f := fs.open("myfile.txt", "")

WHILE f.Queue > 0

[

ok := x.Put(f.Get)

IF ok = 0 break

]

IF ok

x.Flush

2. Receive in a polling loop (COPY)

MAKE x Protocol("XMODEM", serial)

f := fs.open("rxfile.dat", 8)

f.empty

FOREVER

[

some_polling_function

some_other_polling_function

IF x.Queue > 0

f.Put(x.Get)

IF x.Queue < 0

[

if x.Queue = -1

; Transfer completed

...

; file receive failed...

]

]


Flush

x.Flush rarrow Int

Returned value:
TRUE (-1) if successful
FALSE (0) if failed, e.g. because no acknowledgement was received

Flush completes an outgoing file transfer. Any current incomplete packet is padded out to 128 bytes with 0 (NUL) bytes and then sent. The process waits for the last packet to be acknowleged, sends an EOT byte to indicate the end of the transfer, and waits for that to be acknowledged, returning TRUE if the process completed without timout or cancellation.


Free

x.Free rarrow Int

Returned value:
0-128 : free space in transmit buffer
-2 : Connection cancelled by other end
-3 : Transfer failed with timeout
-4 : Connection closed

Free returns the number of free bytes that can be written to in the transmit buffer. A positive value shows the number of bytes that can be written using the Put message without blocking. Zero means that a Put message will wait until free space is available. A negative value indicates that something has gone wrong and the transfer will not complete.


Put

x.Put(Int byte_to_send) rarrow Int

Returned value: TRUE (-1) : sent OK
FALSE (0) : failed

Put waits if necessary for any current full packet to be acknowledged, then places the byte in the transmit buffer. If the buffer becomes full as a result, a packet is transmitted.

A returned value of 0 means that the transfer has either timed out or been cancelled by the other end of the connection.


Queue

x.Queue rarrow Int

Returned value:
0-128 : bytes available
-1 : End of file received
-2 : Connection cancelled by other end
-3 : Transfer failed with timeout
-4 : Connection closed

Queue returns the number of bytes available in the receive buffer. A positive value shows the number of bytes that can be read using the Get message without blocking. Zero means that a Get message will wait for an incoming packet. A negative value indicates that something has gone wrong and the transfer will not complete.


Reset

x.Reset

The Reset message returns the XMODEM object to the same initial state as when created. If a transfer was in progress it is cancelled. After a transfer has completed, a Reset is necessary to enable a new transfer to take place.


Get

x.Get rarrow Int

Returned value:
+ve : next received byte
-1 : End of file
-2 : Connection cancelled by other end
-3 : Timeout
-4 : Connection closed (possibly because of an earlier error)

Get waits until there is incoming data available, then returns the next byte of incoming data or an error code in the event of failure or normal end of file.


SMS

The SMS protocol object simplifies the sending and receiving of messages using any GSM device that complies with the ETSI standards and supports PDU mode. It has been tested with a Siemens MC-35 GPRS terminal and should work with many other GSM terminals or mobile phones with suitable serial adapters.

The MC-35 has 35 message memory locations. An incoming message fills the lowest numbered empty memory location. The SMS protocol object can read and delete any of these locations by number. Other devices may have different message memory sizes - consult the documentation when designing your code.

Summary of Messages

MAKE

Address

Empty

Format

Get

Length

Remove

Send

Time

PRINT TO

PRINT


Character Set

For most purposes, all you need to know is that the SMS object will allow you to pass ASCII messages to and from strings or text buffers.

The rest of this section describes various provisions for data other than ASCII text.

There are 3 different character encodings in common use on GSM networks:

· GSM 7 bit encoding which includes ASCII and some European characters and is the default for text.
· UCS2 (16 bits)which is a two byte representation of the Unicode code points up to $FFFF (Covers many European and Middle Eastern alphabets and symbols) and can also be used for binary data.
· GSM 8 bit encoding which is usually used for binary non-text data such as graphics, ringtones and.SIM updates

The SMS object can use all three of the above encodings in GSM messages.

For communication with the Venom program, it uses text or 8 bit and 16 bit encodings, translating to and from the GSM 7 bit code as needed:

8 bit | ISO-8859-1 with the addition of code point 0x80 for the Euro ( € ) symbol, borrowed from the WIN-1252 character map. ISO-8859-1 is the first 256 code points of Unicode and a superset of ASCII.
16 bit | UCS2. The only character translated between this and text data types is the Euro Symbol. If a 16 bit message is received into, or transmitted from, a 16 bit Venom buffer or array variable, all values are passed unchanged.

Sending in GSM7 Format

When sending messages, the message passed to the SMS object as a string or text buffer is assumed to be an ISO-8859-1 string and converted where possible to GSM 7 bit. The following codes will be translated successfully:

All ASCII printable characters except ` (back quote, code 96 or $60).

ASCII CR (13) and LF (10)

These are usually available from your keyboard.

The following ISO-8859-1 and Win-1252 characters, listed with their decimal and hex codes for convenience.

char

€

¡

£

¤

¥

§

¿

Ä

Å

Æ

Ç

Ñ

Ö

Ø

Ü

dec

128

161

163

164

165

167

191

196

197

198

199

209

214

216

220

hex

80

A1

A3

A4

A5

A7

BF

C4

C5

C6

C7

D1

D6

D8

DC

char

ß

à

ä

å

æ

è

é

ì

ñ

ò

ö

ø

ù

ü

dec

223

224

228

229

230

232

233

236

241

242

246

248

249

252

hex

DF

E0

E4

E5

E6

E8

E9

EC

F1

F2

F6

F8

F9

FC

The following characters belong to the GSM set but not to ASCII or ISO-8859-1, but their GSM codes may be inserted into an outgoing message and will display correctly on a mobile phone.

char | dec | hex
Δ | 16 | 10
Φ | 18 | 12
Γ | 19 | 13
Λ | 20 | 14
Ω | 21 | 15
Π | 22 | 16
Ψ | 23 | 17
Σ | 24 | 18
Θ | 25 | 19
Ξ | 26 | 20

Receiving in GSM7 Format

When receiving messages encoded with the GSM encoding, the characters described above will always be received as sent.

UCS2 Format

Receiving

If a received message uses the UCS2 character encoding and is restricted to the low 256 code points, the entire set of ISO-8859-1 characters as tabulated below will be will be received correctly as text. Additionally the Euro symbol ($20AC in UCS2) is translated to $80, which is not a defined code point in ISO-8859-1 but mapped to the Euro Symbol in the commonly used WIN-1252 character set so it will display correctly on many terminal configurations.

Sending

All values from 0 to $FF are sent unchanged as 16 bit values, with the exception of $80 which is translated to $20AC, the UCS2 code point for the Euro symbol.

NUL 0 0 *[1]

SOH 1 1

STX 2 2

ETX 3 3

4 4

5 5

6 6

BEL 7 7

BS 8 8

TAB 9 9

LF 10 A

11 B

FF 12 C

CR 13 D

14 E

15 F

16 10

XON 17 11

18 12

XOFF 19 13

20 14

21 15

22 16

23 17

24 18

25 19

26 1A

ESC 27 1B

28 1C

29 1D

30 1E

31 1F

32 20

! 33 21

" 34 22

# 35 23

$ 36 24

% 37 25

& 38 26

' 39 27

( 40 28

) 41 29

* 42 2A

+ 43 2B

, 44 2C

- 45 2D

. 46 2E

/ 47 2F

0 48 30

1 49 31

2 50 32

3 51 33

4 52 34

5 53 35

6 54 36

7 55 37

8 56 38

9 57 39

: 58 3A

; 59 3B

< 60 3C

= 61 3D

> 62 3E

? 63 3F

@ 64 40

A 65 41

B 66 42

C 67 43

D 68 44

E 69 45

F 70 46

G 71 47

H 72 48

I 73 49

J 74 4A

K 75 4B

L 76 4C

M 77 4D

N 78 4E

O 79 4F

P 80 50

Q 81 51

R 82 52

S 83 53

T 84 54

U 85 55

V 86 56

W 87 57

X 88 58

Y 89 59

Z 90 5A

[ 91 5B

\ 92 5C

] 93 5D

^ 94 5E

_ 95 5F

` 96 60

a 97 61

b 98 62

c 99 63

d 100 64

e 101 65

f 102 66

g 103 67

h 104 68

i 105 69

j 106 6A

k 107 6B

l 108 6C

m 109 6D

n 110 6E

o 111 6F

p 112 70

q 113 71

r 114 72

s 115 73

t 116 74

u 117 75

v 118 76

w 119 77

x 120 78

y 121 79

z 122 7A

{ 123 7B

| 124 7C

} 125 7D

~ 126 7E

127 7F *[1]

€ 128 80

129 81 *[1]

130 82

131 83

132 84

133 85

134 86

135 87

136 88

137 89

138 8A

139 8B

140 8C

141 8D

142 8E

143 8F

144 90

145 91

146 92

147 93

148 94

149 95

150 96

151 97

152 98

153 99

154 9A

155 9B

156 9C

157 9D

158 9E

159 9F

160 A0

¡ 161 A1

¢ 162 A2

£ 163 A3

¤ 164 A4

¥ 165 A5

¦ 166 A6

§ 167 A7

¨ 168 A8

© 169 A9

ª 170 AA

« 171 AB

¬ 172 AC

173 AD

® 174 AE

¯ 175 AF

° 176 B0

± 177 B1

² 178 B2

³ 179 B3

´ 180 B4

µ 181 B5

¶ 182 B6

· 183 B7

¸ 184 B8

¹ 185 B9

º 186 BA

» 187 BB

¼ 188 BC

½ 189 BD

¾ 190 BE

¿ 191 BF

À 192 C0

Á 193 C1

Â 194 C2

Ã 195 C3

Ä 196 C4

Å 197 C5

Æ 198 C6

Ç 199 C7

È 200 C8

É 201 C9

Ê 202 CA

Ë 203 CB

Ì 204 CC

Í 205 CD

Î 206 CE

Ï 207 CF

Ð 208 D0

Ñ 209 D1

Ò 210 D2

Ó 211 D3

Ô 212 D4

Õ 213 D5

Ö 214 D6

× 215 D7

Ø 216 D8

Ù 217 D9

Ú 218 DA

Û 219 DB

Ü 220 DC

Ý 221 DD

Þ 222 DE

ß 223 DF

à 224 E0

á 225 E1

â 226 E2

ã 227 E3

ä 228 E4

å 229 E5

æ 230 E6

ç 231 E7

è 232 E8

é 233 E9

ê 234 EA

ë 235 EB

ì 236 EC

í 237 ED

î 238 EE

ï 239 EF

ð 240 F0

ñ 241 F1

ò 242 F2

ó 243 F3

ô 244 F4

õ 245 F5

ö 246 F6

÷ 247 F7

ø 248 F8

ù 249 F9

ú 250 FA

û 251 FB

ü 252 FC

ý 253 FD

þ 254 FE

ÿ 255 FF

*[1] Code values $00-1F, $7F-9F are not defined in ISO-8859-1 but will be received and may result in characters displayed according to the font used in your terminal, or with the usual ASCII control character meanings.

Binary Data

The SMS object can also use 8 bit and 16 bit Buffer and Array objects for sending and receiving binary data using the GSM 8 bit and 16 bit (UCS2) data coding schemes. When this is done no code translation at all is performed.


Creation

MAKE sms Protocol("SMS", Int serialport)

"SMS" | Shows what type of protocol object to create
serialport | 1 or 2 to select serial port to which GSM device is connected

Returned value: a protocol object variable


Debug

sms.Debug

Displays internal information about the SMS object

sms.Debug(Int n)

Turns debugging mode on (n=1) or off (n=0, default)

In debugging mode, all output from the GSM device is echoed to serial port 1.

This will only work is the GSM device is connected to serial port 2.


Address

sms.Address rarrow String

Returns the senders address (i.e. phone number) of the last message read. This is a fixed string whose contents remain valid until a new message has been read or any message is deleted.


Empty

sms.Empty

Clears the internal buffer holding the result of PRINT TO sms statements.

This is not usually needed, as sending a message clears the buffer anyway.


Format

sms.Format larrow Int

A value of 16 causes any text messages (from string or text buffer) to be encoded as 16 bit UNICODE (UCS2).

A value of 7 causes any text messages (from string or text buffer) to be encoded using GSM 7 bit encoding.

Default is 7 bit encoding.

Messages sent from 8 bit and 16 bit integer buffers or arrays are unaffected by the Format setting.


Get

sms.Get(Int n[, Buffer/Array buf) rarrow Int

n | Message store number, starting from 1.
buf | Buffer to which the message contents will be appended or array to which the message contents will be written

Returned value indicates the type of message found in the message store.

-1 | Error (invalid message number)
0 | No message
7 | Received GSM 7 bit encoded text
8 | Received 8 bit binary message
16 | Received 16 bit text or binary message

Reads a message from the numbered store location in the GSM device

Stores the date/time, originator and text of the message in the SMS object. (see Time, Address and PRINT)

Optional Buffer or Array Parameter

If a buffer or Array parameter is specified, its data type can be text or any integer type.

32 bit arrays are not permitted

The array must be big enough to hold the message.

In certain cases with Buffers, conversion for the Euro symbol is performed between 8 bit (€ = $80) and UCS2 (€ = $20AC), as described in the following table.

Buffers

Message type | Buffer type | Conversion
7 | 16 or 32 | Euro symbol: $80 converted to $20AC
16 | text | $20AC converted to $80
16 | 8 | integer values over $7f are truncated to 8 bits
all other combinations |  | simple copy

Arrays

For arrays, the data is copied unmodified, except that a 16 bit message read to an 8 bit array will be truncated.

SeeAlso See also: Character Set

TimingIcon The Get message will wait while confirmation is received that the message has been sent successfully. If no confirmation is received, then Get will timeout after 20 Seconds.


Length

sms.Length rarrow Int

Returns the length of the GSM 7 bit encoded message stored in the SMS object as a result of PRINT TO sms statements.

If the sms object is set for 7 bit text sending (the default) this length takes into account a handful of characters that have to be encoded as a two-character escape sequence.

For a message to be sent successfully using 7 bit GSM encoding, this value must not exceed 160.

For a message to be sent using 16 bit encoding, the maximum is 70.

The following characters result in an escape sequence and require two characters in 7 bit mode:

^ { } \ [ ~ ] €

sms.Length(Str) rarrow Int

Performs the same length calculation on a fixed string or text buffer.

sms.Length(Int msgno) rarrow Int

msgno

Message number

This form of the Length message reads an SMS message from the GSM device's memory just like Get, but the returned value is the length of the message.


Remove

sms.Remove(Int msgno)

msgno

Message store location to be deleted

· Deletes numbered message from GSM device's message memory
· Clears the current message


Send

sms.Send(dest[, message]) rarrow Int

dest | String or text buffer holding the recipients phone number
message | String or buffer holding the text of the message

Returned value: true (-1) if successful, false (0) if sending failed.

Effect of 2nd Parameter on Message Data Encoding

Param | Max length | Encoding
none | 160 | The message is the result of any preceding PRINT TO sms statements, encoded as for string or text buffer.
string text buffer | 160 (7 bit) 70 (16 bit)* | The message is sent by default using GSM 7 bit coding, unless the Format message has been used to change this to 16 bit UCS2 coding.
8 bit buffer or array | 140 | Contents are sent using GSM 8 bit encoding. This is not usually used for text messages in mobile phones, but for binary messages such as ringtones, SIM updates and graphics.
16 bit buffer or array | 70 | Contents are sent in a message that specifies UCS2 encoding in the header. Mobile phones display this using the UCS2 mapping, or it can be used for binary data.

*16 bit mode is enabled by the Format message to the SMS object

Sending a message has no effect on the current stored incoming message.

SeeAlso See Length, PRINT TO, Format


Time

sms.Time rarrow Int

Returns the timestamp of the current (most recently read) message in Venom time i.e. seconds since the beginning of 1990.


Accepting Print

PRINT TO sms, printlist

The print output is appended to an internal buffer for subsequent sending.

If the limit of 160 characters is exceeded the extra characters are discarded without warning.

SeeAlso See also: Empty, Length


PRINT

PRINT sms:select [: format]

Select Value | What's Printed
none | Print originator, date/time and message text on three separate lines
0 | Print originator (i.e. sender's phone number)
1 | Print a string containing the date and time of the message. If a second colon operator is present, it controls the format of the date and time info in exactly the same way as the first colon operator when printing a DateTime object.
2 | Print the message text

If the message is empty, the string: "[SMS: empty]" is always printed.


Code Example

Sending Data Readings by Text

In this example, the VM-1 monitors two voltage readings via 10 bit analogue inputs.

On receipt of a text message starting with the word "READINGS", it sends them in a text message by reply.

If V1 exceeds a critical level, a message is sent to an alarm number immediately, and repeatedly every 5 minutes .

#DEFINE v1_alarm_level 614 ; alarm level

#DEFINE alarm_number "0797626xxxx" ; mobile # for alarm message

TO init

MAKE v1 Analogue(40) ; the voltage measurement inputs

MAKE v2 Analogue(41)

MAKE serial2 AsynchronousSerial(38400, 2, 0) ; set up serial port

MAKE sms Protocol("SMS", 2) ; SMS object uses serial 2

MAKE buf Buffer("") ; for received message

MAKE alarmtimer timer(300000) ; 5 minute timer for alarm repeats

END

TO main

EVERY 5000 ; poll for request every 5 seconds

[

print "v1 ", v1.value * 0.00488:1:2, " v2 ", v2.value * 0.00488:1:2, CR

REPEAT 4 ; poll 1st 4 message memories

if SMS.Get(index, buf) > 0

[

PRINT "Received:",CR, sms, CR

IF buf.Find("READINGS") = 0

[

PRINT TO sms, "V1 = ", v1.Value * 0.00488:1:2, CR,

"V2 = ", v2.Value * 0.00488:1:2

sms.Send(sms.Address) ; Reply to sender of incoming message

]

sms.Remove(index) ; clear message memory

]

; check alarm level

if v1.Value > v1_alarm_level AND alarmtimer.done

[

PRINT "v1 > alarm",CR

alarmtimer.go ; restarts the timer

PRINT TO sms, "ALARM: V1 = ", v1.Value * 0.00488:1:2

sms.send(alarm_number)

]

]

END


PulseCounter

Object Types

PulseCounter

PulseCounter is used to count pulses on one of the ‘clock input’ channels. It actually counts 'edges' - that is when the input signal changes from one state to the other. The pulse counter object can be set up to count positive-going, negative-going, or both edges. It keeps track of the count as a 32-bit number.

Summary of messages

MAKE

Count

Reset

PRINT


Creation

MAKE obj PulseCounter (Int chan, Int edge, Int chanx)

A new PulseCounter object is created with a zero pulse count. chan is one of the clock input channels, and edge is one of:

1: Count on the Positive Edge (0V -> 5V)

2: Count on the Negative Edge (5V -> 0V)

3: Count on Both Edges

The optional parameter chanx is explained below.

Relating Clock and Pulse I/O

Each PulseCounter object uses a counter/timer register from the processor’s internal TPU module to hold the count. This means that no pulse I/O object (e.g. PulseWidthOut, PulseWidthIn, FrequencyIn, AsynchronousSerial port 3) can use that register.

The optional parameter chanx allows you to choose the channel on which you wish to sacrifice pulse I/O. If you don’t include chanx, a default channel will be used:

PulseCounter input channel | Default channel used up
1 | 18
2 | 6
16 | 3
17 | 4

Any channel that is not usable for pulse I/O is still available for use as Digital.

For a full explanation of how clock and pulse I/O are related, see the diagram and text in the VM-1 Datasheet: Relating Clock and Pulse I/O.

Examples

MAKE p_in1 PulseCounter (1,1) ;channel 1. Rising edge.

MAKE p_in2 PulseCounter (1,2,19) ;chan 1 Falling edge.

In the first example the pulse count input is on channel 1, and the associated default channel, 18, becomes unavailable. In the second example we chose to make channel 19 unavailable instead.

Hardware | For channel details see the VM-1 Datasheet.
LIMIT | The maximum number of PulseCounter objects is 4, limited by the number of clock input channels available on the VM-1.
TimingIcon | The input clock pulse width must be greater than 1.5 'states' for single-edge detection or 2.5 'states' for 2-edge detection. A state is one period of the processor clock: - 1/16th of a microsecond, normally.
SeeAlso | See also FrequencyIn, Digital, PulseWidthOut, and Shaft.


Count

obj . Count  rarrow  Int

Returns the current pulse count.

-->PRINT p . Count
3245-->

LIMIT | The PulseCounter object can keep track of over 2 billion pulses - i.e. it uses a 32-bit count register. When the count exceeds 231-1, then the value wraps round to -231.
SeeAlso | See also Reset.


Reset

obj . Reset

Resets the pulse count to zero. For example:

-->PRINT p . Count,CR
3245
-->p . Reset
-->PRINT p . Count,CR
0
-->

SeeAlso

See also Count


Printing

PRINT obj

Prints the object’s type and current pulse count in square brackets:

-->PRINT p
[PulseCounter: 10]


PulseWidthIn

Object Types

PulseWidthIn

PulseWidthIn is used to measure the width or period of incoming pulses on one of VM-1 channels 3, 4, 5, 6, 18 or 19. Pulses or periods from 50µs to over 35 minutes can be measured with a resolution of 1µs.

Summary of messages

MAKE

Done

Go

Period

PRINT


Creation

MAKE obj PulseWidthin (Int chan, Int mode )

A new PulseWidthIn object is created.

chan must be one of: 3, 4, 5, 6, 18 or 19

mode has the following meanings:

0 | Measure low pulse width: falling to rising edge
1 | Measure high pulse width: rising to falling edge
2 | Measure period between falling edges
3 | Measure period between rising edges

Examples

MAKE pw1 PulseWidthIn (3, 1) ;VM-1 channel 3 High pulse width

MAKE pw2 PulseWidthIn (18, 3) ;chn 18 Period between falling edges

Hardware | For channel details see the VM-1 Datasheet.
LIMIT | The maximum number of PulseCounter objects is 6, limited by the number of pulse I/O channels available on the VM-1.
TimingIcon | If the input clock pulse width is less than approximately 50µs then the measurement may become inaccurate. If you are using other pulse width I/O objects concurrently then the minimum pulse width measurable will increase. Unfortunately it is difficult to be completely precise about the minimum measurable in any particular circumstances.
SeeAlso | See also FrequencyIn, Digital, PulseWidthOut, Shaft.


Done

obj . Done rarrow Int

Returns -1 (TRUE) when the measurement cycle is complete, i.e. both the leading and trailing edge have been seen. Returns 0 (FALSE) if this condition has not yet been met.


Go

obj . Go

Starts a measurement cycle. The time measurement will start at the next leading edge as specified by mode when the object was created, and the measurement is complete as soon as the correct type of trailing edge is encountered.


Period

obj . Period rarrow Int

Returns the measured period in microseconds. Periods below ~50μs are not measured correctly because of interrupt response limitations, and the maximum useful value that can be returned is 2,147,483,647μS (max value for a signed 32 bit integer, around 35 minutes).

The Period message can be used in two ways:

By itself, the Period message will initiate a measurement cycle and wait for the result before returning. The task is suspended while waiting.

In conjunction with the Go and Done messages, the task can loop and execute other code while waiting. When the Done message returns true, the next Period message will return immediately with the value just measured. If a Period message is sent any time after a Go message and before the measurement cycle is complete, the task will wait.

; example of 1st usage

width := pw.Period ; task is suspended while waiting

; example of 2nd usage

pw.Go

while NOT pw.Done

[ ; other code in loop executed while waiting

]

width := pw.Period


PRINT

obj . Print

Prints, inside square brackets, the text “PulseWidthIn : “ followed by the last measured value, followed by a new line.

No measurement cycle is initiated. If no measurement has been made since the object was created the value printed is -1.

The Print message is not recommended for general programming with PulseWidthIn objects.

Example:

-->print pw

[PulseWidthIn: 456]

-->


PulseWidthOut

Object Types

PulseWidthOut

PulseWidthOut generates pulse trains with variable Mark/Space ratio and frequency.

A PulseWidthOut object may be set to generate a continuous signal, or a pulse train containing a specific number of pulses.

Speed profiles for stepper motors may be generated using the Queue message.

Care should be taken to ensure that the creation of a PulseWidthOut object does not use the same internal counter register as a PulseCounter or Shaft object. See PulseCounter or Shaft for details.

Normally the PulseWidthOut Width and Period values are given in units of 1µS however this may be altered using the Format message.

Timing accuracy is governed by the VM-1 crystal oscillator. See the VM-1 datasheet.

Summary of messages

MAKE

Asserted

Count

Format

NotAsserted

Off

On, Go

Period

Queue

Width

PRINT


Creation

MAKE obj PulseWidthOut

(Int channel, Int period,

Int width, Int polarity,

Int count)

A new PulseWidthOut Object is created. Note that the pulse train will not actually start until the Go or On message is sent.

The table below describes each of the parameters.

Parameter | Range of values | Purpose
channel | 3,4,5,6,18 or 19 | The VM-1 Channel to use
period | 2 – 65536 | The period of the output signal
width | 0 – (period-1) | The width of the output signal
polarity | 0 or 1 | 0: active low; 1: active high.
count | 0 – 2,147,483,647 | Optional. The number of pulses to generate; 0 means continuous output.

In general channels 5 and 19 are the best to use for PulseWidthOut, especially if high frequency pulses are required.

Example

;Create a 1:10 mark:space PWM waveform
MAKE pwm pulsewidthout(6,10000,1000,0)

pwm . On ;turn it on

Hardware

The VM-1 channels may be used by other objects. See Digital, PulseCounter, Shaft and I/O channel table in the VM-1 Datasheet.

LIMIT

The maximum number of PulseWidthOut objects is 6 (one per available channel).

The maximum value of period is 65536. The minimum value of period is 2, but also see warning below.

Warning: When generating a defined-length pulse train using count, PulseWidthOut uses interrupts to count the pulses. If the period becomes too small the VM-1 may start to behave erratically. The exact threshold for this depends on interrupt loading. Keep the period above 100uS per PulseWidthOut object when using count until this has been characterised. Similarly, when using more than one PulseWidthOut with count concurrently, the minimum pulse width should be increased. Unfortunately it is difficult to be completely precise about the minimum pulse width attainable in any particular circumstances.

A further restriction applies to all channels other than 5 & 19: When generating high frequency continuous pulse trains, setting the period and width values may result in an output that misses a state-change. Again, keeping the period above 100uS until this has been fully characterised will be well into the safe region.

SeeAlso

See also PulseWidthIn, PulseCounter, Shaft.


Asserted

obj . Asserted lrarrow Int

Setting Asserted TRUE starts a pulse train (like On), and setting it FALSE stops the train (like Off). Asserted returns TRUE if the pulse train is currently active, FALSE otherwise.

SeeAlso

See also NotAsserted


Count

obj . Count   lrarrow  Int

Count allows the pulse train length to be read or set.

Setting the Count takes effect the next time the train is triggered (using Go or On). It has no effect on a currently active pulse train.

Reading the Count returns the number last set during creation or using Count. Use Queue if you want to find the number of pulses remaining to be sent.

SeeAlso

See also Creation


Format

obj . Format := Int

Setting format allows the timing, or even the source, of the clock pulses to be changed in the PulseWidthOut object.

The value passed to the format message consists of a bit field. The lower three bits (bits 0 – 2) determine the source of the clock pulses – one of several divisions of the processor clock crystal or even a VM-1 channel. The table shows the clock rate or VM-1 channel selected depending on the channel and bits 0 – 2. The clock rate is shown as Ø/N where Ø is the VM-1 clock crystal frequency (normally 16Mhz) and N is a division ratio. The column in bold is the default setting.

VM-1 channel/ Bits 0-2 | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111
3 | Ø | Ø/4 | Ø/16 | Ø/64 | Chan 2 | Chan17 | Ø/256 | Chan16
4 | Ø | Ø/4 | Ø/16 | Ø/64 | Chan 2 | Chan17 | Ø/1024 | -
5 | Ø | Ø/4 | Ø/16 | Ø/64 | Chan 2 | Ø/1024 | Ø/256 | Ø/4096
6 | Ø | Ø/4 | Ø/16 | Ø/64 | Chan 2 | Chan 1 | Ø/256 | -
18 | Ø | Ø/4 | Ø/16 | Ø/64 | Chan 2 | Chan 1 | Chan17 | Ø/1024
19 | Ø | Ø/4 | Ø/16 | Ø/64 | Chan 2 | Chan 1 | Chan17 | Chan16

The next two bits (bits 3 & 4) determine which edges to count on.

Counting on both edges effectively doubles the frequency of the clock, allowing Ø/2, Ø/8, Ø/32, etc. You can’t count on both edges when Ø is selected as the clock source.

Bits 4,3 | Count on edge
00 | Rising
01 | Falling
10 | Both
11 | Both

Examples:

p.Format := %00011 ; use units of 4uS.

p.Format := %01011 ; VM-1 channel 2 falling edge is the clock.


NotAsserted

obj . NotAsserted lrarrow Int

Setting NotAsserted TRUE stops a pulse train (like Off), and setting it FALSE starts the train (like On). NotAsserted returns FALSE if the pulse train is currently active, TRUE otherwise.

SeeAlso

See also Asserted


On, Go

obj . Go
obj . On

On (or Go) starts a pulse train.

On is necessary to start the train after the PulseWidthOut has been created.

Every time the message On is given, the number of pulses to be sent out is reset to the value of Count. If this was zero, then the pulse train keeps going indefinitely.

Go has exactly the same effect as On.

SeeAlso

See also Off and Count


Off

obj . Off

Off turns off the pulse output at the next edge.

SeeAlso

See also On/Go


Period

obj . Period lrarrow Int

An active variable that allows the overall period of the waveform to be read or set. The units are determined by the clock source, but the default is µS.

The diagram below illustrates the relationship between period and width for an active-high waveform.

The minimum Period value is 2, but see the warning notice in Creation.

If Period is set to less than the current Width then the output will go to the 100% duty state. As soon as Period is greater than Width again, pulses will reappear.

If you have Count set when Period is less than Width, counting of pulses will continue even if no real pulses are generated.

If you call both Width and Period, it is possible under some circumstances for one of these messages to have to wait for a maximum time given by Period. However if you stick to a constant Period and vary Width, or vice versa, this will never occur.

SeeAlso

See also Creation, Count.


Queue

obj . Queue rarrow Int

If the pulse train is active and count has been set, queue returns the number of pulses still to be generated. If the pulse train is inactive or the pulse train is continuous, or no count has been set it returns 0.

SeeAlso

See also Count


Width

obj . Width lrarrow Int

Allows the mark period of the waveform to be read or set. The units are determined by the clock source, but the default is µS.

The diagram below illustrates the relationship between period and width for an active-high waveform.

If Width is set to zero or less, then the output will go to the 0% duty state, i.e. pulses will not be generated.

If Width is set to more than the current Period then the output will go to the 100% duty state so the output is turned on continuously, no pulses will be generated. As soon as Width is less than Period again, pulses will reappear.

If you have Count set when Width is zero, or Width is greater than Period, the count will continue even if you can’t see pulses.

If you change both Width and Period, it is possible under some circumstances for one of these messages to have to wait for a maximum time given by Period (while swapping tasks). However if you stick to a constant Period and vary Width, or vice versa, this will never occur.

SeeAlso

See also Creation, Period


Printing

PRINT obj

Prints the object type and current width and period within square brackets.

-->PRINT pwm

[PulseWidthOut: 1000/10000]

SeeAlso

See also Period, Width


Die

Die turns off the pulse train immediately and removes the object.


RandomNumberGen

Object Types

RandomNumberGen

The Random number generator object is an interface to two pseudo random number generators:

1. A 16 bit generator based on a 16 bit pseudo random binary sequence, similar to that produced by the rand() function in a typical C library. It produces a sequence containing each number from 1 to +65535 exactly once. Its randomness does not pass stringent statistical correlation tests but it is reasonably quick (114 µs)
2. A very high quality 32 bit generator that has an extremely long sequence combined from 3 32 bit Tausworth generators. The full range of positive and negative 32 bit integers is generated. The same generator is also used to produce random floating point numbers in the range -1.0 <= n < +1.0. The 32 bit generator is a little slower than the 16 bit (234 µs).

All generator types can be seeded with integer values or a string or text buffer value.

Summary of messages


Creation

Make r RandomNumberGen(Int prototype[, various seeds])

Prototype | 1.0 or any floating point value: Make a floating point generator 16 : make a 16 bit generator 32 : make a 32 bit generator
Seeds | A single integer, string or text buffer contents define a starting pattern for all generator types. Up to 3 integer values can be used for the 32 bit generator giving a very wide range of possible starting points in the sequence.


Get

r.Get rarrow Int or Float

r.Get(Int min, Int Max) rarrow Int

Returns a value of the type defined when the generator was created.

16 bit values have a flat distribution in the range 1 to 65535
32 bit values have a flat distribution in the range -2147483648 to +2147483647.
Floating point values are any of 4194304 equally spaced values between -1.0 and +1.0

If min and max values are specified, integer generators will return numbers in that range, including the min and max values. For the 16 bit generator, any range with not more than 65535 between min and max can be specified, including negative numbers.

Floating point numbers in a range can be produced by scaling the output of a float generator, e.g. to return values between 4.5 and 9.5 use a formula like:

4.5 + (ABS randf.Get) * 5.0

or

7.0 + randf.Get * 2.5


PRINT

The PRINT operator on a random number generator produces output like this:

[rand:-0.652303] (float)
[rand:6189] (16 bit)
[rand:-1553008633] (32 bit)


Reset

r.Reset(Int or Str seed)
r32.Reset(Int seed1[, Int seed2[, Int seed3]])

Any random number generator can be re-seeded with an integer, string or text buffer. The same seed value will always restart the pseudorandom sequence at the same point.

A 32 bit generator can optionally make use of up to 3 seed integer values.


Value

Value is a synonym for Get for all types of random number generators.


RealTimeClock

Object Types

RealTimeClock

The RealTimeClock object uses a PCF8583 clock/calendar IC to keep track of the number of seconds that have elapsed since 00:00:00 on the 1st of January 1990. This number may be converted to a meaningful date by printing the clock or by using a DateTime object.

RealTimeClock can keep track of the date and time until the year 2089.

The clock has an alarm output that may be used to power up the system at a pre-determined date and time up to a year ahead.

Register and RAM Usage

As well as a clock/calendar function, the PCF8583 device also contains 256 bytes of non-volatile SRAM. When it is operating as a clock/calendar the first 16 bytes are used for the clock calendar registers. Additionally, another 6 bytes are used by the RealTimeClock object. Thus the first usable byte of the SRAM is at address 22 ($16).

Summary of messages

MAKE

Off

On

SleepUntil

Time

Valid

PRINT TO

PRINT


Creation

MAKE clock RealTimeClock

The clock object is created without affecting the time held internally.

If the real-time clock IC has not had it’s time set previously then this will need doing before it can be used properly. When the controller is powered down the real-time clock IC is kept powered by the backup Lithium battery.

When a clock IC is first plugged in, the alarm output will pulse at 1Hz until it is accessed by one of SleepUntil, On or Off.

Hardware | You may need to plug a PCF8583P into your VM-1 system - see the VM-1 Datasheet.
LIMIT | The clock can hold times from 1990 to 2089


Off

obj . Off

Turns the alarm output off.

SeeAlso

See also SleepUntil


On

obj . On

Turns the alarm output on.

SeeAlso

See also SleepUntil


SleepUntil

obj . SleepUntil (Int sec)

The real time clock IC has an alarm output that may be set to ‘go off’ at any time up to a year ahead. The message SleepUntil controls the alarm setting. When SleepUntil is called, the alarm output is turned off immediately and will turn on again at the specified time. If you connect the alarm output to a suitable circuit then your application electronics will be able to ‘sleep’ consuming zero power until a specified time in the future.

clock . SleepUntil(clock.Time + 60) ;sleep for a minute

LIMIT | The time to sleep until should be two or more seconds, and less than a year, into the future.
SeeAlso | See also On, Off


Time

obj . Time lrarrow Int

Time is an active variable that holds the seconds count of the clock. This may be converted to a date using a DateTime object, or by printing the clock. If the clock chip is not present, or the time has not been set since the clock chip was plugged in, then the time returned will be zero.

In order to set the clock's time, use the following procedures.

Type the following code to see what state the clock is in:

-->PRINT clock , CR

It will give one of the following:

--------- --:--:-- ;no clock chip found, or
==-===-== ==:==:== ;the time has not been set, or
08-Jan-90 10:45:32 ;the time has been set, but may be wrong.

In the first case you need to fit a PCF8583P, see the VM-1 Datasheet.

In the second and third cases, set the time by printing a date and time to the clock:

PRINT TO clock , “27-2-02 13:25:00”

TimingIcon | Generally the clock will keep time to a few seconds a day. If the controller is used near the temperature extremes then this accuracy will be affected.
SeeAlso | See also DateTime


Valid

obj . Valid rarrow Int

Valid returns TRUE if the clock IC is fitted and the clock has been set.


Accepting Print

The clock’s time and date can be set using PRINT TO. E.g.:

PRINT TO clock,"06-06-2001 10:56:00"

Printing to the clock must obey these rules:

· The date comes first
· You must use ‘:’ to delimit the time
· You must provide all six elements of the date, using numbers

The clock can accept just about any separator for the date and can work with the ‘short’ year, e.g. “27-2-02”.


Printing

PRINT obj : f

Printing the RealTimeClock object shows the current time and date in a variety of formats. The following examples all represent 1:50pm on 12 January 2004.

f | Description | Layout | Example
:0 | Day, Month, Year, H(24), M, S | DD-mmm-YY HH:MM:SS | 12-Jan-04 13:50:00
:1 | Day, Month, Year, H(24), M | DD mmm 'YY HH:MM | 12-Jan-04 13:50
:2 | Day, Month, Year | DD-mmm-YY | 12-Jan-04
:3 | Hours(24), Mins, Secs | HH:MM:SS | 13:50:00
:4 | Hours(12), Mins, Secs, am/pm | HH:MM:SSxx | 01:50:00pm
:5 | Day, Month, Year | DD-MM-YY | 12-01-04
:6 | Month, Day, Year | MM-DD-YY | 01-12-04
:7 | Day of the week | ddd | Mon
:8 | Month | mmm | Jan

If the clock chip is not found, or the time has not been set since the clock was plugged in, then the clock will print in the following form, where digits and letters have been replaced by '-'s and '='s characters.

--------- --:--:-- ;no clock chip found, or
==-===-== ==:==:== ;the time has not been set

LIMIT

Format 0 is used if no format is supplied or if the format is greater than 8.


SafeData

Object Types

SafeData

SafeData allows easy storage and verification of non-volatile data/parameters in EEPROM (and other) devices.

Use the Element message to read and write all sizes of integer data, and floating-point data.

Use the Put and Get messages to read and write blocks of data to and from Arrays.

Use the Checksum message to validate the data.

Summary of messages

MAKE

Checksum

Element

Get

Put

PRINT


Creation

MAKE s SafeData (Int type , Int bus , Int address)

type gives the type of non-volatile storage device: see the table below.

bus gives the I2C Bus the device is attached to: either 1 or 2.

address gives the I2C Address of the device: usually 160, 162, ... and upwards.

There are two device types currently supported:

Type | Description
0 | EEPROMs, and other devices, compatible with the M24C02. The significant common feature is they take one byte of address within the device (maximum storage 256 bytes).
1 | EEPROMs compatible with the M24C32, M24C64, etc. The significant common feature is they take two bytes of address within the device.

The bus and address parameters specify which I2C bus the EEPROM is on (1 or 2), and which address it is located at on the bus (160, 162, ...). For example:

MAKE s SafeData (0 , 1 , 162)

Hardware

A suitable EEPROM is fitted to Micro-Robotics Application Board 5811. The example above will create a SafeData object in the fitted memory.

For the 5802 Application board, use
MAKE s SafeData (0 , 2 , 162)

Note: you can find out what devices are connected at which addresses on an I2C Bus by printing the I2CBus object.

memoryUse

SafeData is a Zero-Memory object


Checksum

obj . Checksum(Int start , Int end) rarrow Int

Checksum returns the sum of all the bytes in the device from start to end, inclusive, as a 16-bit unsigned integer. It can be useful for validating the contents of the device.

s.(0,8) := a

s.(1,16) := b

s.(3,16) := c

s.(5,32) := d

s.(9,1.0) := e

s.(13,16) := s.Checksum(0,12) + MY_CONSTANT ;save a checksum of the data.

…

if s.(13,16) <> s.Checksum(0,12) + MY_CONSTANT

[

data_not_valid

]

A constant value, called here MY_CONSTANT, is used to get round the condition that if the data is all zeros, then the checksum will match even if all zeros is not correct data. Use any integer value, such as ‘42’.


Element

obj . Element(Int addr , Int/Float proto) lrarrow Int/Float
obj . (Int addr , Int/Float proto) lrarrow Int/Float

The element message allows read and write access to the device. The parameters to Element are the address within the device, and an optional prototype parameter that tells the object what type of data is being stored. This prototype is the same as that used in Arrays and Buffers, but only the following are allowed:

Prototype | Data storage
None | 8-bit unsigned integers
8 | 8-bit unsigned integers
16 | 16-bit signed integers
32 | 32-bit signed integers
1.0 or any float | Floating point numbers

The .Element message has a standard shortcut in Venom-SC which is .()

For example:

s.(0,8) := 24

Writes 24 to one byte at location zero.

s.(2,1.0) := 231.3438

Writes a floating-point number to four bytes at location two

You should be careful to take account of the size of the data you are writing when you choose the start address, so you don’t get overlaps or holes in the device’s memory space.

s.(0,8) := 24

s.(1,16) := 1232

s.(3,16) := 23232

s.(5,32) := 323323222

s.(9,1.0) := 1.23232

Reading data out of the device is very similar to writing it.

Val := s.(0,8)

Reads a byte out of the device from location zero.

s.(2,1.0) := 231.3438

Reads a floating-point number to four bytes at location two.

There is currently no validation of data written to the EEPROM so you may want to check the correct data has been written.


Get

obj . Get(Int start , Int block_address, Int nbytes )

Get reads a block of data from the device, and writes it to a place in the controller’s RAM given by an address. This would normally be used to write data from the device to an Array object.

The block_address parameter is usually found by taking the Address of an Array. Take care when setting the value of block_address as getting it wrong will cause the system to misbehave in an unpredictable manner.

s.Get(0,arr.Address,arr.Length) ; read the array from the device.


Put

obj . Put(Int start , Int block address, Int nbytes )

Put writes a block of data to the device, from a place in the controller’s RAM given by an address. This would normally be used to write data to the device from an Array object.

s.Put(0,arr.Pointer,arr.Length) ; write the array to the device.

There is currently no validation of data written to the EEPROM so you may want to check the correct data has been written.


PRINT

Printing the SafeData object prints some or all of the contents as a list of bytes in hex format, each line up to 16 bytes long.

If you supply colon format parameters, then you can specify the amount of data printed, and the start position of the data to print. One colon parameter specifies the amount of data to print from the start; two colon parameters specify the start point and then the amount of data to print.

If no colon parameters are present, 256 bytes from the start of the device are printed. For example:

PRINT s:16:32

SafeData [A20100]

$01 $02 $03 $04 $04 $04 $04 $04 $04 $04 $00 $00 $42 $C8 $76 $C9

$41 $41 $41 $41 $41 $41 $41 $41 $41 $41 $41 $41 $41 $41 $41 $41

-->

The numbers in [] indicate the I2C address, I2C Bus number (less 1), and Device type of the storage device, set in MAKE.

SeeAlso Print formatting, in general; Print formatting for Objects.


SerialIO

Object Types

SerialIO

SerialIO allows communication with many ICs that communicate on the ‘Microwire’ and ‘Serial Peripheral Interface’ (SPI) buses. Because there are so many different devices available, and each has a slightly different protocol, the SerialIO object provides a general interface. This is analogous to the low level I2C Net commands.

The SerialIO object controls four VM-1 channels. These are connected to the ‘Chip select’, ‘Serial Clock’, ‘Data in’ and ‘Data out’ lines of the device(s).

It is possible to multiplex the Chip Select signal to allow more than one device to be put on the bus. These devices would not be fully independent as they share the Serial-Clock, Data-in and Data-out signals. Thus if you want to use them in different tasks you will need to use the locking provided.

The connections from the VM-1 to a device are as follows. See the VM-1 data sheet for the channel numbers:

VM-1 Function | Connect to
µwire Din | Device’s data out*
µwire Dout | Device’s data in
µwire clock | Device’s serial clock
µwire Chip select | Device’s chip select

*Not necessary if no data comes back.

The input and output data are related to the clock edges as follows:

Output data from the VM-1 is set up, and then the clock is pulsed high and low. Output data is held for some time after the clock goes low.

Input data is sampled a while after the clock goes high, but before it goes low.

Data is clocked in and out MSB (Most Significant Bit) first.

Only as many clock pulses are are needed to clock the data out are used. After the data is clocked out the clock signal returns and stays at the low state.

The approximate overall clock period is 7uS. As the bus is controlled by manipulating digital I/O in software, the data set-up and hold times are of the order of a microsecond.

Summary of messages

MAKE

Off
On

Put


Creation

MAKE s SerialIO (Int bits)

Where bits is the number of bits to be clocked in or out with each access. The maximum number of bits is 32. If your application requires several different word lengths, then you can define an object to handle each length. As well as returning the object, this command will initialise the VM-1 channels to be used. For example we might want 12 bits sent.

MAKE s SerialIO(12)

memoryUse

SerialIO is a Zero-Memory object


Off

obj . Off

This pulls the Chip Select signal high to end a communication.


On

obj . On

This pulls the Chip Select signal low to start a communication.


Put

obj . Put(Int data) lrarrow Int

obj . Put(Int n_bytes, Int source, Int dest)

Data is sent and received with the same command. This is because some devices receive input data at the same time as sending output data. Data is clocked in and out MSB first.

Single data items

For sending and receiving a single item of data use Put with one parameter:

s.Put(data)

Using the above 12-bit example, this will send the value of data in 12 bits. It will also receive 12 bits of data output by the device, if they are present. This value is returned by Put and may be used in any way, for example:

val := s.Put(27)

Block data transfer

If you need to send and/or receive a block of data you can use Put in ‘block transfer’ mode. Here a block of data (8-bit bytes only) is sent, and a block may also be received.

In this mode Put has three parameters:

· n_bytes – the number of bytes to transmit (and receive)
· source – the address of the block of data to transmit
· dest – the optional address of the block to put received data into.

If the dest parameter is not present, or has a value of zero, then received data is not processed.

The source and dest parameters are usually found by taking the Address of two Arrays. Take care when using the dest address and the n_bytes count as getting them wrong will cause the system to misbehave in an unpredictable manner.


Shaft

Object Types

Shaft

Shaft monitors quadrature-phase inputs to keep track of the position of rotary (shaft) encoders. Up to 2 shaft encoders producing edges with a phase difference and overlap of at least 0.1mS and a pulse width of at least 0.16mS may be monitored.

Summary of messages

MAKE

Count

Reset

PRINT


Creation

MAKE obj Shaft (Int ch1, Int ch2 , Int chanx)

A new Shaft object is created, monitoring channels ch1 and ch2. The initial count is zero.

The channels ch1 & ch2 must be paired: 1 with 2 and 16 with 17.

Note: if the count value counts the wrong way, then you will have to alter the hardware in order to swap which phase of the signal goes to which channel.

Relating Clock and Pulse I/O

Each Shaft object uses a counter/timer register from the processor’s internal TPU module to hold the count. This means that no pulse I/O object can use that register.

The optional parameter chanx allows you to choose the channel on which you wish to sacrifice pulse I/O. If you don’t include chanx, a default channel will be used:

The optional parameter chanx allows you to choose which pulse I/O channel you wish to sacrifice. If you don’t include it, the following default channel will be used:

Shaft input channels | Default channel used up
2 and 1 | 6
17 and 16 | 18

Any channel that is not usable for pulse I/O is still available for use as Digital.

For a full explanation of how clock and pulse I/O are related, see the diagram and text in the VM-1 Datasheet: Relating Clock and Pulse I/O.

MAKE encoder1 Shaft(16,17)

MAKE encoder2 Shaft(1,2,3)

The first example creates a Shaft object reading channels 16 and 17. Channel 18 becomes unavailable by default. The second example uses the optional parameter chanx to create a Shaft object reading channels 1 and 2. Channel 3 becomes unavailable.

Hardware | For channel details see the VM-1 Datasheet.
LIMIT | A maximum of 2 Shaft objects may be created.


Count

obj . Count lrarrow Int

An active variable that holds the count of quadrature phase edges seen by the Shaft object. The count can be set or read. The diagram below gives an example of input waveforms and the count that they might produce. Note that the count will change on every edge.

LIMIT | Count can hold values up to around ±2 billion, but only values up to around 1 billion may be held by variables.
TimingIcon | The phase difference or overlap between the two input clocks should be greater than 1.5 'states', and the pulse width should be greater than 2.5 'states', or VM-1 will not count correctly. If the phase difference is very near zero, then the count may go either up or down. A state is one period of the processor clock: 1/16th of a microsecond, normally.
SeeAlso | See also Reset, PulseCounter


Reset

obj . Reset

Resets the count to zero.

SeeAlso

See also Count.


Printing

PRINT obj

Prints the current value of the Count like this:

[Shaft: 1330]

SeeAlso

See also Count.


String object

Object Types

String object

String objects are strings of variable text - that is you can assign the text they are to hold at runtime, unlike string constants, which are defined at program time.

A string object has a capacity, or maximum length - this is the memory reserved for it when it is created. The actual text held in the string at any time may be less than the capacity of the String object, but it can never be more.

The text of a string object is null-terminated, i.e. there is a character of value zero at the end of the text. The size of a string doesn't include this character.

String constants

Constant (i.e. quoted) strings and String objects (or variable strings) are very similar - they are treated the same in almost every situation in Venom-SC, however you cannot do any write operations to a constant string, and the Get, Readpoint, Reset and Queue messages don't work.

Summary of messages

MAKE

Compare

Element

Empty

Find

Get

Free

Flush

Length

Put

Queue

Readpoint

Reset

Value

PRINT

PRINT TO


Creation

MAKE obj String (Int size)

Create a string with a capacity of size characters. The string is initialised to be empty.

Usage note: Don't bother using String objects where you could use a variable that refers to a string constant:

s := "some text"

;...and maybe later:

s := "some other text"

Removing Strings

Sometimes you will wish to create a string for temporary use, and then discard it later. You can remove the string using the .Die message. This returns the memory taken by the string. Also take a look at AUTODESTRUCT and DELETE as these may be useful.

SeeAlso | String constants
LIMIT | The maximum capacity of a string is ~64K (65535) bytes long.
memoryUse | Strings use up the memory taken by the text plus an overhead of 12 bytes. Six of these bytes are the memory taken by any object that is held on the heap. Strings require contiguous memory in the heap - so if you try to create a very large string in system that has been running for a while with a lot of dynamic memory allocation going on (creating and killing objects, for example) then you many find that there is not enough contiguous memory to create the string. In that case MAKE will generate a Resource Error.
BugAlert | BUG ALERT: Note the following Venom code snippet does not put the contents of the string constant into the string variable - it overwrites s with the string constant, and, critically, it loses the string object you made, together with the memory it took. This is an example of a memory leak, which, if it is repeated enough will result in your application running out of memory. If you suspect your application has memory leaks in it, you can use the garbage scanner to detect them. MAKE s String(10) s := "some text" One way of doing this correctly is MAKE s String(10) s.Put("some text")


Compare

obj . Compare (String or Buffer str, Int uncased, Int length)  rarrow  Int

Compare compares two strings. This allows you to put strings in alphabetical order. A Text Buffer may also be used as the second string.

The integer result returned depends on whether the second string is 'less than', 'greater than', or the same as the first string. Here, 'greater than' and 'less than' refer to comparing the strings character by character until one has a higher ASCII value than the other (or they turn out to be identical strings).

You can think of the Compare message as a minus sign between the two strings.

The return result is:

> 0 (Positive) | If the second string is 'less than'
= 0 (Zero) | If the second string is the same
< 0 (Negative) | If the second string is 'greater than' the first

For example:

-->PRINT "The first string" . Compare("The second string")

-13-->

Though of course normally you wouldn't be comparing two string constants.

Case-insensitive comparison

The optional, second parameter determines whether the comparison is case sensitive or insensitive. The default value (0) means case sensitive. If the second parameter is 1 then the comparison is done in a case-insensitive manner:

-->PRINT "The first string" . Compare("THE FIRST STRING", 1)

0-->

Note that the case-insensitive compare is done in UPPER CASE, which leads to the following characters being treated as greater than any alphabetic character:

[ \ ] ^ _ `

Length-limited comparison

The optional third parameter, length, will limit the comparison to the first length characters of the string. If length is missing or zero the length of the comparison will be unlimited.


Element

obj . Element (Int item_number) lrarrow Int

obj . (Int item_number) lrarrow Int

The Element() active variable allows both read and write random access to the contents of a string as if it were an array. Thus you may read or write individual characters in the string.

If you try to write outside the boundaries of the string you will get an Array index out of range Error.

Note: Venom abbreviated syntax allows the use of .() to substitute for .Element().

Note: Write access is only permitted for variable strings, and not string constants; if you attempt to write to a string constant you will get an Assignment to write-protected item error.


Empty

obj . Empty

Empty sets a string to an empty string: "" by writing a null character at the start. The actual memory held by the string is still available, so the string may have new text data written to it using Put or PRINT TO at a later time.

Empty does not remove the string from memory. To do thus use the message Die.


Find

obj . Find (String str, Int start_pos) rarrow Int

obj . Find (Buffer buf, Int start_pos) rarrow Int

Find searches a string for occurrences of the search text.

The search text is held either in another string or in a text buffer.

The search starts at the optional position specified by start_pos (or from the start of the string if no second parameter is supplied).

If a match is found, the start position of the found text is returned, otherwise the value -1 is returned.

The following example finds the start position of the first occurrence of a string constant in the string:

MAKE s string(100)

s.Put("text ttx txt text")

pos := s . Find ("tex", 3) ; pos will be 13

LIMIT If the search text is held in a text buffer, then only the first 256 characters are used.


Flush

obj . Flush

Flush removes any text from before the readpoint, copying it to the front of the string. The readpoint is reset to 0.

The overall capacity of the string remains the same, but the length will be reduced if any text is moved.


Free

obj . Free rarrow Int

Free returns the amount of space left in this string - i.e. how many more characters may be Put or PRINTed to it before it is full.


Get

obj . Get rarrow Int

Returns the character from the string at the current Readpoint and increments the Readpoint.

Runtime error 8 if at end of string.


Length

obj . Length rarrow Int

Length returns the current length of the string. This is not the same as the capacity of the String object.


Put

obj . Put (Any data)

Put will append a single character (Integer, Character constant), string constant or string object the text currently held by the string, but only up to the capacity of the String object. Text that won't fit into the String is ignored.

LIMIT Put is only allowed for variable string objects.

SeeAlso PRINT TO


Queue

obj . Queue  rarrow  Int

Shows how many characters are available to read with Get message, i.e. between Readpoint and end of string.


Readpoint

obj . Readpoint lrarrow Int

Set or gets the current Readpoint, i.e. the position at which the next Get will read a character.

The string starts at Readpoint=0

Runtime error 8 results on attempt to assign Readpoint past current string length.

SeeAlso Get


Reset

obj . Reset

Shorthand for obj.Readpoint := 0


Value

obj.Value([Int or Float prototype]) rarrow Int or Float

Returns the numerical value of the string

The value returned is of the same data type as the prototype, and if the prototype is an integer, its value is taken to be the number base.

If no parameter is given, a decimal integer is assumed (equivalent to a parameter value of 10)

For example:

Parameter | Interpretation
none or 10 | decimal integer
2 | binary integer
16 | hexadecimal integer
1.0 | float

The base works for values up to 32, assuming use of the letters A-Z or a-z for the digits above 9.

Any white space characters at the start of the string are skipped, and the conversion stops at the first character that is not a valid part of the type of number being evaluated, or at the end of the string if encountered first


Accepting Print

PRINT TO <String>, <print item>, ...

Strings are able to accept print. The print output is simply appended to any existing text in the string, up to the capacity of the string.

Text that won't fit into the capacity is ignored. For example:

MAKE str String(10)

PRINT TO str, "Some text to over-fill the string"

PRINT str

Gives the result:

Some text

LIMIT PRINT TO is only allowed for variable string objects.

SeeAlso Put


Printing

PRINT obj

PRINT obj : n

PRINT obj : start : n

Printing a string prints out all the text in the string.

If the optional format parameters are used then any subsection of the string may be printed. See formatting strings for details.

Example

Extract a subsection of a string and put it in another string:

PRINT TO s2, s1:5:3


Stopwatch

Object Types

Stopwatch

Stopwatches are for timing events. Once created they immediately start counting time in milliseconds. You can reset the time, or set it to any value you like, including negative values.

Summary of messages

MAKE

Reset

Time

PRINT


Creation

MAKE obj Stopwatch

A new Stopwatch object is created. Its Time is set to zero, but immediately starts incrementing at 1000 per second. For example:

-->MAKE s Stopwatch
-->PRINT s:1
00:00:00:03-->

SeeAlso

See also Timer, RealTimeClock, PulseWidthIn.


Reset

obj . Reset

Resets the Stopwatch’s time to zero.


Time

obj . Time lrarrow Int

Reads or sets the Stopwatch’s time in milliseconds. Time may be set to any value, including negative values.

LIMIT | You should be aware that after ~25 days (2,147,483,648 ms), the number of milliseconds timed by the stopwatch will exceed the size of the largest integer, and so you won't be able to store Time anywhere. After ~50 days Time will wrap round and become negative. You should therefore reset any Stopwatches before this period if you need to rely on their Time value.
TimingIcon | Stopwatches count in milliseconds. The accuracy depends on the VM-1's crystal oscillator. See the VM-1 Datasheet
SeeAlso | See also PulseWidthIn for timing between edges on signals.


Printing

PRINT obj : Int f1 : Int dp

Prints the time or the period of the Stopwatch in different formats. f1 gives the format style to use.

f1 | Format | Key
:0 | DD:HH:MM:SS.sss | D is a day digit (0-24)
:1 | HH:MM:SS.sss | H is an hours digit (0-23)
:2 | MM:SS.sss | M is a minutes digit (0-59)
:3 | SS.sss | S is a seconds digit (0-59)
 |  | s is a fraction of a second digit, specified by dp.

dp gives the number of decimal places to print the seconds value to. If dp is zero then no decimal point or fractional digits are printed.

Tip: if you want to print out any ordinary integer in the format used by Stopwatch or Timer, you can create a Timer object, set its Period to the value you want to print, and then print it, remembering to specify printing the Period.

LIMIT | dp has a maximum value of 3.
LIMIT | If no format is supplied the value of the Stopwatch is printed in the form: [Stopwatch: Time in mS].


Task

Object Types

Task

A Task object is used to represent and control a task started with the START command.

A task object is returned by the START command. You can’t create a task object using MAKE or NEW.

When a task comes to an end (either by running out of code to execute, or with STOP, the task object remains. However it ‘knows’ that the task it refers to does not exist anymore.

Summary of messages

Creation

Die

Done

PRINT

SeeAlso See also STOP & LIST.


Creation

There is no MAKE for Task objects - they are created by START.


Die

obj . Die

Die will stop the task. It is equivalent to STOP obj.

tsk . Die


Done

obj . Done rarrow Int

Done returns TRUE when the task is no longer running.


PRINT

PRINT obj

PRINT or LIST will print the details of a task, for example

-->PRINT tsk

TASK 1:

in this_procedure(line 2)

in a task started from main (line 2).

[During bytecode 'BRA' at $2603FE]

___________________


Timer

Object Types

Timer

Timer objects are software countdown timers. Once started, a Timer object ‘runs’ for a given number of milliseconds, and then stops.

Summary of messages

MAKE

Asserted

AwaitAsserted

AwaitNotAsserted

Done

Go

NotAsserted

Period

Reset

Time

PRINT


Creation

MAKE obj Timer (Int period)

A new timer object is created. Once the timer is started it will ‘run’ for period milliseconds before stopping. A timer is created in the stopped state.

For example:

MAKE tmr Timer(100000) ; a 100 second timer

LIMIT | The maximum value the period may be set to is the largest positive integer (~2billion), which is equivalent to ~24 days.
SeeAlso | See also Stopwatch, RealTimeClock; WAIT, EVERY
memoryUse | You can make as many timer objects as you require. Each one will take a small amount of memory.


Asserted

obj . Asserted rarrow Int

Asserted returns TRUE if the Timer is running, i.e. it has been started but has not stopped yet. Returns FALSE if the timer has stopped.

SeeAlso

See also NotAsserted


AwaitAsserted

obj . AwaitAsserted

Waits until the timer is started.

SeeAlso

See also Asserted, NotAsserted, AwaitNotAsserted


AwaitNotAsserted

obj . AwaitAsserted

Waits until the timer has stopped.

SeeAlso

See also Asserted, NotAsserted, AwaitAsserted


Done

obj . Done rarrow Int

Done returns TRUE if the timer has stopped, and FALSE if the Timer is running.


Go

obj . Go

Starts the timer, effectively loading Period into Time.

SeeAlso

See also Period, Time


NotAsserted

obj . NotAsserted rarrow Int

NotAsserted returns FALSE if the timer is running, and TRUE if it has stopped.

SeeAlso

See also Asserted


Period

obj . Period lrarrow Int

Period holds the millisecond value that gets loaded into Time when the timer is started with Go, etc.

Period is an active variable.

LIMIT | The maximum value Period may be set to is the largest integer (~2billion), which is equivalent to ~25 days.
TimingIcon | All timing is done in milliseconds. The accuracy of the timing depends on the controller's crystal oscillator. See the VM-1 Datasheet.
SeeAlso | See also Creation, Time, Go, Printing


Reset

obj . Reset

Reset immediately stops the timer. It cannot be restarted from where it left off.

SeeAlso

See also Creation, Go


Time

obj . Time lrarrow Int

Time is an active variable holding the countdown time: the time left before the timer stops. Time may be set – this allows you to alter the period before the timer stops. If the timer has stopped then setting Time non-zero will start it.

LIMIT | The maximum value Time may be set to is the largest integer (~2billion), which is equivalent to ~25 days.
TimingIcon | All timing is done in milliseconds. The accuracy of the timing depends on the VM-1's crystal oscillator. See the VM-1 Datasheet.
SeeAlso | See also Creation, Period, Go, Printing


Printing

PRINT obj : Int f1 : Int dp : Int select

Prints the time or the period of the timer in different formats. f1 gives the format style to use:

f1 | Format | Key
:0 | DD:HH:MM:SS.sss | D is a day digit (0-24)
:1 | HH:MM:SS.sss | H is an hours digit (0-23)
:2 | MM:SS.sss | M is a minutes digit (0-59)
:3 | SS.sss | S is a seconds digit (0-59)
 |  | s is a fraction of a second digit, specified by f2.

dp gives the number of decimal places to print the seconds value to. If dp is zero then no decimal point or fractional digits are printed.

select chooses whether the time printed should be the Time or the Period. If select is missing or zero, then the Time is printed, if select is 1 then the Period is printed.

Tip: if you want to print out any number in the format used by Stopwatch or Timer, you can create a Timer object, set its Period to the value you want to print, and then print it, remembering to specify printing the Period.

LIMIT | dp has a maximum value of 3.
LIMIT | If no format is supplied the Timer is printed in the form: [Timer: Period : Time].


TouchScreen

Object Types

TouchScreen

The TouchScreen object interfaces to a TSC2003 Touch Screen Controller IC via the I2C Bus. The IC may be used to detect the position of a finger or stylus touching a resistive touchscreen.

Normally a touchscreen is placed in front of a graphics LCD, functioning as the input device in a Graphical User Interface. The TouchScreen object is able to convert the touch position on the screen into the coordinates used on the Graphics LCD.

It is possible to define virtual keys on any area of the touchscreen, and to create a Keypad object that uses the touchscreen as its input device. Thus, all the higher-level functions of Keypad may be implemented on a touchscreen.

Hardware | This object requires a TSC2003 IC to be present.
SeeAlso | See also GraphicsLCD.

Summary of messages

MAKE

Asserted

Conversion

Key

NotAsserted

Value


Creation

MAKE obj TouchScreen(Int type, Int Bus, Int I2C_addr)

Type gives the type of touchscreen hardware to be driven. Only type 0, the TSC2003, is currently supported.

Bus is the number of the I2C Bus: either 1 or 2.

I2C_addr is the address of the TSC2003 on the I2C Bus and must be in the range 144-150 (even numbers).

The Micro-Robotics I2C address is obtained by doubling the 7-bit address usually given in a device datasheet.

A touchscreen object will normally be used in conjunction with a GraphicsLCD object, and may be used with a Keypad object.

Example

MAKE t Touchscreen(0, 1, 144)

SeeAlso

See also GraphicsLCD, Keypad


Asserted

obj . Asserted rarrow Int

Asserted returns TRUE if the touchscreen is being touched.

When Asserted detects a touch it records the X,Y coordinates of the touch so that they may be read out using the Value message.

SeeAlso

See also Value.


Conversion

In each individual touchscreen assembly the touchscreen system has to be calibrated so that the X, Y coordinates it returns coincide with the screen coordinates of the graphics LCD. This calibration is handled automatically by the Conversion message.

The Conversion message has two different forms:

The first form is used to set up the calibration.

The second form allows the four calibration constants to be read out of, or written into, the TouchScreen object. The calibration data can in this way be stored for repeated use so the actual calibration need only be done once.

Initial Calibration

This form of the message is used to calibrate the touchscreen:

obj . Conversion (Int phase, Int xpixel, Int ypixel)

The basic procedure is this:

1. Draw a cross near the bottom left corner of the LCD. Let’s call it (X1, Y1).
2. Send TouchScreen the message Conversion (1, X1, Y1) – i.e. using the same coordinates as the cross. The Conversion message will wait for a touch.
3. Touch the cross accurately
4. Sound a beeper, or otherwise let the user know the touch was detected.
5. Draw a 2nd cross near the top right corner of the LCD. Let’s call it (X2, Y2).
6. Send TouchScreen the message Conversion (2, X2, Y2)
7. Touch the 2nd cross accurately
8. Sound a beeper, or otherwise let the user know the touch was detected.
9. The calibration constants are then calculated and stored by the object. All subsequent readings of the coordinates will be calibrated.
10. The four numbers that represent the calibration may be accessed, using the second form of the Conversion message, and preserved in non-volatile storage.

Example of calibration procedure on Graphics LCD’s full-screen window ‘w’:

#define POSA 50 ;Position of the ‘+’ symbol.
#define SZ 5 ;Size of the +
#define XSZ 320 ;LCD Size
#define YSZ 240

TO calibrate_touch
PRINT TO w,CLS,"Touch screen calibration"
w.Line( POSA-SZ, POSA, POSA+SZ, POSA)
w.Line( POSA ,POSA-SZ, POSA, POSA+SZ)
t.Conversion(1, POSA , POSA)
PRINT BEEP

PRINT TO w,CLS
w.Line( XSZ-POSA-SZ, YSZ-POSA, XSZ-POSA+SZ, YSZ-POSA)
w.Line( XSZ-POSA, YSZ-POSA-SZ, XSZ-POSA, YSZ-POSA+SZ)
t.Conversion(2, XSZ-POSA, YSZ-POSA)
PRINT BEEP
END

Reading and Writing calibration data

obj . Conversion (Int index) lrarrow Int

When sent with one parameter, the Conversion message reads or writes the calibration constants. There are four constants (index is in the range 0 – 3), and each constant is a two-byte (16-bit) number.

The constants represent X-offset, Y-offset, X-scale, Y-scale.

When the Touchscreen object is first created these constants are given default values that result in the touchscreen reporting touches as the raw output values from it's 12-bit ADC - i.e. values in the range 0 - 4095.

Storing a Calibration

The four calibration constants may be stored in, and subsequently retrieved from, non-volatile storage, making it unnecessary to perform a calibration every time the system is turned on. See the example below:

#define TWO_BYTES 16 ;Define data size for each entry.

#define XSUM_POS 8 ;Position in EEPROM of checksum.
TO init_touch
MAKE eeprom SafeData(0,1,162) ;Non-volatile storage

; Is the calibration data in the EEPROM valid?
IF eeprom.Checksum (0,XSUM_POS-1) = eeprom.(XSUM_POS,TWO_BYTES)

[

; Then Load the data into the TouchScreen object.
REPEAT 4
t.Conversion(index0) := eeprom . (index0 * 2, TWO_BYTES)

]
ELSE
[
calibrate_touch ;Do the calibration.

; Save the calibration data.
REPEAT 4
eeprom.(index0 * 2 , TWO_BYTES) := t.Conversion(index0)

; set the checksum to validate the data.
eeprom.(XSUM_POS,TWO_BYTES) := eeprom.Checksum(0,XSUM_POS-1)
]
END

SeeAlso

See also SafeData


Key

obj . Key (Int x1, Int y1, Int x2, Int y2)

obj . Key

The Key message allows an unlimited number of ‘virtual keys’ to be defined on the touchscreen.

Each key is a rectangle defined by the coordinates (x1, y1) & (x2, y2).

Each time the Key message is called with four parameters, a new key is added. The keys are numbered from zero upwards in order of creation.

In this example four keys are created, and a rectangle is drawn around each key on window ‘w’.

#define KEYBD_X 10
#define KEYBD_Y 10
#define KEYSIZE 40
#define KEYSPACING 45

TO keys
LOCAL x:=KEYBD_X, y:=KEYBD_Y

t.Key ;reset the key list.
REPEAT 4
[
w.Box(x , y , x+KEYSIZE , y+KEYSIZE , 1)
t.Key(x , y , x+KEYSIZE , y+KEYSIZE)
x := x + KEYSPACING
]
END

Scan order

When keys are scanned (using the Keypad object), the scan is done in numerical order starting with Key 0. A touch position is compared with each key in turn, and the first key to match is returned. This is important to consider if you define keys with overlapping areas. It can be useful to define overlapping keys. For example you may want the background to be a default ‘key’ that is detected if no others are.

Removing keys

If you call the Key message with no parameters then all the keys are discarded, and new ones may be defined if desired.

t.Key ;reset the key list.

Using the Keys

To use the keys as a keypad, create a keypad based on the touchscreen like this:

MAKE t TouchScreen (0, 1, 144)

MAKE kpd Keypad (t)

Then use the Keypad object in the normal way to detect key presses, etc.

Usage Note: If you redefine a TouchScreen virtual keypad when, say, moving from menu to menu, you should be aware of how the Get message for Keypad’s InputBuffer will behave, as it is currently implemented: when the old set of keys is removed from the TouchScreen object, but before the new set has been defined, the InputBuffer may detect no key being pressed. If the operator is still pressing the touch screen when the new keypad is defined, this will be interpreted as a new key press. One solution is to not the change the virtual keys until the operator has stopped touching the screen.

SeeAlso

See also Keypad


NotAsserted

obj . NotAsserted rarrow Int

NotAsserted returns TRUE if the touchscreen is not being touched.

X, Y coordinates of the touch are recorded.

SeeAlso

See also Asserted


Value

obj . Value (Int ordinate) rarrow Int

Value returns the X or Y ordinate of a touch. This will be in Graphics LCD coordinates if calibration was carried out as detailed in Conversion.

The X and Y coordinates are set each time Asserted detects a touch on the touchscreen.

Value (0) | X ordinate
Value (1) | Y ordinate

This example draws a line to each new touch on the screen:

TO lines
EVERY 50
[
IF t.Asserted
[
w.Line( t.Value(0), t.Value(1))
]
]
END

SeeAlso

See also Conversion, Key


TCP/IP Networking

There is more to programming TCP/IP networking applications that can be covered adequately by an entry under “Protocol” in the "Object Types" section of this help file. This section has:

· A detailed reference section for each type of protocol objects
· Notes on how the objects interact
· Advice on programming robust real applications

Protocol Object

The generic Protocol class covers a set of objects that control different communication protocols. Several are related because they are different parts of a TCP/IP stack. The XMODEM file transfer and SMS message protocols are independent protocols that use a serial port directly and are documented separately under "Protocol" in the "Object Types" section.

How the protocols are related

IP Protocol Family

Glossary of Abbreviations

Name | Expansion | Description
ARP | Address Resolution Protocol | Matches up 48 bit ethernet addresses with IP addresses
CHAP | Challenge Handshake Authentication Protocol | Part of PPP – a more secure method of verifying a user’s credentials
CRC | Cyclic Redundancy Check | Verifies that data in a packet has not been corrupted in transmission.
DNS | Domain Name Service | Relates domain names to IP addresses
FTP | File Transfer Protocol | list directories, send and receive files
HTTP | HyperText Transfer Protocol | The protocol used between web browsers and web servers.
ICMP | Internet Control and Monitoring Protocol | Used by IP devices to test and report on the state of the network.
IP | Internet Protocol | Concerned with addressing and routing
IPCP | Internet Protocol Control Protocol | Part of PPP – deciding IP addresses of the ends of a link and DNS addresses
ISP | Internet Service Provider | Usually the entity at the other end of a PPP link, providing a connection to the rest of the internet.
LAN | Local Area Network | Network sharing a common geographical location and address range
LCP | Link Control Protocol | Part of PPP – setting up connections, negotiating options
MAC | Media Access Control | The lowest level ethernet protocol. MAC address = ethernet hardware address
PAP | Password Authentication Protocol | Part of PPP – verifying a user’s credentials
PPP | Point to Point Protocol | Family of protocols for using serial lines for packet transfer
TCP | Transmission Control Protocol | Setting up sessions between two endpoints; error-free transfer of streams of byte data between the two points
UDP | User Datagram Protocol | For speedy short messages and time-critical data streams
URI | Uniform Resource Identifier | Standard method of naming a resource on a network and the protocol for retrieving it
URL | Uniform Resource Locator | As URI, but more specific about location of resource


Protocol Object

TCP/IP Networking

Protocol Object

The generic Protocol class covers a set of objects that control different communication protocols. Several are related because they are different parts of a TCP/IP stack. The XMODEM file transfer protocol is an independent protocol that uses a serial port directly.

Summary of messages

MAKE


Creation

Make p Protocol( string name, various param)

Protocol names

"IP" = IP protocol object

"POP3" = POP3 incoming mailbox object

"PPP" = PPP link via serial object

"ETH" = Ethernet interface object

"SMTP" = SMTP email sender

"TELNET" = Telnet client object

"TCP" = raw TCP socket object

"UDP" = UDP Datagram object

"HTTP" = HTTP server object

"FTPServer" = FTP (File Transfer Protocol) server object

"FTPClient" = FTP (File Transfer Protocol) client object

"XMODEM" = XMODEM file transfer object (not part of TCP/IP)

"SMS" = SMS GSM text message control object (not part of TCP/IP)

The other parameters vary with the name given and are described in the sections below.

IP Addresses and domain names

An IP address is a 32 bit number. It is conventionally written as a “Dotted Quad” of decimal numbers representing one byte each e.g. “152.158.91.245” but can also be represented by an integer in Venom.

Any messages parameter described as host can be either

· An integer representing the IP address
· A string representing the address as a dotted quad
· A string containing the domain name, assuming the VM-1 has TCP/IP access to a name server, which is usually the case if an internet connection is available.
· A string containing a local host name assigned with the IP.Address message.

The following code illustrates an IP address is constructed, and the use of the “IP” formatting specification in a PRINT statement.

-->a := 23

-->a := a * 256 + 42

-->a := a * 256 + 159

-->a := a * 256 + 212

-->print a:"IP",CR

23.42.159.212

-->

The preceding calculation can also be done by sending the Value message to an IP object (see ip.Value).


IP

TCP/IP Networking

IP

IP stands for Internet Protocol. The protocol is concerned with addressing and routing packets on the Internet, and with certain test and housekeeping functions.

An IP object does not have to be created in order for IP to be used for routing and addressing incoming and outgoing IP datagrams, nor for TCP or UDP connections. The IP module autonomously handles routing, accepting IP address registration from the PPP module and Ethernet modules, creating a loopback interface on 127.0.0.1 and routing packets between TCP clients, the PPP links and (if/when available) the Ethernet interface. The module also replies to any incoming ICMP echo (ping) requests.

A Venom IP object can be created to enable certain services:

· Testing the network using the Time message, which acts like the well known "ping" utility.
· Converting Dotted Quad IP addresses and domain names into numerical IP addresses.
· A general TCP/IP interface polling function.
· Assigning names to local IP addresses.

Summary of messages

MAKE

Address

Debug

Find

Go

PRINT

Time

Value


Creation

MAKE ip Protocol("IP") rarrow Protocol Object


Address

ip.Address (name)  larrow  ipaddress

This stores the association of a symbolic name with a numerical IP address (integer or dotted quad string) in a local table. This may be useful for local networks so hostnames can be used without a DNS server. Any number of addresses can be assigned this way.

ip.Address (host) rarrow Int

Converts a hostname or IP address in dotted quad notation to a numerical IP address. If the host string starts with a numeric character it is assumed to be a dotted quad IP address, otherwise is it treated as a host name and will either return an address that was previously assigned by the first form of the Address message or if not in the list will be found by DNS lookup like ip.Find.


Debug

Debug can be used in two ways.

ip.Debug(n)

Shows information, chosen by the value of n

n | Information displayed
1 | Routing table
2 | List of host addresses assigned using the Address message

ip.Debug(int type) larrow Int

e.g.

ip.Debug(0) := 1 ; enable packet logging

Controls logging of IP packets and events to files in a RAM file system

· Debug(0) controls logging of packets to ip.packet.log.
· Debug(1) controls logging of events to ip.event.log.
· A value of 0 stops logging and closes the file.
· A value of 1 starts logging. If the file was not in use, it is cleared.
· A value of 2 starts logging and always appends to the existing file.
· Each file is opened in a mode that limits the size to 5000 bytes so only the latest data is retained.
· The value can be changed at any time to turn on and off the logging activity.

A RAM file system must exist for this feature to work


Find

ip.Find(string) rarrow Int

The parameter can be a fixed string or text buffer.

Performs a DNS query to convert a domain name or hostname into an IP address. This is the same function as udp.Find. The names "localhost" and "loopback" are recognised and converted automatically to 127.0.0.1. All other names require an internet connection so the names can be looked up with a nameserver.

ip.Find(Int n) lrarrow Int

Returns IP address of name server in use, or assigns the address of a nameserver to use. n can be 0 or 1 denoting the two nameserver addresses that are tried in succession.


Go

ip.Go(Int milliseconds)

Polls all IP interfaces at regular intervals for the length of time specified.
If a parameter of 0 is supplied, polls forever and does not return. This is useful to keep interfaces alive in one task while another task does not have to implement code to poll the TCP/IP interfaces frequently.


PRINT

PRINT ip

Prints the routing table. The default routing table only contains the localhost address 127.0.0.1. When a PPP connection is made, its address is added to the routing table and becomes the default route. The ethernet object can also add network and host addresses to the routing table. (see Ethernet.Address)


Time, Period

ip.Time (Any host[, Int Timeout])  rarrow  Int
ip.Period (Any host[, Int Timeout])  rarrow   Int

Returns time to respond to ICMP echo request ("ping") in milliseconds. If there is no response after 10 seconds a value of -1 is returned.

host | is either a string containing a domain name or dotted quad IP address, or an IP address as an integer
Timeout | if specified, overrides the 10 second default timeout in milliseonds

Period is a synonym for Time.


Value

The older message name Value is a synonym for Address.


POP3

TCP/IP Networking

POP3

POP (Post Office Protocol) version 3 is a protocol for fetching mail from an external mailbox. It is a popular mechanism for users on the end of a dialup link to collect mail from a mailbox on their ISP's server on demand.

A POP3 object is a holder for a mailbox list. When opened it represents a list of incoming messages corresponding to the mailbox on the ISP's server. The messages are referenced by number, and the POP3 object allows the program to retrieve headers and/or message body for local processing and to delete messages from the remote mailbox.

A POP3 client must log in to a POP3 server, supplying a user name and password, in order to prove that it is entitled to read and delete its messages.

Summary of messages

MAKE

Close

Count

Element

Length

Open

PRINT

Remove


Creation

MAKE pop3 Protocol("POP3", Str server)

server is a string or text buffer containing the domain name of the mail server that will be used. Typically this information is supplied by an ISP when the account is opened. A typical value might be "pop3.ukfsn.org".

This creates a mailbox object. Its initial state is empty and closed.


Close

pop3.close

Close a mailbox. The TCP connection to the server is closed, and afterwards no access is possible to the mailbox contents. A side-effect is the physical deletion of any messages on the server that were previously marked for deletion with the Remove message.


Count

pop3.Count rarrow Int

If the mailbox is open, returns the number of incoming messages listed


Element

pop3.Element(Int msgno, Str tag) rarrow String

msgno is the message number.

tag is a string or text buffer to match the name or first part of the name of a header element.

A header element is one of a sequence of lines of text which precede the message and contain control information. Common examples are:

· From: shows the email address from which the message was sent
· To: shows the email address of the intended recipient of the message
· Subject: What the message is about

The header element name is terminated with a colon. The tag parameter to the Element message must match the first part of the tag. The matching is not case sensitive. E.g. "Date" and "date: " will both match "Date: "

The value returned is the address of a fixed string which is valid as long as the POP3 object is open. The string contents are the header line starting from the first non-blank character after the colon.

Example

print pop3.element(3, "from"), CR

sales@microrobotics.co.uk

-->


Length

Pop3.Length( Int msgno) rarrow Int

msgno is the message number assigned by the server.

This message returns the number of characters in an email message, including the headers.


Open

Pop3.Open(Str username, Str password) rarrow Int

username defines the user whose mailbox is to be opened.
password must be the correct password for that user.
Each parameter can be a fixed string or text buffer.

This message makes a TCP connection to the mail (POP3) server specified when the POP3 object was created. The value returned is:

· 0 or positive number: the number of messages in the mailbox
· -1 : unable to make a TCP connection
· -2 : POP3 authentication failed
· -3 : some other error or timeout during the exchange of messages after logging in


Remove

pop3.Remove(msgno)

Marks the specified message for deletion. Runtime error if out of range. Note that after marking a message for deletion all the messages are still in the mailbox and have the same numbers. Actual deletion occurs when the mailbox is closed.


PRINT

PRINT pop3

Prints a list of message numbers and the size of each message

PRINT pop3:msgno[:maxlines[:maxchars]]

Prints the message contents of the message headers, controlled by colon parameters.

msgno is the message number, starting at 1 for the first in the mailbox. Runtime error if out of range.
maxlines if non-zero, print the message body only up to the maximum number of lines specified. If this parameter is missing, the default value is 100 lines. A value of 0 means print the message headers instead of the body.
maxchars specifies the maximum number of characters in the message body, and will override the maxlines setting if this limit is reached first. Default limit if parameter is missing: 5000 characters.


PPP

TCP/IP Networking

PPP

PPP stands for Point to Point Protocol and is a widely used standard for encapsulation of packets and link management on a serial line.

A PPP object makes a connection via serial line and modem or GPRS terminal, usually to an internet service provider. The object handles all LCP and IPCP negotiation.

Features

CHAP or PAP authentication

IPCP negotiation to obtain dynamic IP address and DNS server addresses.

Summary of Messages

MAKE

Close

Debug

Element

Open

Period

Timeout

Valid


Creation

MAKE ppp Protocol("PPP", serialobject)

The serialobject parameter is an AsynchronousSerial object previously created. PPP has been extensively tested on serial port 2 but should work on either of the VM-1's serial ports. The port is usually expected to be connected to a modem or GPRS terminal.


Close

ppp.Close

Disconnect.
Sends LCP terminate request, and then attempts to disconnect the modem by sending the standard disconnect sequence:

<1 second pause> "+++" <1 second pause> "ATH0" <CR>

Off is a synonym for Close .


Debug

ppp.Debug lrarrow int

Enables (1) or disables (0) debug output during the connection phase.

The DEBUG option produces a trace, for a terminal connected to serial port 1, of the modem control and LCP packet exchange, which may help when testing the connection to an ISP with a modem or GPRS unit. Typical output will look like this:

user_dbg=1

ATZ

OK

AT+CGDCONT=1,"IP","orangeinternet"

OK

ATD*98*1#

waiting for CONNECT

CONNECT

user Orange secret

Tx:LCP:CONFREQ id=180 len=4

Rx:LCP:CONFREQ id=3 len=29 MRU=2000 ACCM=000a0000 PFC ACFC MAGIC=ac14e9f8

AUTH=CHAP

Tx:LCP:CONFREJ id=3 len=24 MRU=2000 ACCM=000a0000 PFC ACFC MAGIC=ac14e9f8

Rx:LCP:CONFACK id=180 len=4

Rx:LCP:CONFREQ id=5 len=9 AUTH=CHAP

Tx:LCP:CONFACK id=5 len=9 AUTH=CHAP

Rx:CHAP challenge id=1 len=25:

Tx:CHAP response id=1 len=27:

Rx:CHAP success id=1 len=4:

Tx:IPCP CONFREQ id145: [6]IPADDR=0.0.0.0


Element

Element (COPY)

ppp.Element(str tag) lrarrow str

tag is a string or text buffer having one of several standard values documented below.

The value assigned can be a string or text buffer.
The value returned is a fixed string

Tags for PPP.Element

"MINIT1" 1st modem initialisation string
"MINIT2" 2nd modem initialisation string
"DIAL" modem dial command, typically starting "ATD"
"USER" user name for PAP or CHAP authentication
"PASS" password for CHAP or PAP authentication
"DNS1" dotted quad IP address of DNS server
"DNS2" second DNS server
"HOSTMODE" "1" for hostmode (see below).
Note that DNS1 and DNS2 do not usually have to be specified, as they will be overwritten by values provided by the ISP during IPCP negotiation.

Example

ppp.Element("MINIT1") := "AT&F0"

ppp.Element("MINIT2") := "AT&D0M0"

ppp.Element("DIAL") := "ATDT08452121666"


Open

p.Open rarrow IP address or 0

Starts connection and returns IP address of negotiated connection if successful, zero if failed.

On and Go are synonyms for Open.

· The response from the modem is monitored for certain strings to speed up the response time, and the timeouts depend on the command sent to the modem.
· The strings "ERROR", "NO CARRIER", "NO DIALTONE" are recognised at any time and result in immediate failure return.
· The string "OK" is recognised and results in the next command being sent immediately.
· If the command contains the string "ATD" there is a 60 second timeout waiting for a response
· All other commands have a 2 second timeout waiting for a response

After the modem has made a successful connection there are exchanges of LCP packets to establish a valid connection to the internet:

1. LCP negotiation to establish that the VM-1 performs no compression, and escapes all ASCII control characters. At this stage the VM-1 also finds out whether the remote end prefers PAP (Password Authentication Protocol) or CHAP (the more secure Challenge Handshake Authentication Protocol). The VM-1 can use either.
2. Authentication: the chosen protocol is used, with the username and password, to establish the VM-1's identity
3. IPCP (Internet Protocol Control Protocol) determines the local and remote IP addresses of the ends of the PPP link, and attempts to obtain primary and secondary nameserver (DNS) addresses.

Host Mode

Host mode is useful for connecting to the VM-1 from another computer via a direct serial link with software such as Windows Dialup Networking or Linux chat and pppd, designed for use with a modem and dialup connection to an ISP. It can also be used to connect a pair of VM-1's together. If host mode is set, the VM-1 behaves initially like a modem. It responds to "AT" commands with "OK" until it receives an "ATD" command when it responds with "CONNECT" and then starts LCP negotiation. Host mode expects no user authentication and assigns the VM-1 the IP address 192.168.230.230 and the calling computer the address192.168.230.231. Future versions may allow these IP address values to be overriden.


Period

ppp.Period  lrarrow  Int

Returns and optionally sets the period in milliseconds of inactivity after which LCP ECHO messages are sent.

Setting a value of 0 disables sending echo messages and checking for timeouts.

The default value is 0 (echo testing disabled)

If this value is set non-zero, the PPP protocol will send an LCP echo request message when no packet has been received for the period specified, and while no packets are received will send more echo requests at time intervals of the same period. If no response is received after a timeout period is exceeded, the link is assumed to be down and marked internally as dead, requiring a new Open message to restart it. The default timeout period is 120 seconds, which can be changed with the Timeout message.

Normally an echo request should cause an echo response to be sent back immediately from the other end of the link.

The Period value should be set much smaller than the Timeout value so that several echo requests can be sent before the link is declared dead. Typical figures might be:

Period | Timeout | no. of echo requests
10000 (10 sec) | 60000 (1 min) | 5
30000 (30 sec) | 120000 (2 min) | 4

SeeAlso See also: Timeout


Timeout

ppp.Timeout lrarrow Int

Returns and optionally sets the timeout period in milliseconds after which the link is assumed dead if no packets have been received.

This mechanism is only enabled if echo requests have been enabled by setting Period to a non-zero value. See Period description for hints on suitable values.

The default timeout value is 120000 (120 seconds).

SeeAlso See Also: Period


Valid

ppp.Valid rarrow Int

Returns true (-1) or false (0) depending on whether the link is open and working.

A false value can mean any of the following:

· Initial state, not connected
· sent a Close message
· received a TERMREQ packet from other end
· Packet reception timeout, only if echo requests were enable with the Period message

SeeAlso see also: Close, Period, Timeout


Ethernet

TCP/IP Networking

Ethernet

The ethernet Protocol object controls an ethernet hardware interface. After the object is created it can be assigned address ranges for the connected LAN (Local Area Network) and gateway addresses for reaching other destinations via the LAN. All packets for addresses on the LAN or reachable via a gateway will automatically be routed though the ethernet interface. All the IP based protocols such as UDP and TCP and higher level protocols that use these will work over the ethernet interface in the same way as they do over PPP.

Any ethernet device has an ethernet address, commonly called a MAC (Media Access Control) address which should be unique in the world for each device, to guarantee that devices on the same network will all have individual addresses. The MAC address of each ethernet interface made by Micro-Robotics is programmed in during production and taken from a unique address block assigned to Micro-Robotics by the IEEE.

In IP networking, each device on a LAN will have an IP address too, which should be unique within the LAN but part of a block of related addresses. You must assign an IP address as part of your network system design. The ethernet object automatically handles the ARP (Address Resolution Protocol) to match IP and MAC addresses for devices on its network.

Summary of messages

MAKE

Address

Count

PRINT


Creation

MAKE eth Protocol("ETH", Int busnum, Int select [, Int ipaddress ])

MAKE eth Protocol("ETH", Int busnum, Int select, 0 [, str name ])

busnum | is the I2C bus number 1 or 2 used internally for addressing the ethernet controller's EEPROM in which the MAC address and IP address are stored.
select | is a byte value written to address decoding logic to enable the ethernet controller. Its value depends on the hardware inferface between the VM-1 and the ethernet controller, but usually a specific pattern in the low 4 bits will be required.
ipaddress | is the optional IP address of the ethernet controller. If specified, the address is stored in the EEPROM on the ethernet controller. If not specified, the address previously stored in EEPROM is used. A value of 0 means use DHCP to find the IP address (see DHCP, below)
name | If ipaddress is given as 0, an optional string here is sent to the DHCP server as a hostname and may be transferred to a local DNS so other devices on the network can find the VM-1's IP address by using its host name. (see DHCP, below)

Normally this will create an ethernet interface control object. If the hardware is missing or if the EEPROM contents have become corrupted, run time error 12 (device not found) will result. If you suspect EEPROM corruption, contact Micro-Robotics for advice on restoring the correct MAC address to your ethernet interface. You will need the ethernet interface serial number when you do this.

Hardware

If the Micro-Robotics ethernet card 5810 is being used on the Micro-Robotics application board 5811 the parameters for creating the object should be bus number 1 and select value $d, for example:

MAKE eth Protocol("eth", 1, $d, "192.168.1.1")

Note: The IP address 192.168.1.1 is an example only. It is a value that may work with many LANs, but the correct value really must be determined from the address range in use on the LAN or obtained by DHCP (see below). The ethernet Address message section gives some useful information on network address ranges.

SeeAlso

See Also: 5810 data sheet, 5811 data sheet

DHCP (Dynamic Host Configuration Protocol)

This is often used for configuring IP addresses and other parameters automatically. If you have a DHCP server on your network (the function may be included in a simple box like an ADSL router) you can use it to configure the following parameters automatically:

· IP address of the VM-1's ethernet interface
· IP address of the default gateway to destinations outside the LAN
· IP address of DNS nameserver

In some networks the DHCP server is linked to a local name server. If a hostname parameter is given when creating the VM-1's ethernet interface, the name is sent to the DHCP server, and should be transferred to the DNS server so that another network user can reach it by name. For example, if the ethernet is set up with the following command:

MAKE eth Protocol("eth", 1, $d, 0, "controller1")

and you create a web server in the VM-1, you can reach it using a web browser and the URL: http://controller1


Address

eth.Address("DHCP" [, str hostname]) rarrow Int

This attempts to use DHCP to get or refresh the IP address and gateway and DNS addresses from a DHCP server on the local network. It is useful if DHCP failed when the ethernet object was created, for example because the VM-1 was not physically attached to a network at the time, and the network cabling has subsequently been re-attached.

The value returned is TRUE (-1) if address information was successfully obtained from a DHCP server, FALSE (0) if there was no server response. If there was no server response, the IP address of the ethernet interface remains unchanged.

eth.Address('I' [, ipaddr addr[, ipaddr mask]]) lrarrow int

addr is an IP address to assign to the ethernet interface.

mask is a mask to define the network part of the address.

The value returned is the IP address of the interface.

If mask is not specified a default value is assigned according to the standard Internet address classes convention:

Address Range | Mask
0.0.0.0 – 127.255.255.255 | 255.0.0.0
128.0.0.0 – 191.255.255.255 | 255.255.0.0
192.0.0.0 and higher | 255.255.255.0

The value of addr is determined by the range of addresses used by the network. In an existing network, a network administrator should assign a suitable address and mask value for the device being attached. For private networks, there are special ranges of addresses which can safely be used without reference to any internet authority. These are:

Address Range | Mask
192.168.0.x – 192.168.255.x | 255.255.255.0
172.16.x.y – 172.31.x.y | 255.255.0.0
10.x.y.z | 255.0.0.0

In the lists above, all addresses in one network must have the same values in the parts designated by digits, and all must have different values denoted by x,y and z. In general, a 1 bit in the mask corresponds to part of the network address (constant within the LAN) and a 0 bit corresponds to part of the host address (different for each device within the LAN).

DHCP

If you created the ethernet object specifying DHCP, you should not need to use this message as the DHCP server will have sent an IP address to the VM-1.

eth.address('C')

(mnemonic “Clear”)

This removes all IP routing table entries for this interface.

eth.address('D', addr)

(mnemonic: "Default")

This sets a default gateway. All packets not routeable via an explicit route will be sent to this gateway in the LAN for forwarding to another network. If the addr parameter is missing, the current gateway address is returned, or 0 if there is none.

DHCP

If you created the ethernet object specifying DHCP, you may not need this message, as the DHCP server should have sent the gateway address.

eth.address('G', addr, subnet [,mask])

(mnemonic: "Gateway")

addr | is the address of the gateway, which must be local to the network.
subnet | is the base address of the range of addresses to be routed via that gateway.
mask | if specified, sets an subnet mask to define the range of addresses. If not specified a default mask is used following the rules for eth.address('I').

This sets up a gateway through which to route packets with addresses in a given range. It will not often be necessary to provide a gateway address for a range of addresses like this as most networks will use a default gateway for everything not local to the LAN, but this capability allows more complex setups when required. Note that the VM-1 cannot obtain information on such networks by DHCP; you have to specify it yourself.

eth.address('N', addr)

(Mnemonic: "Nameserver")

Sets the address of a DNS nameserver to resolve domain names. If addr is missing, the current nameserver address is returned as an integer.

This message is the equivalent of sending the message Find(0) := addr to an IP Protocol object.

If you need to use domain names, you should set the address of a DNS server known to be accessible to your network. This will either be a server on your LAN itself or that of your Internet Service Provider.

DHCP

If you created the ethernet object specifying DHCP, you may not need this message, as the DHCP server should have sent the name server address.


Count

Eth.Count(int n [, 0]) rarrow int

The value returned is a count of events as specified by n:

n = 0 Packets received

n = 1 Packets transmitted

n = 2 Missed received packets

n = 3 Transmit errors

n = 4 Collisions

If a second parameter with a value of zero is present, the counter is reset to zero.


PRINT

PRINT eth [: Int mode]

Printing an ethernet object will display its MAC and IP address in the following format:

ETH: MAC=00:50:c2:3d:12:34 IP=192.168.14.101

If a colon operator is present, it can have the following effects:

0 Print MAC address only

1 Print IP address only


FTPClient

TCP/IP Networking

FTPClient

This Protocol object is an FTP (File Transfer Protocol) client which connects to FTP servers and can get a server directory listing and send and receive files.

N.B. FTP is and old and widely supported protocol on the internet, but it is not secure. User names, passwords and file data are transferred unencrypted and file transfers can be intercepted in either direction.

The Venom FTP objects support a small but commonly used subset of the FTP protocol as documented in RFC959.

FTPClient Messages and equivalent FTP Protocol commands

This is probably only interesting if you are already familiar with the workings of FTP.

Open | USER PASS
Get | PORT or PASV RETR
Put | PORT or PASV STOR
Remove | DELE
Name | RNFR and RNTO
Go | CWD
Close | QUIT
PRINT obj:0 | PWD
PRINT obj:1 | NLST
PRINT obj:2 | LIST

The FTPClient object can request binary or ASCII file type, but as the Venom filesystem convention is to use CRLF for line endings there is no difference in the processing at the Venom end (but the server may do ASCII translation of text from its local system convention)

MAKE

Close

Debug

Get

Go

Open

Put

PRINT


Creation

MAKE ftp Protocol("FTPCLIENT" [, Int bufsize [,Int mode])

Parameters

bufsize | (default 2048) The size of the TCP buffer in the data connection, for the direction in which file data will be transferred
mode | 'A' for active, 'P' (default) for passive - determines the mode for opening the data connection

Buffer Size and Memory Usage

For best performance a big TCP buffer is desirable on the data connection for the direction in which data is being transferred. The buffer size parameter selects the size for this buffer (see TCP Creation). All other buffers are the 1024 byte minimum as data sizes are small.

Active and Passive Modes

When the data connection is opened, it can be initiated from either the server end or the client end.

The terms Active and Passive are from the server's point of view, so:

Active means the server opens a data connection to the client

Passive means the client opens the data connection to the server

Passive mode is used by typical web browsers and is appropriate if the client is behind a firewall that restricts incoming TCP connections. Occasionally a server behind a firewall will need to use active mode for similar reasons.

Port Numbers (Technical Note for Firewall Administrators)

If you are using a VM-1 which makes ftp connections outside a LAN through a firewall, and which for some reason must use Active mode, you may find it useful to know that the Venom FTP client's PORT command will use data connection port numbers in the range 2000-3999, so the firewall can be configured to allow incoming connections to those ports.


Close

ftp.Close

Closes the connection with the server, first sending an FTP QUIT command, then closing the control TCP connection.

Harmless if FTP connection already closed.


Debug

ftp.Debug(Int Value)

Parameter

0 - no debug output

1 - display control connection dialogue

When debug mode is enabled, all commands to the server and responses back from the server are displayed on the serial 1 terminal. This is useful when any FTP operation doesn't work, as the server responses usually contain explanatory text.


Get

ftp.Get(file f, str name) rarrow Int

Parameters

f | An open file in which to receive the file data
name | Fixed string or text buffer with the name of the file on the FTP server (can include path)

Returned Value

True (-1) for successful transfer, 0 (false) for any failure.

Gets a file from the server, storing its data in the open file. Any existing file contents are replaced with those of the retrieved file.

The data type for the FTP transfer is ASCII if the local file was opened as a text file, binary for any other file type.


Go

ftp.Go(str path) rarrow Int

Parameters

path

specifies new directory path

Return Value

true(-1) if changed working directory successfully, false (0) if not.


Name

ftpclient.Name(oldname, newname) rarrow Int

oldname | String or text buffer: contents must match the name of an existing file on the server
newname | String or text buffer containing the new name for the file

Returned value: true (-1) if rename was successful, fails (0) otherwise.

Renames a file on the remote server to a new name.

If newname matches an existing file on the server, that file is deleted before the other file is renamed to it.

Note that this message is useful when updating a file on a server where a process on the server may be reading the file at any time. By uploading to a temporary file and then using rename, the update to the real file is a single instantaneous operation and the reading process will never see a partially filled file.


Open

ftp.open(site, str user, str password) rarrow Int

Parameters

site | Integer or string IP address, or hostname. String can be fixed string or text buffer
user | fixed string or text buffer holding user name for logging in to FTP server
password | fixed string or text buffer holding user's password

Return Value

True(-1) for successful connection and login, fale(0) if failed for any reason


Remove

ftpclient.Remove(name) rarrow Int

name

String or text buffer containing name of file to be removed

Returned value: true (-1) if remove was successful, fails (0) otherwise.

Removes a file or directory from the remote server.


Put

ftp.Put(file f, str name) rarrow Int

Parameters

f | An open file to send
name | Fixed string or text buffer with the name of the file to be created or replaced on the FTP server (can include path)

Returned Value

True (-1) for successful transfer, 0 (false) for any failure.

Sends a file's contents to the server. The server replaces any existing file of the same name with the new contents.

The data type for the FTP transfer is ASCII if the local file was opened as a text file, binary for any other file type.


PRINT

PRINT ftp

Prints [FTPCLIENT] followed by some state information

PRINT ftp:0

Prints the servers's current directory as a string, if a control connection is open

Otherwise prints a single question mark

PRINT ftp:1[:str path]

path

optional string or text buffer specifying directory path to list

Prints a directory listing of the server's current directory or specified path.

The format of the listing is one file name per line separated by CR LF and is thus designed to be usable by a program.

If the connection is closed, prints a single question mark.

PRINT ftp:2[:str path]

path

optional string or text buffer specifying directory path to list

Prints a directory listing of the server's current directory or specified path

The format of the listing is server-dependent and designed to be human-readable.

If the connection is closed, prints a single question mark.


FTPServer

TCP/IP Networking

FTPServer

The FTP (File Transfer Protocol) Server object runs a server that requires no program input from the controlling Venom program once set up.

It will work with either RAM or FAT file systems, with the limitation that RAM filesystem does not support directories.

The essential services of FTP are:

· User authentication
· listing directories
· transferring files to or from the server

The following FTP commands are understood:

USER | Login: user name
PASS | Login: password
NOOP | Null command for testing and suppressing inactivity timeout: returns "200 OK"
CWD | Change working directory
CDUP | Change to parent directory
PWD | Print working directory
QUIT | Log off and disconnect
PORT | Client says which IP address and Port it is listening on (active mode FTP)
PASV | Request Passive mode transfer
TYPE | File data type: Any type accepted. VM-1 does not treat binary and ASCII differently as its file system stores ASCII compatibly with FTP ASCII mode.
RETR | Retrieve a file from server and transfer to client
STOR | Store a file in the server's file system, transferred from the client
LIST | List files in default directory listing format
NLST | List file names only separated by CRLF
SYST | Replies with "WIN32", which is a recognized OS name.
SIZE | Size for a file, error message for a directory
STAT | Shows system status info: Venom version, logged in user
RNFR | Rename "from" file name
RNTO | Rename "to" file name
DELE | Delete file
XCWD | Synonym for CWD
XPWD | Synonym for PWD
XCUP | Synonym for CDUP

See the description of the Run message for more details on how each command is handled.

The FTP server has been tested successfully with:

· Unix and Windows command line FTP clients
· SmartFTP (Windows graphical FTP client)
· Mozilla Firefox
· Microsoft Internet Explorer.

Limitations

LIMIT

· The server doesn't allow clients to create directories
· Only one user can be logged in at a time (but multiple Venom tasks can run a server object each)
· Only ASCII and binary types and the streaming mode are supported (but the alternatives are rarely used)
· Numerous less frequently used FTP commands are not supported

Summary of Messages

MAKE

Debug

Go

Run

PRINT


Creation

MAKE ftpserver Protocol("FTPSERVER", FileSystem fs, str name, str password

[, str directory])

fs | The FileSystem to use for file transfer operations.
name | String or text buffer with valid username to log in to FTP server
password | String or text buffer containing password required for successful login
directory | (FAT file system only, ignored if used with RAM File system) Optional false root directory for FTP operations. All file system content outside this directory is completely invisible to an FTP client. Default is root directory.

Both the username and password may contain wildcard characters: '?' matches any character, and '*' matches any string.

If a false root directory is specified, it must exist on the file system.

SeeAlso See Run description for more notes on false root directory and server operation

Memory Usage

memoryUse

Creating an FTPServer protocol object uses about 2430 bytes of memory.

A file or listing transfer opens another TCP connection which uses approximately 5k.

TCP/IP and file system activity also use unpredictable amounts of memory temporarily.


Debug

ftpserver.debug(Int mode)

mode

0 - no debug (default)

1 - enable debugging output

When debugging output is enabled, the ftp object sends to serial port 1 a message describing every command received and every response sent back to the client.

A typical sample of output looks like this:

ftp: sending response: 220 VM-1 FTP server

cmd: "USER vm1" : USER

ftp: sending response: 331 OK, send password

cmd: "PASS secret" : PASS

ftp: sending response: 230 Logged in

cmd: "PASV" : PASV

ftp: sending response: 227 passive 172,16,1,150,15,132

cmd: "LIST" : LIST

ftp: sending response: 150 Opening data connection

ftp: sending response: 226 LIST done.

cmd: "SYST" : SYST

ftp: sending response: 215 WIN32


Run, Go

ftpserver.Run[(Int time)]

ftpserver.Go[(Int time)]

time

Number of milliseconds to run

Runs the server for the specified number of milliseconds. If no parameter is given, runs the server for ever.

If a file transfer is requested during the period specified, the Go message does not return until the file transfer has been completed.

While the server is running, one user at a time may log in and perform file operations. To enable simultaneous access by more users, separate ftp server tasks can be created.


Notes on FTP

Notes on Supported FTP Commands

The full details of these commands, their parameters and response codes are documented in RFC959 "File Transfer Protocol". The descriptions below summarize the set of commands supported by the VM-1. In practice you should not need to know these details as you should be able to use the FTP server with many existing FTP client programs (including many web browsers that can handle FTP), but if anything goes wrong, the information below may help to diagnose the cause.

If the FTP server was created with a false root directory, all references to the filesystem's directory structure are relative to that directory. E.g. if the filesystem has a directory "/ftp" which is used as a false root, an ftp request for "/file1.txt" will access "/ftp/file1.txt" on the file system. When the FTP current working directory is "/" it would be "/ftp" on the file system, and the FTP command "CWD .." or "CDUP" at that point would not result in a change of directory.

Use of a false root directory is recommended for any system connected to the internet as it protects all files outside that directory from any malicious user that has gained ftp access.

USER, PASS

These must be sent in the correct order and with the correct user name and password. As a measure against brute force password guessing attacks, a series of failed logins causes a response delay whose length increases with each failure. After 1 minute of failed login attempts or inactivity the control connection is disconnected and the failure response delay reset to 0.

When the FTPServer object is created, both user name and password can be specified with wildcards. '?' matches any charcter; '*' matches any string.

NOOP

Can be used by an FTP client to check that the server is listening or to prevent an inactivity timeout.

Only works when logged in.

Response is 215 OK

CWD dir

XCWD dir

This command is only valid when the file system supports directories, e.g. FAT system.

A directory name beginning with '/' is taken to be an absolute directory.

Otherwise it is a subdirectory of the current directory.

The special string ".." is interpreted as "change to parent directory". It is accepted but has no effect when used in the root directory.

On the RAM file system, "/" is accepted as a target directory. Any other value causes an error response.

CDUP

XCUP

Equivalent to CWD .. or XCWD ..

PWD

XPWD

Print working directory. The FTP root directory is the root of the file system.

"/" is shown as the root directory, even if the file system is RAM

QUIT

Disconnects the control connection, allowing another incoming connection and login to start.

PORT <text> h1,h2,h3,h4,p1,p2

Indicates that data transfers are to be carried out in active mode. The server will connect to the IP address and port specified by the numbers h1-h4 and p1, p2.

PASV

Causes the server to send a response detailing the IP address and port number on which it will listen for data transfers, and to set up a listening (passive) TCP connection when a data transfer is required.

The IP address will be the same as used for the control connection.

The port number will be in the range 2000-3999.

TYPE x

Specifies file data type. x is usually 'A' for ASCII or 'I' for Image (binary). The server accepts any value, but as the format for storage of ASCII text in files on the VM-1 is the same as the format for ASCII mode FTP transfer, no special processing is required for either data type. The command is therefore ignored but produces a response

200 TYPE OK

RETR filename

Retrieve a file - the file is sent to the client. The filename my be a simple name for a file in the current directory, a full path starting with '/', or a relative path from current directory.

STOR filename

Stores a file from the client in the location and name specified. The filename and path are as for the RETR command. If a file with the same name existed, it is overwritten.

LIST filespec

For a FAT filesystem, filespec may be:

· a directory
· a directory followed by a wildcard file specification
· a wildcard file spec only

The returned data is a list of files in UNIX "ls -l" format, because this format is expected by semi-automatic clients like web browsers.

The filesystem PRINT message is used for this function.

SeeAlso See FileSystem (FAT) PRINT and FileSystem(RAM) PRINT.

NLST filespec

Produces a list of file names only, separated by CRLF. For the FAT filesystem, filespec can be used and can contain directory path and wildcards.

RNFR filespec

RNTO filespec

These set up source and destination names for a file rename operation. RNFR must be sent first and followed by RNTO with no intervening command. Either filespec can be a full path (starting with '/') or a name within the current directory, and can be the name of a file or directory. If the "to" and "from" paths are different, the file or directory is moved to the new position in the directory structure.

DELE filespec

Deletes a file. If filespec refers to a directory, all its files and subdirectories are deleted too.

SYST

Produces the response

215 WIN32

The response has to be a recognized string as defined in the IANA "assigned numbers" document and also needs to be one likely to be recognized by web browsers. "WIN32", whilst wildly inaccurate, at least correctly reflects the capabilities and limitations of the FAT file system used in the VM-1 and is likely to be widely recognized by ftp client programs.

SIZE

For a plain file, produces the response

230 nnnnn

Where nnnnn is the file size in bytes.

For a directory, the response is:

550 Not a plain file.

This information seems to be used by some clients (e.g. web browsers) as an ad hoc way of guessing whether a name in a directory listing is a plain file or a subdirectory.

Timeouts

Any inactivity of more than 60 seconds, or failure to login successfully within 60 seconds, causes the control connection to be disconnected.

No file data transfer timeout is currently defined.


HTTP

TCP/IP Networking

HTTP

The HTTP object can be used as the basis of a web server thread. It creates a TCP listener, parses incoming http requests and creates the necessary headers and other protocol for the response. The application program thus only has to identify the URI (Uniform Resource Identifier) requested and create a response either by printing HTML or by sending buffer or file contents to the HTTP object.

The HTTP protocol object can work automatically with a local file system, so that an incoming request for a file will result in that file being sent without any Venom program involvement at all. The object will guess the correct MIME data type for common file naming conventions and will send sensible default cache control headers to improve efficiency.

The object supports http GET requests with parameters in a query string in the URI. This has important applications for sending data to the VM-1 from a browser, typically in response to submitting a form or just clicking on a button to alter the state of a remote device.

Enough of the http protocol is implemented to enable the VM-1 to process common requests originating from any web browser, to process data sent by a typical HTML form and to respond with data encoded in a way that any browser can handle.

Sending HTML code in response to a request is a simple matter of using PRINT statements to generate the required text.

The creation of HTML code is a wide-ranging topic that is not documented here.

VHTML - HTML with embedded Venom Variable Names

A special variant of HTML code allows Venom global variable names to be embedded in what would otherwise be an HTML file. Such a file is identified by its name ending with the string ".vhtml".

Inside the file, variable names are enclosed between backslash ('\') characters.

If a literal backslash is needed in the HTML code it is represented by an empty name i.e. two consecutive backslashes.

When the file is sent in response to an http request, the global variable table is searched for a matching name. Type conversions are performed according to the C language printf() formatting conventions as follows:

· integer: "%ld"
· float: "%g"
· strings and text buffers are sent verbatim.
· Unmatched variable names are substituted with the string "?xxxx", where xxxx is the name.
· Variables whose type is invalid are substituted with the string "?type:xxxx" where xxxx is the name.

It's worth emphasising that variables substituted in this way do not necessarily have to be in ordinary display text. They could appear in the attributes for an HTML tag, or in part of an embedded CSS style specification for example. This is useful for changing default values of form input elements, and offers creative possibilities such as data-driven changes of colour or bar-graph charts.

Notes on URIs

An http request is typically of the form:

GET http://www.example.com/index.html?test=abc HTTP/1.1

or

GET /index.html?test=abc&rate=10 HTTP/1.1

The first form is an absolute URI with the scheme (http://) and host (www.example.com) included. The second form is called a relative URI. Either may be sent by a browser; the http protocol object will skip the host part if present.

The '?' character and following string are optional. This query string, if present, contains data that can be processed by the server. It is typically sent when an HTML form is submitted, in which case it is a sequence of "name=value" pairs separated by '&'. Because certain characters are unsafe to send in a GET query like this they are escaped; the HTTP Protocol object translates these escape codes when the data is retrieved by a Value message.

HTTP Protocol Considerations

Persistent connections

The HTTP object supports persistent connections, i.e. when a request has been received and the response sent the TCP connection remains open so further requests can be sent in the same connection. The connection is closed if no further requests are received for 5 seconds, or if the remote end closes the connection.

Note that an application using the HTTP object should run several web server tasks. To communicate with one browser needs 2 tasks as the HTTP standard (RFC 2616) recommends the use of a maximum of two two simultaneous connections per user agent. More are needed if you expect multiple users to access the VM-1's web server concurrently.

Headers

The HTTP object ignores all headers in the request, using default settings.

The headers sent in responses are:

Server: VM-1/yyyymmdd | yyyymmdd is the venom release date code
Date: Tue, 28 Nov 2006 14:23:12 GMT | The standard format for HTTP dates
Transfer-encoding: chunked | All data is sent in this format
Cache-control: | Either a max-age value or "no-cache" (see Period message)
Content-type: | See Format message for some default automatic types

Methods

Only the GET method is currently supported.

POST may be added to a later version.

Summary of messages

MAKE

Flush

Format

Get

Valid

Value

PRINT

Put

Queue

PRINT TO


Creation

MAKE http Protocol("HTTP" [, filesystem fs, [, Int port[, Int txbuf, Int rxbuf]]])

filesystem | must be present and specifies a file system to be searched for files to match incoming http GET requests for serving automatically. If this parameter is missing or nil then no file system will be used.
port | if specified, defines the port number for the TCP listener. By default the object will listen on port 80, which is the standard port number for http.
txbuf, rxbuf | define the transmit and receive buffer sizes for the TCP object. Default buffer sizes are txbuf 4096 and rxbuf 2048.

The make statement creates an http type protocol object and associated TCP listener. The HTTP object includes a buffer in memory for storing response data prior to transmission.

memoryUse

An HTTP Protocol object with default TCP buffer sizes uses 11710 bytes of memory when created


Address

http.Address rarrow Int

The Address message returns:

· 0 if the http object is in the listening state
· the IP address of the originator of the request if the http object has returned from a Get message or a Queue message has returned a value of 1

Example

path := http.Get

PRINT "request from ", http.Address:"IP", CR


Flush

http.Flush

Transmits any remaining data in the response buffer, then returns the http object to a listening state.

If no data was sent to the object following a successful Get, the Flush message causes a pre-packaged HTTP Error 404 (Not Found) response to be generated.

A Flush message must always be sent to the http between Get messages, even if the first Get returned a request for something non-existent.


Format

http.Format(string/buf mimetype)

mimetype

Fixed string specifying the MIME (Multipurpose Internet Mail Extension) data type for the response string.

The MIME type data must be a recognised string in the general format type/subtype.

This message is only necessary to override the default MIME type generated by the HTTP object, based on the URI received. By searching the URI for certain strings the following types are inferred by default, and if the request is for a file that exists the indicated MIME-type will be sent automatically.

URI substring | Default MIME type | Use
.png | image/png | Graphics images, especially drawings and solid colours
.jpg .jpeg | image/jpeg | Graphics, especially photographic images
.gif | image/gif | As PNG, older standard
.htm, .html | text/html | HTML code
.vhtml | text/html | HTML code with Venom variable names embedded. See VHTML
.txt | text/plain | text not to be interpreted as HTML, usually displayed in a fixed size font
.css | text/css | Style sheets to define presentation style of HTML pages
.log | text/plain | Log files are assumed to be plain text
default | application/octet-stream | A generic stream of bytes - unknown application

A full list of registered MIME media types is available at http://www.iana.org/assignments/media-types/.

BugAlert Minor bug: the parameter must be a fixed string. It should be allowed to be a text buffer also.


Get

http.Get rarrow Str

Waits for incoming request that cannot be processed automatically. When one is received, returns the requested resource path as a fixed string which remains valid until a Flush message is sent to the HTTP object..

http.Get(stringobj s)

In this form, the path is stored in the string object supplied as a parameter.

The resource path, in simple terms, is the part of the URI that looks like a file name. For example, if the URI was

http://www.mysite.com/search.html?keyword=VM-1

The path would be search.html

If no file system was specified when the HTTP object was created, then every incoming request will cause Get to return. Otherwise during the Get, any incoming request whose path matches a file name in the file system and which has no query string will be serviced automatically. This includes the processing of VHTML files. The Get will not return until something is requested which does not match a file name or which has a query string.

If there is a query string (e.g. keyword=VM-1 in the example above) then Get returns the path as usual.

Data can be retrieved from the query string with the Value message.


Period

http.Period  larrow  Int

This sets the period of time in seconds the the returned data can be allowed to remain in a browser or proxy cache. The purpose of this is to speed up response when the same data is requested more than once and has not changed. If a web browser has cacheing enabled, a resource may be fetched the first time with this time period set in a Cache-control header, then during that period any further requests will use the cached copy instead of requesting it again from the VM-1. An expiry value is assigned automatically by the http protocol object and the Period message is only needed if the default is to be overridden. The Period message should be sent after Get and before sending any response data, and only applies to the current request.

A period of 0 is appropriate if the response contains variable data that is likely to change every time it is requested.

The default max-age values assigned by the http object are:

Data type | Default period
HTML, plain text, CSS | 3600 = 1 hour
graphics formats and PDF | 86400 = 1 day
VHTML | 0 (no cache)
Default (unrecognised type) | 3600 = 1 hour

Technical Detail

The relevant http protocol headers are:

Cache-control: max-age=nnn (for non-zero period values)

or

Cache_control: no-cache (period = 0)


Put

http.Put(data)

Put puts a character, buffer, string, array or file into the response buffer.

A buffer must be text or 8 bit integers.

An array must be 8 bit integers.

All integer types are sent as 8 bit binary or character data.

Text buffers and strings are sent unmodified as 8 bit characters.

Files of any type are sent as a stream of bytes as stored in the file, starting at the files's current read point and finishing at EOF, except that if the file name ends with the string ".vhtml" (the test is not case-sensitive) it is subjected to VHTML processing. The file is left open with the readpoint at the end.


Queue

http.Queue rarrow Int

Returned value:

0 if no incoming request requiring service by the Venom program is present

1 if an incoming request requires processing by the Venom program

If a request can be processed internally this is done and Queue then returns a value of 0.

The returned value thus always indicates whether a subsequent Get will return immediately.

Queue can be used in a loop where is is required that Getwill never block. e.g.

forever

[

if http.Queue > 0

process_request(http.Get)

; other tasks in loop...

...

]


Valid

http.Valid lrarrow Int

Gets or sets the numerical response code to be used in the response headers.

This is usually set automatically, but if you want to generate a customised error message to accompany an error response you can do so by printing the HTML response text to the http object and setting Valid to an appropriate value such as 404 (not found) .

The values generated by the HTTP object automatically are:

200 - OK : normal code for data response

400 - bad request

404 - Not found (e.g. file not found)

414 - request line too long (max 1022 chars)

503 - Unavailable (generated when file system media, e.g. memory card, has been removed and a file was requested)

See Internet RFC 2068 "Hypertext Transfer Protocol" for the full list of codes and their correct usage, but most values are unlikely to be useful.


Value

http.Value(name [, prototype]) rarrow Value

name

is a fixed string or text buffer containing the name of a variable that may have been sent as part of the query string in an incoming request.

If the name matches such a variable, a value is returned.

If no prototype is specified, the returned value is a fixed string. This string is valid until the next Value message is sent to the http object, so it should be printed to a text buffer if it is to be retained

If the prototype is an integer, the value is expected to be a string of digits and will be converted to an integer value which is returned.

Similarly if the prototype is a floating point value, the variable's string data is converted to a floating point value that is returned.

If the name is not present in the query string an empty string or zero numerical value is returned.

Examples of usage

PRINT TO bufval, http.Value("stringval")

intvar := http.Value("intval", 0)

fltvar := http.Value("fltval", 1.0)

A suitable URI to produce results from the above would be something like:

formresponse.html?stringval=abcdef&intval=1234&fltval="123.456"


PRINT

PRINT http

If the http object is listening, printing it produces the text: "http listening"

If a Get has returned a request and before a Flush message has been sent, printing the http object produces the text "http GET " followed by the requested URL


PRINT TO

PRINT to http, list

Any data can be printed to an HTTP object using the usual conventions for text devices. The print output is appended to the content part of the response. This is the normal way to generate an HTML page in response to an http GET request.


TCP

TCP/IP Networking

TCP

A raw TCP object type is available to enable the Venom programmer to implement proprietary or existing application protocols that use a TCP link.

A TCP connection can be viewed as a bidirectional conduit for reliably transmitting and receiving streams of bytes of any length. Any loss or corruption of data results in retransmission, so that while data integrity is guaranteed, timing is not.

Summary of messages

MAKE

Close

Debug

Die

Flush

Free

Get

Open

Put

Queue

Reset

Status

Timeout

PRINT TO


Creation

MAKE x Protocol("TCP", [, Int txbufsize [, Int rxbufsize]])

txbufsize : transmit buffer size, default 2048
rxbufsize : receive buffer size, default 2048

Creates a TCP protocol object, allocating memory for this and the transmit and receive buffers. The buffer sizes are optional. They should be specified as an exact power of 2. If not, they will be increased to the nearest next power of 2, e.g. specifying 5000 will allocate 8192 bytes. Increasing these sizes can improve performance but uses memory.


Close

tcp.Close

Closes an existing connection made by the object. The TCP protocol attempts to go through the usual sequence to close a connection. Note that closing a connection in TCP means that there is no more data to send. The connection may remain open in the receiving direction and continue to receive data. It is up to the remote end to initiate a close when it has no more data to send. See also Reset.


Debug

tcp.Debug(0) larrow Int
tcp.Debug(1) larrow Int

If a RAM file system exists, these messages control the logging of information to files.

· Debug(0) Controls logging of all TCP packets to the file tcp.packet.log.
· Debug(1) Controls logging of all TCP events (opening and closing connections, and certain exceptions) to the file tcp.event.log.
· A value of 0 stops logging and closes the file
· A value of 1 starts logging, and if the file was not currently in use it is cleared so the log starts at the beginning of the file
· A value of 2 explicitly requests appending new log data to the end of the existing file, without clearing the existing contents.
· Each file is opened in a mode that limits the size to 5000 bytes so only the latest data is retained.
· The assigned value can be changed at any time to turn on and off the logging activity.
· Sending this message to any TCP object controls logging for all TCP connections. The connections are identified by a number at the beginning of each line of log text.

SeeAlso See Also: FileSystem (RAM)


Die

tcp.Die

If the Die message is sent to a TCP object, the memory used by it is freed and any open connection will be aborted.

If a TCP object is created as a local variable in a Venom procedure or function, it must be sent a Die message before the function exits, or there will be a memory leak and problems with the existing connection persisting.

The Die message could be useful to reclaim the memory used by TCP object no longer in use, or to change the buffer sizes between one connection and another.


Flush

Flush (COPY)

tcp.Flush

Forces any locally buffered data to be sent and waits for it to be acknowledged. The packets are sent with the TCP PSH (Push function) flag set. This is intended for interactive use, where a response is expected from the other end once all the current data has been sent. The intended function of the PSH flag is to force the TCP protocol to send data immediately when it might otherwise have refrained from doing so because the resulting data segment would be small.


Free

tcp.Free rarrow Int

Returns the free space in the transmit buffer.
If Free returns a negative value it means the connection is not usable, e.g. it has been closed or reset by either end.


Get

tcp.Get rarrow Int

Gets a single character or byte from the incoming data stream.
If the connection is open but there is no data, the TCP object will wait indefinitely for data to arrive or until the timeout limit has been reached, if a timeout was set.
With no parameter, the data is normally a byte value in the range 0 to 255.
A returned value of -1 means there is no connection e.g. it has been closed or reset.
A returned value of -2 means the timeout expired.

tcp.Get(stringobj s) rarrow Int

Reads a line of input terminated by CRLF from the TCP incoming data stream into the string object specified in the parameter.

The LF character is detected as the end of line marker, but neither CR nor LF is included in the returned string.

Neither CR nor LF is included in the returned string.

Transfer also stops if the capacity of the string object is reached first.

tcp.Get(0, Int max) rarrow string or 0

A Get message with two integer parameters of which the first is 0 gets a line of text expected to be delimited by ASCII CRLF. The max parameter sets a size limit of the string returned, as a way of the protecting the program against garbage data that could result in a string of unlimited size.

If this form of Get fails due to a closed connection, an integer value of 0 is returned.

The contents of the string should be copied (e.g. By PRINTing to a buffer) for further processing before this type of Get message is sent again.

This form of the Get message is historical, dating back to before the string object type was introduced to Venom.


Open

There are different forms of the Open message, for different purposes.

Active Open

tcp.Open(host, Int port) rarrow Int

host : Integer, string or text buffer representing the remote domain name or IP address to connect to
port : Integer representing remote port number to connect to.

Opens an active connection (i.e. the VM-1 initiates a connection) to an address and port number on the net. Returns when established.

The return value is TRUE (-1) if the connection was made successfully, or FALSE (zero) if it failed.

Passive Open

tcp.Open(Int Port)

port is an integer port number.

When one parameter is specified, Open sets up the TCP object as a passive listener. The message returns immediately and the object continues to wait for an incoming connection.
A passive Open message does not return a value.
A run time error may result if the protocol object is in an incompatible state, e.g. if it already has a connection open, or the port number is invalid.

Test for Open Connection

tcp.Open rarrow Int

Return value:

-1 | if closed/unused
0 | if listening
IP address | when connected

With no parameters, the Open message is used as a test to find out whether a connection is open. After a passive open message has been sent, this will tell if an incoming connection has been received.
Always returns immediately with value according to state.


Put

tcp.Put(Int)
tcp.Put(string)
tcp.Put(buffer)
tcp.Put(array a[, Int size])

Puts a byte, fixed string or entire buffer or array contents into the outgoing data stream.

The buffer or array can be of any data type. 16 or 32 bit integers and floats are sent as stored internally in Venom, most significant byte first. Using arrays or buffers gives fast data transfer rates.

For arrays, an optional second parameter limits the size of data sent to TCP. The data is always sent from the beginning of the array.


Queue

tcp.Queue rarrow int

Return the number of bytes received and unread.
If Queue returns a negative value, it means the connection has been closed or reset. Note that when a receiving connection has been closed, Queue will continue to show a positive value while there is still unread data in the buffer, but will return negative once the last byte has been read.


Reset

tcp.Reset

The Reset message forces a TCP object immediately into the closed state. Any packet received from the other end of a prior open connection with that TCP object will be rejected with a TCP RST (reset) packet.
All unread data in the receive buffer or untransmitted data in the transmit buffer is lost. The object can then be reopened for a new connection.


Status

Status

Tcp.Status rarrow Int

The value returned has the following meanings:

0 Normal connection.

1 Host unreachable – it was impossible to route packets to the remote destination.

2 Timeout when sending – no acknowledgement received after several retransmissions of the same data.

3 Connection attempt was refused.

4 DNS lookup failure when opening an active connection to a host specified by name.

5 TCP connection closed normally

This provides more information when the return value from a queue, Free or Get message indicates that the connection is closed.


Timeout

tcp.Timeout lrarrow Int

Set a timeout value in milliseconds for the Get message. A value of 0 disables the timeout, which is the state when the TCP object is created.

This message also sets a maximum limit for acknowledgement timeouts when sending data. By default there can be a delay of over 3 minutes before a link is dropped because of lack of response. In some cases, like a local area network, it is reasonable to assume that lack of response within a few seconds indicates a non-responsive host; setting a lower timeout discovers this condition faster.


PRINT TO

PRINT TO TCP object

The PRINT statement can be used to print anything to a TCP object as if the TCP object was a text buffer or serial port. The Keyword CR results in the sequence CR LF (13, 10) being sent to the TCP data stream, which is usually the correct line ending sequence in text-based protocols over TCP, such as SMTP, POP3 and HTTP.

Other PRINT keywords are not recognised and should be avoided.


Telnet

TCP/IP Networking

Telnet

A very simple telnet client implementation. All incoming telnet option requests are rejected, none are sent and occurrences of the telnet IAC (Interpret as Command) character in the incoming or outgoing data are handled using the standard escape sequence. The VM-1 telnet protocol object is otherwise similar to the TCP object.

By default a telnet server listens on port 23, but any port number may be used.

Summary of messages

MAKE

Close

Die

Flush

Free

Get

Open

Put

Queue

Reset

Timeout

The Creation and use of a Telnet object is identical to that of a TCP object.

Note that the Put and Get messages are slower than those for TCP because of the need for escaping the IAC character and dealing with incoming IAC sequences.


UDP

TCP/IP Networking

UDP

UDP stands for User Datagram Protocol. UDP datagrams do not require the setting up of a connection. The transmission is typically fast but survival of the data in transmission is not guaranteed. UDP is useful for some types of application:

· Real time updates of continuously varying data, where any missing value is shortly overwritten by the next.
· Simple query-and-reply protocols with short messages that will fit in a single packet each. DNS queries normally use this as it is much faster than TCP.
· Any application requiring broadcast data.

UDP is used internally by Venom for:

· DNS lookups
· Getting the time and date for sending email with the SMTP object

Summary of messages

MAKE

Close

Debug

Empty

Find

Get

Go

Length

Open

Put

Queue

Time

PRINT TO


Creation

MAKE udp Protocol("UDP") rarrow udp protocol object

Creates a protocol object of type UDP. This can then be used to send and receive UDP packets.

To send packets use Put and Go.

To receive packets, use Open, Queue, Get and Empty.


Close

udp.Close

Closes a UDP listener and frees any existing transmit and receive buffers.


Debug

udp.Debug(1)

Displays a list of UDP objects, showing listening port number where applicable. Note that the list appears in reverse order of creation.

udp.Debug(2)

Lists the DNS cache, which contains a maximum of 100 most recently looked-up domain names. Entries are expired after an hour. The expiry time in minutes is shown for each entry. The most recent and frequently used entries are at the top of the list.

udp.Debug(3)

Shows information about the udp object, including the contents of any outgoing or received packets.

Any other parameter value will display a brief help message.


Empty

udp.Empty

Clear received packet, leaving buffer ready for next to be received.

Note that the UDP object can only hold one received packet at a time. While the receive buffer is occupied, any further received packets are ignored. After the Empty message has been sent, the next received packet will be placed in the buffer.


Find

udp.Find(string host) rarrow Int

Performs a DNS query to get the IP address of an internet host
host is a string containing the domain name to look up.
The returned value is the IP address of the host, or 0 if the query failed.

The names localhost and loopback are recognised internally and converted to the standard loopback IP address 127.0.0.1.

Note that a connection to a nameserver must be available for this to work for names other than "localhost" and "loopback". When a PPP connection is made to the internet, the ISP usually provides a nameserver address during the initial link negotiation. When connected to an ethernet, the Address message to an IP object can be used to define a DNS server.

This DNS mechanism uses a local cache of names and addresses to save time on repeated lookups. In the current version the cache will hold 100 entries, each entry expires an hour after it was first obtained and least recently used entries are discarded when the cache becomes full.


Get

udp.Get  rarrow  string

udp.Get(0) rarrow string

Both these forms return a string containing the data contents of any UDP packet. It would be usual to expect the packet to contain readable ASCII text when using this form of Get. If it is used on binary data the string would be considered terminated prematurely on the first zero data byte.

Note that as with any message that returns a fixed string type the data contents of the string have a limited lifetime and should be copied if you want to keep them. The data pointed to by the returned value is valid until the UDP object is sent a Close or Empty message.

udp.Get(1) rarrow Int

Returns the IP address of the sender of a received UDP packet.

udp.Get(2) rarrow Int

Returns the source port number of a received UDP packet.

udp.Get(3) rarrow Int

Returns the destination port number of a received UDP packet.

udp.Get(4) rarrow Int

Returns the data length of a received UDP packet. See also Length.

udp.Get(5, Int offset, Int length) rarrow Int

Returns a component of the data in a received UDP packet.
offset is the number bytes from the start of the packet data (offset 0 is the first data byte)
length is 1, 2 or 4 and is the size of the data item to return. Values of 1 or 2 bytes are converted into standard 32 bit Venom integers using unsigned arithmetic, so a byte value of $FF is returned as 255 and a two byte value of $FFFF is returned as 65535, not as -1.

udp.Get(Array/buffer a) rarrow Int

Returned value: the number of elements transferred

This form reads the incoming packet's data into an array or buffer, much faster than repeated udp.Get(5, x, y) messages.

The array or buffer can be of any data type.

For an array, the number of bytes transferred is the size of the UDP packet data or the size (in bytes) of the array, whichever is smaller.

For a buffer, the entire data contents of the UDP packet are appended to the buffer.

SeeAlso

Open - To configure the UDP object to listen for incoming packets.

Queue - To check whether a packet has arrived.

Empty - To clear the received packet buffer, leaving it ready for the next packet to be received.


Go

udp.Go(host, Int port [, Int myport])

Go is a synonym for the preferred Send, retained for compatibility with older code


Length

udp.Length rarrow Int

Returns the length of the data part of a received UDP packet. It is a synonym for udp.Get(4)


Open

udp.Open(Int port) rarrow Int

Allocates a receive buffer and enables the object as a UDP listener. A specific port number can be given, or 0 which means accept packets with any destination port number.

The returned value is true or false: a false value means that new listener was not created because a listener already exists with the same port number.


Put

Put (COPY)

udp.Put(Int)

Appends a character or byte value to the object's transmit buffer.

udp.Put(Array a [,Int start , Int size])

a | The array to append to the udp packet
start | start position of array data (default 0)
size | number of elements to transfer (default: to end of array)

Appends the contents of the array to the data in the UDP outgoing packet.

The array may be of any data type.

If start and size parameters are given, a subset of the array is copied.

LIMIT

Note that the UDP object imposes an internal limit of 592 bytes for the user data.

If you create outgoing packets using 16 bit or 32 bit arrays, bear in mind that these occupy 2 or 4 bytes per element respectively.


Send

udp.Send(host[, port])

Sends a packet containing the data assembled by Put and PRINT TO
host is a host (domain) name or IP address to which to send the packet.
port is the destination port number.
myport, if specified, is the source port number. A value of zero is used by default, which means the recipient is not expected to have any use for a source port number, i.e. will not be replying.


Time

udp.Time[(Int force)] rarrow Int

Returns internet time as a Venom time value, which is the time in seconds since midnight GMT on 1 January 1990. This is the same time base as used by the RealTimeClock object.

For this message to work, there must be an existing connection to the internet to set the internal clock, or you must select a local server (see below). Once the clock has been set successfully from a time server, the time is estimated using Venom's internal millisecond timer. If more than about 10 hours has elapsed since the clock was last synchronized to a server, it is resynchronized if a connection is currently available. If force is used with a non-zero value, the time is synchronized to the server as long as at least 30 seconds have elapsed since the server was last queried. This option should only be used in exceptional circumstances, or the time server pool could be overloaded with requests.

If there has never been a successful connection to a time server, a value of 0 is returned.

The internet servers used are randomly selected from a pool of many NTP servers in the UK. For more information on how this works, see http://www.pool.ntp.org. We currently use these in turn:

0.uk.pool.ntp.org

1.uk.pool.ntp.org

2.uk.pool.ntp.org

3.uk.pool.ntp.org

udp.Time(Str server)

Selects a time server. server may be an IP address in dotted-quad form, or any host or domain name that can be resolved via the connected network. After this, all udp.Time requests will use this server.

Use with RealTimeClock

If the Real Time Clock hardware option is fitted, the clock can be synchronised to GMT using this service very simply:

...

MAKE rtc RealTimeClock

MAKE udp Protocol("UDP")

...

rtc.Time := udp.Time


Queue

udp.Queue rarrow Int

Returns 1 if a listener has received a UDP packet or 0 otherwise.

Note: there is only space for one packet in the receive buffer. Any packets that are sent while there is a packet in the receive buffer are lost.

SeeAlso Empty


PRINT TO

PRINT TO udp, <print list>

The transmit buffer of a UDP object can be used as the destination of a PRINT operation.


SMTP

TCP/IP Networking

SMTP

SMTP stands for Simple Mail Transport Protocol. Its most common usage is for personal computers to send email to a server for forwarding to its final destination. Hence the Venom SMTP object is for sending email.

Summary of messages

MAKE

Debug

Put

Send


Creation

MAKE smtp Protocol("SMTP", server, id[, username, password])

server | String or text buffer containing the host name of a SMTP server which will be able to accept mail from the VM-1.
id | An optional hostname for the VM-1 itself. If supplied as an empty string, the SMTP object will send its IP address in square brackets as its id when talking to the server, in compliance with the SMTP standard. The ID string must be present even if only as an empty string.
username | Username for authenticating with the SMTP server, if required.
password | Password for authenticating with the SMTP server, if required.

This creates an SMTP object that can then be used for sending email messages.

Authentication

Most SMTP servers do not require authentication if they belong to the same ISP that provides your internet connection; however if you are using a different mail server you may still be allowed to use it as long as you identify yourself as a permitted user. There are several authentication mechanisms: the VM-1's SMTP object only supports the mechanism known as "AUTH PLAIN".


Debug

smtp.Debug larrow Int

The default value is 0.

Setting a value of 1 will echo the exchange of commands and responses with the SMTP server to serial port 1, useful for confirming that the object has been correctly set up for the server with which it will be used.


Put

smtp.Put is a synonym for Send, retained for compatibility with legacy code.


Send

smtp.Send(Str fromaddr, Str toaddr, Str subject,
 Var headers,  Var body)  rarrow  Int

Sends an email message.
Returns result value as follows:

0 - sent OK
1 - unable to connect to server
2 - Error in server commands
3 - Error sending headers
4 - Error sending content

fromaddr | fixed string or text buffer | originator's email address.
toaddr | fixed string or text buffer | recipient's email address.
subject | fixed string or text buffer | "Subject:" line of message
headers | fixed string, text buffer or file | optional headers, such as "Sender: ", "Reply-to: "
body | fixed string, text buffer or file | the message contents

Email addresses may be in the form of these examples:

smith@abc.com

<smith@abc.com>

John smith <smith@abc.com>

The third form is preferred, if for no other reason than scoring fewer points on SPAM filters.


Notes on TCP/IP

TCP/IP Networking

Notes on TCP/IP

Notes on TCP/IP for Venom Programmers

TCP Buffer Sizes

The size of the TCP transmit and receive buffers can have a profound effect on the data transfer speed, depending on the amount of delay in the link between the two ends. For best results the size of the buffer should exceed the capacity of the link, but there is little to be gained in making it much bigger and doing so wastes memory.

Buffer size is always a power of 2, and rounded up if any other size is specified

The minimum allowable buffer size is 1024, which results in pure stop-and-wait action i.e. after a TCP packet has been sent another will not be transmitted until the first has been acknowledged.

The default size of 2048 allows 3 packets to be sent before having to wait for an acknowledgement of the first and should give acceptable performance for many applications.

Increasing a buffer to 4096 is advisable when large volumes of data will be transferred in that direction.

The value of further increases should be determined by experiment and depends on the amount of delay in the link.

In particular, making the receive buffer more than 4096 when using the Ethernet interface might cause the ethernet chip's memory to overflow if the software cannot clear it fast enough (see below), especially if more than one connection exists simultaneously. Even if this happens, TCP has congestion control rules which keep the incidence of packet loss to a minimum.

Multitasking and Timing

Once a connection has been made and incoming packets can be expected, it is up to the Venom programmer to send object messages that result in those packets being seen and processed.

The serial ports have a buffer of 255 characters. Calls must be made sufficiently frequently to prevent the input buffer from overflowing, or packets will be lost and performance will suffer dramatically. As an example, at a connection speed of 38400 bps, the input buffer can fill up in about 64 milliseconds.

The ethernet interface can receive packets much faster than this, but has a buffer capacity of 4k which will hold 7 packets so as long as TCP's inherent flow control is operating properly this should not overflow unless several different sources are trying to send lots of data to the VM-1 at once and the TCP connections have been set up with large receive buffers.

As long as any message is sent to any Protocol object sufficiently frequently, all existing connections will be serviced properly. For example, a typical program might satisfy this requirement by polling a TCP receiver with Queue messages at sufficiently frequent intervals, or a simple TCP Get message will do the same while it is waiting for data.

In practice this is not usually a problem. A server task is listening constantly anyway, and a client task is not expecting any incoming packets unless it has sent a request and is waiting for a response. A minor exception is where you want the VM-1 to respond to a "ping" request but not to participate in any data connection; in that case an IP protocol Go message will allow that to happen.


Example Code

TCP/IP Networking

Example Code

1. Simple Ethernet LAN “ping” Test

In three lines of code this creates an ethernet and IP object and tests the existence and response time of another node in the network, using the equivalent of the well-known “ping” utility.

1. Make an Ethernet protocol object. The Ethernet interface is on our module board which defines the required values for hardware addressing in the second and third parameters. The IP address 172.16.1.150 happens to be compatible with our office network.
2. Create an IP protocol object to receive the Time message and create and receive the necessary ICMP messages.
3. Send Time message to measure the response time of another device on the LAN and print the result.

MAKE eth Protocol("eth", 1, $d, "172.16.1.150")
MAKE ip Protocol("IP")
PRINT ip.Time("172.16.1.199"), " ms response time",CR

2. Getting the VM-1 to respond to a "ping" Test

The VM-1 will send a response to any incoming ICMP packet as long as interfaces are being polled. Any message activity involving protocol objects will enable this; in addition the Go message sent to an IP object will cause the interfaces to be polled without any other side effects. The simplest way to set up a VM-1 to respond to ICMP packets on a LAN for test purposes is this:

MAKE eth Protocol("eth", 1, $d, "172.16.1.150")
MAKE ip Protocol("IP")
ip.Go

This will now respond to ICMP (ping) packets. Press Ctrl/C to return to a command prompt.

3. Pinging an Internet site through a LAN gateway

This does the same as (1) above, but defines a gateway to the internet and pings the Google search engine. It also illustrates the use of a DNS server to find the IP address of a domain.

Notes:

· The second line tells the ethernet interface to use the address 172.16.1.199 for a default gateway to all IP addresses outside the office LAN. It's the LAN address of a router connected to the internet.
· The fourth line tells the IP protocol where our name server is. The router which is our internet gateway also happens to act as a local name server, so it's the same address.
· The string “www.google.com” is recognised as not being a numeric IP address, so the IP system software will transparently make a DNS request for the address.

MAKE eth Protocol("eth", 1, $d, "172.16.1.150")
eth.Address('D', "172.16.1.199")
MAKE ip Protocol("IP")
ip.Find(0) := "172.16.1.199"
PRINT ip.Time("www.google.com"), " ms response time",CR

4. Simple Dialup Program to fetch a Web Page

This program is shown in two alternative versions: either make a dialup connection to an ISP via a modem or set up an Ethernet connection to a LAN with internet gateway. Both then fetch a test page from the Micro-Robotics web site (the test page exists and is at http://www.microrobotics.co.uk/testpage.html) and display the text from the page. You can run this if you have a either dialup account with an ISP (many can be set up for free if you use an 0845 local rate number for access) or a LAN connected to the internet.

The procedure Init creates the three objects needed, and calls a separate procedure that sets up some parameters for our dialup connection. This version is for a dialup connection.

TO init
MAKE modem asynchronousserial(38400, 2, 1)
MAKE ppp protocol ("PPP", modem)
MAKE tcp Protocol("TCP")
setdialup
END

The main program procedure opens the dialup connection, then calls the http fetch procedure, closing the dialup link when it's finished.

Note that when we make the PPP connection, we don't even need to know what our IP address is (it's the value returned by ppp.open, or 0 if it failed), nor do we concern ourselves with the address of a DNS server, though both these pieces of information have been assigned to us by the ISP and will be used internally by later code.

TO main
PRINT "TCP/IP demo",CR
if ppp.Open
[
fetchtestpage
ppp.Close
]
else
PRINT "dialup connect failed",CR
END

This is simply a list of setup commands. The first three are for the modem, the next two for authentication with the ISP, and the last is an optional setting for debugging the dialup process.

Note that this does not cause any connection to be made yet; it simply sets up some data values that will be used when ppp.Open is sent.

Change the settings in setdialup for your account and modem.

; typical ISP dialup with modem
TO setdialup
ppp.Element("MINIT1") := "AT&F0"
ppp.Element("MINIT2") := "AT&D1M0"
ppp.Element("DIAL") := "ATDT908456042086"
ppp.Element("USER") := "myusername"
ppp.Element("PASS") := "xxxxxxxxxxx"
ppp.Debug := 1 ; be verbose (this can be changed to 0)
END

This alternative version uses ethernet and will work if your LAN has a gateway to the internet. The IP addresses are only examples: yours may be different.

TO init
MAKE eth Protocol("eth", 1, $d, "172.16.1.150")

eth.address('D') := "172.16.1.199" ; gateway IP address
MAKE tcp Protocol("TCP")
MAKE ip Protocol("IP")
ip.Find(0) := "172.16.1.199" ; set DNS sever's IP address
END

TO main
PRINT "TCP/IP demo",CR
fetchtestpage
END

This procedure is a very simple implementation of the client end of the http protocol.

1. Open a TCP connection to port 80 (standard port number for http) on the web server for the Micro-Robotics web site.
2. Send two lines of text containing a valid http request, followed by an empty line.
3. Receive and display all the headers and text returned. We stop when the remote end closes the connection, indicated by a negative tcp.Queue value, or if the stipulated timeout of 10 seconds is exceeded.

Note:

· We simply put the domain name of the site in the tcp.Open message. A DNS query will be performed invisibly to look up the IP address of the site. The IP address is available to the Venom code, but rarely needed.
· we can close the sending end of the connection straight after sending the request; the receiving side of the connection remains open until closed by the remote web server.

; simple connect to MR test page
to fetchtestpage

PRINT "TCP connect to http://www.microrobotics.co.uk..."
if tcp.open("www.microrobotics.co.uk", 80)
[
print to tcp,
"GET http://www.microrobotics.co.uk/testpage.html HTTP/1.1",
CR, "host: www.microrobotics.co.uk", CR,CR
tcp.close
tcp.timeout := 10000
while tcp.queue >= 0
[
z := tcp.get
if (z > 0)

PRINT chr z
]
if tcp.queue = -1
print CR,"connection closed",CR
else if z = -2
print "*** timed out", CR
]
else
PRINT "FAILED",CR
end


Appendix

The appendices contain extra information that doesn't fit into the keywords and object types sections.

See the Contents tab to the left of this page for each section.


A: Startup Sequence

Appendix

A: Startup Sequence

The diagram shows what happens when Venom-SC starts.

*'Validate code in RAM' means check that the controller's heap-memory, global variables etc. contain valid data. If not, then reset them.

**All routes through the flow diagram end up at the command line, unless startup never returns – i.e. the application code loops forever. Application programs in general should never terminate to the command line.


B: Robust applications

Appendix

B: Robust applications

This appendix deals with how to create robust Venom-SC applications, i.e. those that have the least chance of going wrong and needing attention in the field.

Protecting your Application Code

While you are developing your application program, your procedures are held in battery-backed RAM. This is fine for development, but not suitable for a finished application in the field: there are many ways to lose a program from battery-backed RAM.

Finished applications should be copied into the Flash memory. Flash memory is 'non-volatile' - it keeps its contents even when not powered. Once the application is in Flash memory, and the write-enable link is removed (see the controller datasheet), then the application can't be accidentally erased.

SeeAlso See ROMing.

Protecting Against Errors

Runtime errors can stop a program from running correctly and cause it to halt forever. This is usually unacceptable for an embedded control application in the field.

To prevent errors from causing your program to halt, use CATCH to trap any errors that you know how to handle.

To deal with errors that you haven't thought about, and so don't know how to handle explicitly, use the ErrorAction system message.

System . ErrorAction := 1

This restarts the Venom application on any error not handled by CATCH.

The default startup procedure defines a 'safe' setting for ErrorAction: it is set to restart on errors if the Program Mode switch is set to 'Run'.

Serial Break

Most applications should turn off the Ctrl-C Escape function, as this could potentially halt an application. Ctrl-C Escape is treated as a runtime error, so if ErrorAction is set, the Venom application will be restarted. To turn off Ctrl-C Escape, use

Serial.Escape := FALSE

Heap size

The memory used by the system is mostly held in an area called the heap. There is also another area that is chiefly used by the RAM filing system called the non-volatile area or NV RAM. You may choose the size of this area. If you don't have a RAM filing system, or other non-volatile storage objects, then a sensible size is zero as the NV RAM subtracts from the space available to the heap. It is possible (though very unlikely) for the partition between the heap and the NV RAM to be moved accidentally. To guard against this it is wise to include a line early in your init procedure to explicitly set the NV RAM size:

Free (2) := 0 ; or what ever size you need.

It's best to use a constant value for the size: the controller has to reset itself if the partition moves. See OperatingSystem.Free for more background information.

Watchdogs

A watchdog is a hardware device that has control of the reset input to the controller. If the program does not 'kick' the watchdog every so often, then the watchdog will reset the controller. This is to halt and restart a crashed micro-controller.

In the VM-1 controller, the Venom task scheduler kicks the watchdog. This is sufficient to guard against most bugs in the Venom language, or processor crashes.

SUMMARY

· Always 'ROM' your application code with Protect
· Something like the following lines should appear near the start of any Venom-SC application released into the field. Some of these will have been taken care of by the default startup procedure – LIST startup to find out.

ErrorAction := 1 ;Restart on errors

Free (2) := 0 ;Ensure adequate heap

Serial.Escape := FALSE ;Disable Escape


C: Calling foreign code

Appendix

C: Calling foreign code

See CALL keyword.


D: Development Checklist

Appendix

D: Development Checklist

The steps involved in developing a typical Venom application are presented here. You may have completed some of these already.

1. Satisfy yourself that the controller and application board have the hardware interfaces that you require. See the datasheet for the controller. Often customers will buy the controller from Micro-Robotics Ltd, and make the application board themselves. However, Micro-Robotics can design and manufacture custom application boards.
2. Get familiar with the Venom language and basic Object Types by reading the Tutorial Guide and by trying out your ideas on your development system.
3. Use this reference manual for reference on Venom-SC keywords and object types.
4. Using development hardware, write key sections of your application to make sure that they are viable.
5. Design and build the application hardware in conjunction with the controller's datasheet and example circuits.
6. Write the complete application program.
7. Read through the Appendix on Robust Applications to make sure your application is as robust as possible.
8. Test the application hardware and software.
9. Protect your application from erasure by burning it into the Flash. See the system message Protect. You may make copies of this Flash subject to the software licence agreement detailed on our website: www.microrobotics.co.uk
10. Go into production with the application hardware and the application Flash.
11. You don't need to buy an expensive Flash programmer to make copies of your master flash device – your development kit can do this – much faster than many programmers.


E: Error messages

Appendix

E: Error messages

Here are all the error messages in the Venom-SC runtime error system.

Each error has a number and associated error text. Sometimes some extra text is added to the error text in the table to pin point the error more accurately, e.g. error 5, Un-initialised variable will usually name the variable concerned.

Runtime Error Number | Error text | Description
1 | Ram full | When there is no RAM left to perform an operation. Often caused by repeatedly MAKEing objects, or by recursion.
2 | Ctrl-C | Escape via CTRL-C. This is not really an error.
3 | Value out of range | A parameter or operand is outside a required range
4 | Type mismatch | A parameter or operand is of a type that can't be handled
5 | Un-initialised variable | Attempt to read a variable that hasn’t been given a value
6 | Division by Zero | An attempt to divide by Zero
7 | Assignment to write-protected item | Attempt to write to a write-protected global, e.g. a procedure name.
8 | Array index out of range | An index is outside limits, e.g. reading off the end of a Buffer or Array.
9 | Illegal bytecode | An illegal bytecode is seen by the BCI. Usually caused by a bug in the Venom compiler or corrupt memory. Please contact Micro-Robotics.
10 | Message sent to non-object | Attempt to send a message to a non-object, for example a.Put, where a is an integer.
11 | Parameter list applied to non-procedure | When something is called as a procedure with parameters, but isn't a procedure so can’t use parameters
12 | Device not found | Could not find the hardware needed for the operation
13 | Venom stack overflow | Used all of the Venom Stack (usually caused by recursion in your Venom program)
14 | Stack wrong at END | The BCI finds the stack is not correct. Usually caused by a bug in the Venom compiler or corrupt memory
15 | Unexpected parameter number/types/values | No Class of object accepted the parameter ranges/types supplied to a MAKE
16 | Could not exit REGION | The program wasn’t in the REGION specified so could not EXIT it
17 | Wrong no of parameters supplied | Procedure or message could not accept the number of parameters passed
18 | Message not recognised | Object didn't accept this message
19 | Attempt to lock object held by dead task | A task locked an object, then later died without unlocking it; subsequently another task tried to lock it. See here for how to block this error.
20 | Message to dead object | Sent a message to a dead object
21 | Task waiting to lock dead object | Object died while a task was waiting to lock it
22 | Internal error | Internal error in Venom compiler. Please contact Micro-Robotics.
23 | Write to read-only attribute | Tried to write to a read-only message
24 | Too many | Too many things have been created (Windows, Nudges...)
25 | Code checking error | Internal code check failed (like assertion failure in C). Please contact Micro-Robotics.
26 | File access error | File system specific
27 | Resource error | Memory or other resource ran out
28 | Script/Data error | Invalid data value or syntax error in a script
29 | Protocol error | Various TCP/IP errors typically caused by performing actions in wrong sequence
30 | [Not currently used] |
31 | Heap Error | An error was detected in the heap structure during a heap operation. This could be because of a bug in Venom-SC, or because your code accessed the heap memory accidentally (using ?, or CALL).
32 | [Unknown error] |


F: FAQ

Appendix

F: FAQ

For a discussion on Frequently asked questions, refer to our website: www.microrobotics.co.uk/sales/faq.html


G: Glossary

Appendix

G: Glossary

Active variable

An active variable is a message whose value may be read and written to. An example is Digital.Asserted.

Analogue

An analogue signal is one that can take a range of values rather than the On and Off of digital signals. The range is divided up into discrete steps. See Resolution.

Application

The application program is the your Venom code, consisting of the procedures you have written.

ASCII

ASCII stands for American Standard Code for Information Interchange, and gives a standard numbering system for the letters, numbers and symbols used in computing. For example, the ASCII code for the letter ‘A’ is 65.

BCI

Byte Code Interpreter - see interpreter.

Binary

Binary is the number base 2, where everything is expressed as Bits of either 0 or 1. Fundamentally, this is what computers work in, but it is rather unwieldy, so hexadecimal is often used instead.

Bit

A bit is a single binary digit, which can either be 0 or 1. Several bits may be combined to give a number.

Bit-wise

A calculation is performed bit-wise if the same operation is performed on every bit of a number individually. In Venom, the AND, OR, EOR and NOT operators are both bit-wise and Boolean. The values chosen for TRUE (-1) and FALSE(0) allow this.

Boolean Operator

Boolean operators are named after George Boole, who first formally investigated the operation of the ‘logical connectives’ AND, OR and NOT. Later, the operator EOR was added for mathematical completeness. Unlike AND, OR and NOT, EOR isn’t used in normal speech. A.A. Milne is the only writer ever to have used EOR successfully in an English sentence.

Byte

A group of 8 bits, which can represent from 0 to 255. This is the standard unit of memory for computer systems, chosen because it was enough to store an ASCII code. In hexadecimal, each hexadecimal digit represents half a byte, or one nybble.

Bytecode

A Bytecode is an instruction that the Venom Virtual Machine understands. They are like virtual machine code. The Venom-SC Compiler turns your Venom code into bytecodes. The Java language also uses bytecodes as it makes it easy to port to different platforms.

Call

When a procedure is executed, either by including its name in the program, or by typing its name in at the command line, this is referred to as a procedure call. CALL is also a keyword in Venom, used to call code in Assembler, C or other languages.

Channel

A channel is a signal used for input and output. It has been given a reference number as a convenience in Venom. The controller datasheet shows you which channels are available where.

Code

A piece of Code is a program or section of a program.

Command Line

The command line is the part of the Venom system that sends the --> prompt to the host computer and then accepts characters typed in by the user.

Digital

A digital signal is one that can either be On or Off. The voltage levels equivalent to On and Off depend on the hardware concerned. This variation also applies to the polarity: Off is often the higher voltage!

Dot Chaining

Dot chaining is a shortcut that allows you to send a message to the result of a previous message. Obviously this result must be an object, and this result should not take any memory. An example is net.On.Put(n).Put(m).Off

Expression

An expression is a piece of program that performs a calculation. Each expression has a value: the result of the calculation. The smallest expression is just a value by itself.

Firmware

Firmware is software that is permanently stored in the computer by being placed in a non-volatile memory (e.g. Flash).

Flag

A Flag is a name for an integer chosen to only represent TRUE or FALSE. The name is believed to come from railway signalling. In Venom, TRUE is represented as -1, and FALSE is 0. The reason for this is that –1 in binary is ‘all 1s’, so the AND, OR, EOR and NOT work properly both as bit-wise operators and Boolean operators.

Flash

This is a ‘writable’ ROM. A flash device on the controller holds the Venom-SC Language, and also your application code when you ‘Protect’ it. To make the Flash secure from accidental erasure, a ‘Write Protection’ link is fitted to the controller. Remove this to prevent overwrites or erasure.

Float

A float is a floating-point number, which allows decimal fractions to be represented as well as whole numbers. Floats in Venom are IEEE single precision.

Fragmentation

Fragmentation occurs if the memory blocks used by the application are taken and returned out of order. As this continues, instead of there being one large area of free memory, there are many small areas, punctuated by memory blocks that are still being used. Only programs that do a lot of complex, dynamic creation and destruction of objects are likely to find this a problem.

Function

A function is a name for a procedure that returns a result. By definition, a pure function is one that only returns a result, and does not have any side effect on any other part of the system.

Global variable

A global variable is a variable that is accessible throughout the program. Global variables are created just by assigning a value to a name: var := 1.0

Hardware

Hardware is the physical electronics that makes up the computer and the devices that are connected to it.

Heap

The heap is an area in the controller's RAM that is reserved for use by your application and also the Venom system in ways that can't be predicted ahead of time.

Hexadecimal

Hexadecimal is the number base 16, which is used as a shorthand way of writing binary. The numbers 10-15 are represented by the letters A-F. Each hexadecimal digit represents 4 binary bits. Hexadecimal is usually used when talking to the computer’s hardware directly, since hardware is usually laid out in round numbers in binary.

Host

The host is the computer (usually a PC) that runs a terminal emulation program so that the user can communicate with the controller.

Instance

When many objects of a single type are created, each of these objects is referred to as an instance of the object type. When a procedure is called more than once at the same time by itself, or by different tasks, each call is referred to as an instance of that procedure.

Int

An Int is an integer: i.e. a whole number. Integers in Venom are stored in 32 bits, representing roughly ±2 billion.

Interpreter

The Interpreter is a machine code program that reads and executes bytecodes. The Venom-SC compiler turns your Venom code into bytecodes. The Venom-SC interpreter is sometimes called the Venom Virtual Machine. VM-1 stands for Venom Machine 1.

K, Kilobyte

A kilobyte is 1024 bytes. The unusual number is chosen because it is a nice round number in binary.

Keyword

A keyword is a fixed element of the syntax of the language, such as REPEAT, Value and Digital. You cannot give procedures and variables the same names as any keyword.

Local variable

A local variable is a variable that is only accessible within a certain instance of a procedure. They will ‘eclipse’ any global variable of the same name for the duration of the procedure. Local variables are created with the LOCAL statement.

Locking

Locking is a way of ensuring that only one task has access to a particular object at any time, to prevent transactions from two different tasks becoming confused.

Machine Code

Machine code is the set of instructions that the microcontroller obeys. Programs written in machine code run faster than those written in the Venom.

Message

A message is something that is sent to an object, consisting of a message name, such as On, Value, DefaultOutput etc., and some parameters. Each object type may respond to each message in a different way.

Object

An object is an element of the system, containing both code and data, that is used to interface to the outside world, store data, etc. All objects have a type, which defines how they act in response to messages. There can be more than one instance of some types, and these act independently as they hold different data.

Operand

An operand is a value acted on by an operator. In the expression ‘a + b’, a and b are operands.

Operator

An operator is a language symbol or keyword that acts one or two operands to produce a result. Each operator has a precedence that governs the order in which operations are evaluated.

Parameter

A parameter is a value that is passed to a procedure or message. This value is operated on by the procedure or message.

Pixel

A pixel is the smallest element of a display screen that can be individually controlled. The greater the number of pixels, the higher the resolution of the screen, and the better quality of the image.

Pointer

A pointer is a value that holds a reference to the position of some data, rather than the data itself.

Postfix operator

A postfix operator is an operator that comes after the value it modifies. Examples include AS INT and AS FLOAT.

Precedence

Precedence sets the order operators will be executed in a complex expression. The higher the priority, the earlier it is executed. See the appendices.

Prefix operator

A prefix operator is an operator that comes before the value it modifies. Examples include ! and NOT.

Procedure

A procedure is a set of commands lumped together as one unit. See the TO keyword. A procedure can take parameters, and return a result.

RAM

RAM stands for Random Access Memory, but the name is a relic. In fact it means that the memory is writable as well as readable.

Recursion

This is where a procedure calls itself, either directly or indirectly. This can be very useful for solving some kinds of problems, but is often done unintentionally. In the unintentional cases it usually leads to a RAM Full error as all the stack is used up.

Resolution

The resolution of a device is the smallest change detectable, or controllable, by it. When used with analogue I/O, resolution refers to the size of the smallest voltage step between possible input readings or output levels.

The resolution of a display screen is the number of pixels it has - this governs the quality of the image. The lower the resolution, the more grainy the image becomes.

The resolution of a timing operation (such as PulseWidthOut) is the smallest interval in time that the timing can change by.

ROM

ROM stands for Read-Only Memory. Usually these days, ROMs are mostly Flash memories. Flashes are writable – though there are safeguards to stop this occurring accidentally.

Routine

Routine is another word for procedure or function.

Software

Software is the program that the hardware executes. If software is contained in a ROM, it is called firmware.

Statement

A statement is a complete piece of program that performs some action.

String

A string constant is a series of characters, enclosed by quotes, such as “A string”. You can use String objects and text Buffers for variable text.

Syntax

Syntax is the structure of the language: how the elements of the language fit together.

Task

A task is part of a program that runs as though it were executed by an independent processor with access to the same memory. In fact, the one processor is shared between all tasks.

Tri-state

A tri-state output is a digital output which, as well as being on or off, can go into a high-impedance state where it doesn’t drive either way.

Type

All objects are of one type or other. The type determines what messages the object understands, and what action it takes on receipt of each message. Examples of objects types are Buffer, PulseWidthOut etc.

Type is also used to refer to what sort of value something is, for example Int, Float, String.

Variable

A variable is a place to store a value. See also Global variable and Local variable.


H: Number Limits

Appendix

H: Number Limits

Integers are signed 32-bit quantities:

Maximum | Minimum
2,147,483,647 | -2,147,483,648
$7FFFFFFF | $80000000

Floats are standard IEEE single precision: 1 sign bit, 8 exponent bits and 23 mantissa bits.

Maximum | Least non-zero | Precision
±3.39E+38 | ±1.18E-38 | ~7 decimal digits


I: Operator Precedence

Appendix

I: Operator Precedence

The following table shows the order of precedence of the operators in Venom-SC. The operators at the top of the table are more tightly binding than those at the bottom.

Those on the same line have the same precedence.

Operators with the same precedence level are evaluated from left to right in an expression, apart from prefix operators, which are evaluated from right to left.

Parentheses | ( )
Postfix | • AS INT AS FLOAT (parameter list)
Prefix | - ABS NOT TYPEOF ? ?? ???? ! SIN COS TAN ASIN ACOS ATAN SQRT EXP LOG
Multiplicative | * / ^ DIV MOD
Additive | + -
Comparative | > < >= <= = <>
Logical | AND OR EOR

The following examples show some cases where precedence is important, and how they are resolved by Venom:

Expression | Is interpreted as if it were written as... | To get the other interpretation, use...
2+3*4 | 2+(3*4) | (2+3)*4
x AND 1 = 1 | x AND (1 = 1) | (x AND 1) = 1
2.1 * x AS INT | 2.1 * (x AS INT) | (2.1 * x) AS INT
! object .Value | ! (object . Value) | (! object) . Value
!proc_ptr(a,b) | ! (proc_ptr (a,b) ) | (!proc_ptr)(a,b)

If you start a statement with ‘(‘ then you should enclose the statement in square brackets so that the Venom parser (which doesn’t have statement separators to tell it where a statement ends) can parse it correctly. Otherwise it may interpret ‘(‘ as the beginning of a parameter list.

So

(!proc_ptr)(a,b)

should be written

[(!proc_ptr)(a,b)]


J: Speed of Execution

Appendix

J: Speed of Execution

Venom-SC is a semi-compiled language, like Java. This means it compiles your code to a set of bytecodes. These codes are then interpreted by the Venom runtime system to run your application. Semi-compiled code runs faster than interpreted code, but not so fast as native machine code. Typically, a single bytecode will execute in 7µS to 15µS on the VM-1. A bit of code like a := a + 1 will take ~50µS.

Measuring Execution Times

The following code allows you to measure the execution time of bit of Venom code.

TO measure_time(n,c)

LOCAL t

AUTODESTRUCT

LOCAL stop_watch := NEW StopWatch

stop_watch.Reset

REPEAT n

[

;commands to be timed

]

t := stop_watch.Time AS FLOAT

PRINT (t / n - c):10:4, " milliseconds", CR

END

The parameter n is the number of times the loop is repeated - increasing it increases the accuracy of the result. The parameter c is a constant adjustment that is used to take into account the time taken to execute the REPEAT command.

Firstly, the procedure should be run with n = 1000; c = 0 and the REPEAT command empty. This will then print the value to use for c.

Then put the code under test into the REPEAT, choose a value of n, and use the value of c you just found.


K: Optimisation

Appendix

K: Optimisation

Optimisation is the automatic or manual alteration of code to make it run faster, occupy less space, or use less electrical power.

Code Optimisation

The Venom compiler automatically performs some optimisations on the Venom code you write.

Because Venom-SC is semi-compiled, the size of the code it produces is typically much smaller than either assembly code or fully compiled code.

Venom also does some more explicit optimisation. Currently this is limited to constant folding. Constant folding is where an operation on one or more constants may be calculated at compile time rather than at run time. For example, the first line could be written as the second, but the first line may be more understandable and maintainable.

a := 5 * 4

a := 20

When Venom compiles these lines of code, it is able to notice the possible optimisation, and compiles as if the second line had been written.

Constant folding is performed on most operations. In order to ensure folding happens, enclose the operations in parentheses:

5 * a * 4 ;will not be folded (the compiler's not that clever!)

5 * 4 * a ;might be… (implementation dependent)

a * 5 * 4 ;might be… (implementation dependent)

a * (5 * 4) ;definitely will be.

Here is the current list of the operations that may be optimised by constant folding. Other operations will be calculated each time.

+ - * ^ / DIV AND OR EOR MOD

NOT - (Unary minus or negative)

TYPEOF (for Integer, Float, and String constants; & NIL)

Power saving

The Venom operating system automatically uses the SLEEP instruction on the host processor. The controller is put into a power-saving mode if there are no tasks requiring any processing power. Interrupts are not affected as they automatically wake the controller from its SLEEP instruction.

In order to make best use of this, make your tasks wait if they can do so without compromising the responsiveness of your code.

For example you could wait for a digital input like this:

WHILE dig.NotAsserted []

However if you don't mind being up to NmS late in the detection of the input you can save power by using something like

WHILE dig.NotAsserted [WAIT N]

The WAIT command will let the controller idle while it's waiting.

AWAIT will also allow the controller to sleep while it's waiting, with a minimal loss of responsiveness

AWAIT dig.Asserted

All commands and messages in Venom that are waiting for an interrupt or for a millisecond time of any sort will allow the controller to idle. Other things will also allow idling.

Examples are WAIT, EVERY, SWAP, serial.Get, keypad.Get, any_object.Lock…

You can check the effect of running various bits of code if you have a power supply with a current meter on it.


L: ASCII Character Set

Appendix

L: ASCII Character Set

The following table shows all of the characters in the ASCII character set, giving the decimal character number, the hexadecimal character number and the character itself. In the case of unprintable characters, either a description is given, or the box is left blank.

Dec | Hex | Char | Dec | Hex | Char | Dec | Hex | Char | Dec | Hex | Char
0 | 0 | NUL | 32 | 20 | SPC | 64 | 40 | @ | 96 | 60 | `
1 | 1 |  | 33 | 21 | ! | 65 | 41 | A | 97 | 61 | a
2 | 2 |  | 34 | 22 | " | 66 | 42 | B | 98 | 62 | b
3 | 3 | BRK | 35 | 23 | £ | 67 | 43 | C | 99 | 63 | c
4 | 4 |  | 36 | 24 | $ | 68 | 44 | D | 100 | 64 | d
5 | 5 |  | 37 | 25 | % | 69 | 45 | E | 101 | 65 | e
6 | 6 |  | 38 | 26 | & | 70 | 46 | F | 102 | 66 | f
7 | 7 | BEEP | 39 | 27 | ' | 71 | 47 | G | 103 | 67 | g
8 | 8 | BS | 40 | 28 | ( | 72 | 48 | H | 104 | 68 | h
9 | 9 |  | 41 | 29 | ) | 73 | 49 | I | 105 | 69 | i
10 | A | LF | 42 | 2A | * | 74 | 4A | J | 106 | 6A | j
11 | B |  | 43 | 2B | + | 75 | 4B | K | 107 | 6B | k
12 | C | FF | 44 | 2C | , | 76 | 4C | L | 108 | 6C | l
13 | D | CR | 45 | 2D | - | 77 | 4D | M | 109 | 6D | m
14 | E |  | 46 | 2E | . | 78 | 4E | N | 110 | 6E | n
15 | F |  | 47 | 2F | / | 79 | 4F | O | 111 | 6F | o
16 | 10 |  | 48 | 30 | 0 | 80 | 50 | P | 112 | 70 | p
17 | 11 | XON | 49 | 31 | 1 | 81 | 51 | Q | 113 | 71 | q
18 | 12 |  | 50 | 32 | 2 | 82 | 52 | R | 114 | 72 | r
19 | 13 | XOFF | 51 | 33 | 3 | 83 | 53 | S | 115 | 73 | s
20 | 14 |  | 52 | 34 | 4 | 84 | 54 | T | 116 | 74 | t
21 | 15 |  | 53 | 35 | 5 | 85 | 55 | U | 117 | 75 | u
22 | 16 |  | 54 | 36 | 6 | 86 | 56 | V | 118 | 76 | v
23 | 17 |  | 55 | 37 | 7 | 87 | 57 | W | 119 | 77 | w
24 | 18 |  | 56 | 38 | 8 | 88 | 58 | X | 120 | 78 | x
25 | 19 |  | 57 | 39 | 9 | 89 | 59 | Y | 121 | 79 | y
26 | 1A |  | 58 | 3A | : | 90 | 5A | Z | 122 | 7A | z
27 | 1B |  | 59 | 3B | ; | 91 | 5B | [ | 123 | 7B | {
28 | 1C |  | 60 | 3C | < | 92 | 5C | \ | 124 | 7C | |
29 | 1D |  | 61 | 3D | = | 93 | 5D | ] | 125 | 7D | }
30 | 1E |  | 62 | 3E | > | 94 | 5E | ^ | 126 | 7E | ~
31 | 1F |  | 63 | 3F | ? | 95 | 5F | _ | 127 | 7F | DEL


M: Extended characters

Appendix

M: Extended characters

[Not available yet]


N: 'ROMing'

Appendix

N: 'ROMing'

This section describes the process of 'ROMing' - or protecting your application code in flash memory.

During development, your application code is stored the battery-backed RAM. This is fine for testing during development, but is not suitable for a finished application in the field. For this we strongly recommend that you protect your application against accidental deletion by copying it into flash memory. This is done using the Protect message.

There are two hardware variants of the VM-1 in respect of flash application space: the original VM-1 and the newer VM-1e.

VM-1

In the original VM-1 your application code is combined with the operating system - in the same flash device - when you call Protect. Once you have done this, and set the VM-1 switch to RunMode, it will always run the application code in the flash whenever it is powered up.

This flash device may be copied as many times as you like, and the resulting copies installed in VM-1s. See Copy.

In this way you can either equip your new production run with the correct operating system and application codes, or send out the flash copies to be installed in your units in the field to upgrade their software.

VM-1e

The VM-1e is intended for applications which are too large to fit in the application space allowed for in the operating system flash (currently 192K).

It has an extra, on-board, flash (512K) purely for storing application code. The operating system flash (the one in the socket) holds the operating system only. This means that operating system and application code updates in VM-1e are separate operations.

To transfer your application code from RAM to the on-board flash, use Protect (just as in VM-1). The VM-1e will then run the application from the on-board flash every time it is powered up in RunMode.

To distribute your application code, you need to produce a distribution flash. A distribution flash holds both a copy of your application code (taken from the on-board flash), and a small boot loader program. The boot loader copies the application code it into the on-board flash of any VM-1e it is plugged into.

To make a distribution flash take an Application Board 2 (Product Code 5805, supplied free with the Starter Kit) and plug in your VM-1e, and also plug a new flash into the flash programming socket. Use Copy to create the distribution flash.

Once you have created the distribution flash, it may be used to update the application in any number of VM-1e. See the procedure below:

VM-1e application code update

· Power down the VM-1
· Remove the operating system flash and put it in a safe place
· Insert the distribution flash
· Power up the VM-1. The LED will flash briefly three times separated by several seconds (for each of the three phases of the copy operation). When the copy is complete the LED will flash continuously. If you have a terminal attached to serial port 1 then you will see the following report at the baud rate set by the baud switch:

App Loader 2006 03 16

Erasing...||||||||Copying...Verifying...Done

· If the operation fails then the LED is lit continuously and the report will confirm the failure. If the loader didn't detect a writable flash memory then it will ask if LK3 has been linked.
· Power down the VM-1, remove the distribution flash and re-insert the original operating system flash
· Check the application performs as expected.

Operating system update

This simply involves taking out the old operating system flash and replacing it with a new flash with the new operating system code in it.

See Copy for one way to create a new operating system flash by downloading an image file from our website.

Application and operating system compatibility

If the application code is compiled using an operating system that is sufficiently different from the operating systems that are in the VM-1e that are to be updated, then it is sometimes possible that the application code and operating systems will not be compatible. For example the application code may use a feature that doesn't exist in an older operating system version.

To guard against this it is recommended that you either make sure you compile any updated application code using the same version of the operating system that resides in all your VM-1e in the field, or that you distribute copies of the new operating system along side the new application code.


O: Non-Volatile RAM

Appendix

O: Non-Volatile RAM

This page explains how non-volatile RAM works in the VM-1.

All the RAM in the VM-1 is backed up by the battery, so it's contents remain over power cycles. However, even though the whole of the RAM contents are retained while power is off, much of it is discarded and has to be rebuilt each time the controller starts up. Most of this rebuilding is done in your init procedure using your MAKE commands.

The only things that are actually retained in RAM over power cycles are:

· Your application code - but only during code development.
· Data from objects that use the 'NV RAM' area.

Procedures

While you are developing your Venom application, all your compiled code is retained in RAM - even over power cycles - as this makes it easy to both emulate the power-on behaviour of the controller, as well as to easily edit the code.

When you have completed development, your code is transferred to flash for safekeeping. When there is an application in flash, the controller makes sure it erases any code it finds in RAM on startup - to make sure the startup sequence is completely predictable.

NV RAM

The NV RAM area is a portion of the controller's RAM you can set aside for storing data you want to retain over power cycles. The only things that use this area currently are the RAM filing system and non-volatile Arrays.

You can choose how big this area is, up to a maximum that uses almost all the RAM. However, memory you reserve in the NV RAM area is not available for use by the system for compiling code or holding compiled procedures and objects, etc.

Memory within the NV RAM area is allocated on a 'first come, first serve' basis each time the controller starts up. To use it correctly, each object that uses some NV RAM must ask for it's allocation only once, with the same size, and in the same order, after startup. This ensures each object gets exactly the same block of memory each time, with its own data in it. The best way to do this is to put all the relevant code in your init procedure, for example:

TO init

Free(2) := 50 * 1024 + 1000; enough NV-RAM for File system and NV Arrays

MAKE fs FileSystem("RAM", 50*1024)

MAKE nv_array1 Array(8, 100, NIL)

MAKE nv_array2 Array(16, 200, NIL)

MAKE nv_array3 Array(1.0, 50, NIL)

… ;other init code

END


Credits

Venom-SC was written by the following people:

Compiler | Karl Lam
Runtime system | Karl Lam
Operating System | Karl Lam
TCP/IP stack | Anahata
Filing system | Anahata
Other objects | Karl Lam, Anahata, Della Burke

The Venom-SC Help File was created by Karl Lam with additions from Anahata.