HL-SYS-003: Haunted Lantern Scripting Language
Haunted Lantern System Document 003:
The Haunted Lantern Scripting Language
1
HL-SYS-003: Haunted Lantern Scripting Language
Revision History:
Date
20150627
Revision
0.1
Author
Henk Kok
Comment
Initial revision
References:
ID
HL-SYS-001
Version
0.1
Title
Haunted Lantern Infrared Commands
2
HL-SYS-003: Haunted Lantern Scripting Language
Table of contents
1
Introduction.................................................................................................................... 4
2
Scripting basics ............................................................................................................... 5
2.1
3
4
Your first script ...................................................................................................................5
Script structure ............................................................................................................... 7
3.1
Preprocessor .......................................................................................................................7
3.2
Types ..................................................................................................................................8
3.3
Variables .............................................................................................................................8
3.4
Functions ............................................................................................................................8
3.5
Statements .........................................................................................................................9
Haunted Lantern library ................................................................................................ 14
4.1
Threading.......................................................................................................................... 14
4.2
Functions .......................................................................................................................... 14
4.3
Macros.............................................................................................................................. 19
3
HL-SYS-003: Haunted Lantern Scripting Language
1
Introduction
This document describes the Haunted Scripting Language (HSL). With this language it is possible to
create complex sequences of effects. The scripts can be used in combination with either a Haunted
Transmitter SC, or with a windows application combined with a Beacon of Death.
You do not need special skills to learn the basics of the Haunted Scripting Language. By just reading the
examples and having knowledge of the Haunted Lantern Infrared Protocol (see [HL-SYS-001]) will teach
you enough to create straight forward scripts. For more complex topics such as events and
multithreading it helps if one has some knowledge of programming.
4
HL-SYS-003: Haunted Lantern Scripting Language
2
Scripting basics
2.1
Your first script
In this section we are going to write a simple script and compile it.
2.1.1 Getting started
Scripts are written in an editor. We advise to take notepad++ which is free to download and use. When
you enable the C language decorations (menu item Language/C/C), the script becomes even more
readable. Note that HSL has many similarities with the C programming language; it even uses the C
preprocessor.
2.1.2 Writing your first script
Open the text editor, type the following and save the file as ‘example1.hsl’
#include "hsl.hsh"
#define TRANSMITTER "HT.SC.0001"
void main()
{
while (true)
{
seq_start();
seq_fade_rgbw(15,0,0,0);
seq_send(TRANSMITTER);
delay(2000);
seq_start();
seq_fade_rgbw(0,15,0,0);
seq_send(TRANSMITTER);
delay(2000);
}
}
2.1.3 Understanding the script
The script starts with the #include "hsl.hsh". Every script should start with this. It adds the file hsl.hsh to
the script which contains important definitions.
The next statement we see is a definition for TRANSMITTER. With this statement we accomplish that
every time the script mentions TRANSMITTER, it will be substituted for “HT.SC.0001”. This is convenient,
because if we want to run it on another transmitter, we have now only one location where we need to
change the name.
“void main()” is the declaration of the main function. This is the function that the script will execute
when it is started. Void means that it does not return a value.
The “while (true)” statement makes sure that we will always repeat the statements that follow. These
statements keep toggling the color between red and green. A new sequence is started, the command to
change the color is added, and the sequence is sent to the transmitter. The script than waits for 2
5
HL-SYS-003: Haunted Lantern Scripting Language
seconds, does exactly the same thing but then with a different color. After the last statement the
execution will jump back to the first statement after the while, and thus keep repeating the color
change.
2.1.4 Compiling your first script
[[NB: this section is subject to modification as we will encapsulate the command line tools with a GUI]]
To compile the script, you have to do the following steps:
Open a DOS command window
Use the cd command to get into the directory where the script resides
Run the compiler. The installer does not add a path to the binary directory, so you have to
supply the full path of the compiler. In this case, that is ‘..\..\hsc.exe’. The compiler takes two
command line arguments: the input file and the output file.
Figure 1: Compiling a script
2.1.5 Running the script
The compiled script has resulted in an object file, which can be run. This can be either done on a
Haunted Controller (stand-alone or the Haunted Transmitter SC integrated controller, see [HL-SYS-004]
for details) or through the Haunted Script Interpreter using the Beacon of Death (see [HL-SYS-006]).
6
HL-SYS-003: Haunted Lantern Scripting Language
3
Script structure
This section explains the basic structure of HSL. Although this chapter is six pages with a high density of
information, it does not even begin to explain all the things you can do with HSL. This gap is partially
filled by the examples, and the rest is learned by writing your own scripts.
3.1
Preprocessor
As HSL uses the C preprocessor, all the features from the HSL preprocessor are available.
3.1.1 Comments
Any text block that is encapsulated by /* and */ is considered comment and is not compiled. The same
applies for any text between // and the end of the line.
/*
* this is a longer comment block
*
* It is spread over multiple lines
*/
// this is a short comment that is on only a single line...
3.1.2 Defines
Defines are useful for many things, but for the purpose of keeping it simple we’ll discuss only two
important uses.
The first use is to keep your script maintainable. What if you write a script for one transmitter and then
want to run it on another. Sure, a global substitute will work, but the define of the transmitter and using
the define in all locations is a much more maintainable solution. See in this excerpt from the script of the
previous chapter.
#define TRANSMITTER "HT.SC.0001"
…
seq_send(TRANSMITTER);
…
seq_send(TRANSMITTER);
Defines can also be used for giving meaning to the text. For instance, creating a message of type 5 is
rather meaningless. But when you create the following define:
#define HL_MT_FADE
5
… and use the define HL_MT_FADE when creating that message, the code becomes much easier to
comprehend.
It is also possible to pass parameters to a definition. In fact the general include file of HSL contains quite
a few examples of this.
#define seq_fade(target, speed)
add_sequence_cmd(HL_MT_FADE, 15, target, speed)
Defines are also referred to as macros, especially when they have parameters.
7
HL-SYS-003: Haunted Lantern Scripting Language
3.1.3 Including files
Common definitions that are used in multiple scripts can be placed in a separate file, which is then
included. It is then just as if the contents of the file was where the include statement was.
#include "hsl.hsh"
The extension ‘hsh’ stands for Haunted Script Headerfile.
3.2
Types
The scripting language knows three types of values:
Integers, which are numbers without a decimal point, e.g. 10, 0, -3, 102382, etc.
Strings, which are a sequence of characters, e.g. “HT.SC.0001”, “main_theme.mp3”, etc. When
writing down a constant string in HSL, it is always encapsulated by double quotes.
Booleans, which are either true or false.
HSL is a strictly typed language, which means that when a value of a certain type is expected, it will be
an error if you pass a value of another type.
It is possible to cast the value from one type to the other. The following conversions are possible:
Int to string, e.g. (string) 3 will result in string “3”.
String to int, e.g. (int) “3” will result in the integer 3.
Boolean to string, e.g. (string) true will result in the Boolean true
3.3
Variables
At every location where you must specify a value of a certain type, you can also specify a variable of that
same type. A variable is a named reference to a value. You can both assign a value to a variable as well
as reference it to retrieve the value.
Before you can use a variable, it needs to be declared so the compiler knows it exists and what type it
has. Declaring a variable is done by specifying its type and name, as follows:
int
delayTime;
string transmitterName;
boolean isStopping;
Working with variables is explained in section 3.5.
3.4
Functions
A function consists of a function header and a function body. The function header tells us what we can
expect of the function. It consists of a return type, a name, and a parameter list:
void start_stroboscope(int r, int g, int b, int w)
This specific function does not return a value (because it is void) and it takes four parameters, named r,
g, b and w. Inside the function, these parameters act as variables. You can assign new values to them, or
access the values in the variables. The body of the function could look like this:
8
HL-SYS-003: Haunted Lantern Scripting Language
{
seq_start();
seq_set_rgbw(r, g, b, w);
seq_stroboscope(20, 3);
seq_end(TRANSMITTER);
}
The body of a function starts with an opening accolade, followed by a list of statements and then a
closing accolade.
If you need a variable inside a function but it is no parameter, then you can also declare it right after the
opening accolade, creating a variable that is only visible inside the function:
void start_stroboscope(int r, int g, int b, int w)
{
int period;
int flashLength;
period
= 20;
flashLength = 3;
seq_start();
seq_set_rgbw(r, g, b, w);
seq_stroboscope(period, flashlength);
seq_end(TRANSMITTER);
}
3.5
Statements
The statements determine the behavior of the script. There are several types of statements.
3.5.1 Assignment
An assignment statement assigns the value of an expression to a variable. An expression can take many
forms, from a simple constant or variable reference, to a complex calculation with many operations.
Note that the type of the expression must match with the variable to which it is assigned. An assignment
statement always ends with a semicolon.
period = 20;
beat2 = period/4;
total_seconds = ((((days*24)+hours)*60+minutes)*60)+seconds;
lantern++;
/* increments the value of lantern with 1 */
intensity += 5; /* adds 5 to the value of intensity */
3.5.2 Function call
A function call statement makes the scripting engine execute the function, and once completed it will
continue with the statement following the function call. If the function requires parameters, these need
to be supplied and they need to be of the right type.
Functions can also have a return value. If so, the function call is seen as an expression of the return type
of the function in for instance an assignment statement. A function call statement also always ends with
a semicolon.
9
HL-SYS-003: Haunted Lantern Scripting Language
start_stroboscope(0,15,0,0);
intensity = random_intensity();
/*
/*
*
*
start a green stroboscope */
assign the return value from
random_intensity() to the variable
intensity. */
3.5.3 If statement
The if statement starts with the keyword if, followed by an expression in parenthesis and a statement.
The expression (see section Error! Reference source not found.) must be of boolean type. Boolean type
xpressions can have the following form:
The keywords true and false
A variable which has the boolean type.
A comparison. Integer expressions can be compared with the equals operator ==, but also with
<, >, <= and >=. Strings and booleans can only be compared with the equals operator.
The inverse of a Boolean expression, written as: !expression
An operation on two Boolean expressions: && or ||. A &&B is true when both A and B are true,
A||Bis true if at least one of A or B is true.
if
if
if
if
if
if
if
(true) …
(ready) …
(!ready) …
(lantern == 12) …
(lantern < 6) …
(transmitter == “HT.SC.0001”)
((lantern >=3) && (lantern <6)) …
Optionally, the if statement can be followed by the else keyword, with yet another statement. For
instance:
void rotate_colors()
{
sRotateCount++;
if (sRotateCount >= 3)
{
sRotateCount = 0;
}
if (sRotateCount == 0)
{
…
}
else if (sRotateCount == 1)
{
…
}
else
{
…
}
}
Note that here the statement following the parenthesized expression and the else is encapsulated in
accolades. This is called a compound statement. Everywhere a statement is expected, a compound
10
HL-SYS-003: Haunted Lantern Scripting Language
statement may be found. A compound statement consists of an opening accolade, a list of (zero or
more) statements and a closing accolade.
When an if statement is executed, it tests whether an expression is true or false. If it is true, it will
execute the statement following the if statement. If there is an else part, the statement followed by the
else will be executed if the expression tested to be false.
In the example, the sRotateCount will be incremented every time the function is executed. Once it hits
3, it will be set back to 0, so it will always be 0, 1 or 2.
Next, we have three different execution paths for each value of sRotateCount. Note that the statement
following the else of if (sRotateCount == 0) is yet another if statement.
3.5.4 While statement
The while statement is a means of continuing to execute the same code for as long as a condition is true.
The while statement consists of the keyword while, followed by a parenthesized expression and a
statement.
while (!connected(TRANSMITTER))
{
delay(1000);
}
This will test whether the TRANSMITTER has connected. When this is not the case, the statement in the
compound statement will be executed: delay(1000). The test will then be performed again and if still not
connected, the delay will also be executed again. This keeps repeating until it is found that the
transmitter has connected.
3.5.5 For statement
The for statement allows the script to repeat a section of the script a defined number of times. The
syntax consists of the keyword for, and between parenthesis, separated by semicolons respectively the
initial statement, the conditional and the iteration statement. Before the for is started the initial
statement is executed. Then the conditional is checked and if found true, then the statement following
the for statement is executed. When that is done, the iteration statement is executed. Then the
conditional is checked again and the actions are repeated for as long as the conditional statement
returns true. The following piece of scripting will first turn on the lantern with ID 0, half a second later
the one with ID1, etc. up to 12.
int lantern;
for (lantern=0; lantern<=12; lantern++)
{
seq_start();
seq_conditional_expression(HL_COND_EXP_ID_0, 0, lantern);
seq_fade(255, 100);
seq_send(TRANSMITTER);
delay(500);
}
3.5.6 Return statement
Functions that have a return type must return a value upon exiting the function. The return statement is
used for that. The return statement can also be used to exit a function before the execution has reached
11
HL-SYS-003: Haunted Lantern Scripting Language
the end of the function. Although this is possible, this is generally considered bad practice because it
makes the flow of the function difficult to understand.
12
HL-SYS-003: Haunted Lantern Scripting Language
int random_intensity()
{
return random(100, 200);
}
void start_stroboscope(string transmitter, int r, int g, int b, int w)
{
if (transmitter != "HT.SC.0001")
{
return; /* bad practise! */
}
seq_start();
seq_set_rgbw(r, g, b, w);
seq_stroboscope(20, 3);
seq_end(TRANSMITTER);
}
13
HL-SYS-003: Haunted Lantern Scripting Language
4
Haunted Lantern library
The previous chapter explained the structure of the scripts and the correct syntax. This chapter focusses
on the semantics. This chapter explains what functions exist that we can use to e.g. manipulate the
lanterns.
4.1
Threading
Up to now we have only discussed a single thread of execution. It is possible to have more than one.
When you spawn a new thread, the new thread will start in the function you specified as entry point,
and the current thread also continues. It is possible to create as many threads as you like, although each
thread adds to the overall system load and for that reason it may be wise to not use too many. Having
multiple threads running at the same time that make use of the same variables create concurrency
issues. Suppose one thread assigns a value to a variable while the other reads it. If we have no control
over the order of execution between the two threads, the variable can be read either before or after it
was assigned in the other thread.
Runtime libraries usually offer tools to deal with concurrency issues with mutexes and semaphores.
These primitives do not exist in HSL. Instead, the event mechanism can be used to circumvent these
problems. Check the scripting examples on how this is done.
4.2
Functions
The following functions are available. Note that not all of them are directly used, as the general include
file hsl.hsh defines macros to abstract these functions.
4.2.1 Haunted House functions
Signature
Parameters
Return value
Description
Signature
Parameters
Return value
Description
boolean load(string hhd_file)
hhd_file: the name of the file containing the Haunted House Description, as created
with the Haunted Configurator
True when the file was successfully loaded, false otherwise
This function loads the Haunted House Description file. This file contains the
configurations for the transmitters that are allowed to connect to the controller. It also
specifies which events are triggered when a button on a transmitter is pressed.
This function only has meaning when running the script on a Haunted Controller. When
running the script on a PC using the Beacon of Death, this function has no effect.
boolean connected(string transmitter)
transmitter – the name of the transmitter that is being tested on being connected.
True when the transmitter is connected to the controller, false otherwise
Tests whether a transmitter is connected or not.
14
HL-SYS-003: Haunted Lantern Scripting Language
4.2.2 Time functions
Signature
Parameters
Return value
Description
void delay(int ms)
ms: number of milliseconds to delay
Pauses the current thread for ms milliseconds
Note: the time is measured from the last time a delay was issued, so statements that
are not a delay are considered to have zero execution time. This makes timing effects
much easier. In the following example the second delay(1000) is started at t=1003, but
because the previous delay ended at t=1000, will the delay last until t=2000.
[t=0] delay(1000);
[t=1000] start_stroboscope(0,15,0,0);
[t=1003] delay(1000);
[t=2000] …
Signature
Parameters
Return value
Description
void reset_time()
Sets the time to 0.
Signature
Parameters
Return value
Description
string ctime()
A string representing the current time “xxx days yyy hours zzz seconds”
Returns a string representing the current time. Convenient for logging
Signature
Parameters
Return value
Description
int time()
The current time
Returns the current time, measured in milliseconds since the script was started or the
last call to reset_time().
4.2.3 Event functions
Signature
Parameters
Return value
Description
void trigger(string event)
event : the event that is triggered.
Triggers the named event. The event remains triggered until explicitly released.
Signature
Parameters
Return value
Description
void release(string event)
event : the event that is released.
Releases the named event. If the event was triggered from another source then the
event remains triggered until all sources have released it.
Signature
Parameters
Return value
Description
boolean triggered(string event)
event : the event that is checked.
True if a source has triggered this event, false otherwise
Checks if any source has triggered this event or not
15
HL-SYS-003: Haunted Lantern Scripting Language
Signature
Parameters
Return value
Description
void wait(string event, int delay)
event : the event that needs to be triggered to make the thread continue
delay : the maximum delay the wait takes place if the event is not triggered. Set to 0 to
wait indefinitely for the event.
Returns a string representing the current time. Convenient for logging
4.2.4 Threading functions
Signature
Parameters
Return value
Description
Signature
Parameters
Return value
Description
int spawn(string function)
function : the function where the new thread starts its execution
A unique value that identifies the new thread. Can be used to explicitly terminate the
thread.
Creates a new thread and starts execution at the named function.
void terminate(int thread_id)
threadId: the unique value that identifies the thread that needs to be terminated.
Terminates a thread, i.e. the execution of the target thread is stopped and the thread
is removed from the system.
4.2.5 Logging functions
Signature
Parameters
Return value
Description
void print(string msg)
Msg: the message to be printed
This function prints a message. On a Haunted Controller all printed messages plus
some messages from the system itself end up in a log file, which is accessible through a
web interface. The PC/Beacon of Death solution will print the message right away.
4.2.6 Functions for constructing and transmitting IR messages
These are functions that construct IR messages and makes sure they are sent. These functions are not
used directly by the script. Instead, the macros defined in hsl.hsh use these functions, and scripts should
use these macros.
Signature
Parameters
Return value
Description
void clear_sequence()
Every thread has a buffer in which IR messages are constructed. When making a new
one, the contents of this buffer should be cleared or commands added to the buffer
will be appended to the old message. This function clears that buffer.
16
HL-SYS-003: Haunted Lantern Scripting Language
Signature
Parameters
Return value
Description
Signature
Parameters
Return value
Description
Signature
Parameters
Return value
Description
Signature
Parameters
Return value
Description
void add_sequence_cmd(int type, int ch, int p1, int p2)
type – the command type (fade, set_rgbw, etc)
ch – the channels to which this command applies. For some commands this field has a
different meaning. See [HL-SYS-001] for details.
p1 – The first parameter to this command. Its semantics depend on the command type
p2 – The second parameter to this command. Its semantics depend on the type
This function adds a command to the buffer. Note that a sequence may consist of a
maximum of 8 commands. Adding more is possible, but you will have to mark the end
of the sequence explicitely with an end of sequence command, so the lanterns will not
see sequences longer than 8 commands.
void send_sequence(string transmitter)
transmitter – the name of the transmitter SC that is going to send the IR command.
This parameter is ignored when using the PC/Beacon of Death solution.
This function passes the constructed IR command to the device that is going to
transmit it. If the transmitter is not connected, the message will be lost!
void silence(string transmitter)
transmitter – the name of the transmitter SC that is going to be silenced. This
parameter is ignored when using the PC/Beacon of Death solution.
A transmitter will repeat the sequence passed with send_sequence() until it has been
told otherwise. When you pass a new sequence, but it is still in the middle of sending
the old one, it will first finish sending the old one and only then start with the new one.
That makes it non-deterministic when the new sequence is going to be transmitted. To
avoid that, it is possible to tell a transmitter to remain silent once it finishes the current
transmitting of the message, so that when a new sequence is issued, it can
immediately begin transmitting that.
With this function it is possible to bring the transmitter into silent mode.
void reset_sync(string transmitter)
transmitter – the name of the transmitter SC of which the synchronization is reset
When multiple lanterns are in the same room doing the same heartbeat or
stroboscope, they will always perform these effects in sync. This is because the
transmitter keeps transmitting packets with synchronization information. When
syncing effects with audio it is sometimes necessary to manipulate this
synchronization. This function sets the synchronization counters on the transmitter all
to zero, forcing heartbeats, stroboscopes and rainbow effects to be reset to the
beginning of the cycle (i.e. the strobe in the stroboscope, the first beat in the heartbeat
and the color red in the rainbow effect).
17
HL-SYS-003: Haunted Lantern Scripting Language
4.2.7 Media functions
Some Transmitters SC have the ability to play audio. These two functions access this feature.
Signature
Parameters
Return value
Description
Signature
Parameters
Return value
Description
void play_audio (string transmitter, string filename)
transmitter – the name of the transmitter SC that will play this audio.
filename – the name of the mp3 file that will be played.
This function commands a transmitter to play an mp3 file.
void stop_audio (string transmitter)
transmitter – the name of the transmitter SC that will stop playing audio.
This function commands a transmitter to stop playing an mp3 file. This function may
result in audible clicks when the mp3 playback is terminated.
4.2.8 Randomize functions
Sometimes it is required to do a random effect. For this, we need to be able to generate random
numbers.
Signature
void srand(int seed)
Parameters
seed – the seed from which the random numbers will be generated. A different seed
gives a different sequence of random numbers.
Return value
Description
Plant a seed for the generation of random numbers.
Signature
Parameters
Return value
Description
int rand()
The generated random number
Generates a random number between 0 and 2147483647
18
HL-SYS-003: Haunted Lantern Scripting Language
4.3
Macros
The file hsl.hsh abstracts some of the knowledge of the Haunted Lantern Infrared Protocol by defining a
number of macros. The following macros are available:
4.3.1 Sequence Encapsulation
seq_start()
Marks the start of a sequence, clearing the buffer with any old contents
seq_send(recipient)
Marks the end of a sequence, sending it to the named transmitter
These the macros do not add any functionality, they only make sure that the whole creation and sending
of an IR command has the same prefix ‘seq_’
4.3.2 The no-operation command
seq_nop()
Inserts a no-operation command
4.3.3 Conditional Expressions
seq_conditional_expression(id, min, max)
Adds a conditional-expression-command to the buffer. See [HL-SYS-001] for details.
seq_conditional_operation_true()
Adds a conditional operation ‘true’ command to the buffer. See [HL-SYS-001] for details.
seq_conditional_operation_false()
Adds a conditional operation ‘false’ command to the buffer. See [HL-SYS-001] for details.
seq_conditional_operation_and()
Adds a conditional operation ‘and’ command to the buffer. See [HL-SYS-001] for details.
seq_conditional_operation_or()
Adds a conditional operation ‘or’ command to the buffer. See [HL-SYS-001] for details.
seq_conditional_operation_xor()
Adds a conditional operation ‘xor’ command to the buffer. See [HL-SYS-001] for details.
seq_conditional_operation_not()
Adds a conditional operation ‘not’ command to the buffer. See [HL-SYS-001] for details.
4.3.4 Operations on lantern variables
seq_set(id, val, delay)
Adds a ‘set value’ command to the buffer. See [HL-SYS-001] for details.
4.3.5 Macros for flicker
seq_flicker(depth)
Adds a ‘set flicker’ command to the buffer. See [HL-SYS-001] for details.
seq_flicker_disable()
Adds a ‘set flicker’ command to the buffer, disabling the flicker. See [HL-SYS-001] for details.
19
HL-SYS-003: Haunted Lantern Scripting Language
4.3.6 Intensity control
seq_fade(target, speed)
Adds a ‘fade’ command to the buffer. See [HL-SYS-001] for details.
seq_set_intensity(target)
Adds a ‘set intensity’ command to the buffer. See [HL-SYS-001] for details.
seq_normal_mode()
Adds a ‘set intensity mode normal’ command to the buffer. See [HL-SYS-001] for details.
seq_heartbeat(period, beat2)
Adds a ‘set intensity mode heartbeat’ command to the buffer. See [HL-SYS-001] for details.
seq_stroboscope(period, flashlength)
Adds a ‘set intensity mode stroboscope’ command to the buffer. See [HL-SYS-001] for details.
4.3.7 Color control
seq_set_rgbw(r, g, b, w)
Adds a ‘set rgbw’ command to the buffer. See [HL-SYS-001] for details.
seq_fade_rgbw(r, g, b, w)
Adds a ‘fade rgbw’ command to the buffer. See [HL-SYS-001] for details.
seq_cmd_rainbow()
Adds a ‘enable rainbow’ command to the buffer. See [HL-SYS-001] for details.
seq_cmd_off()
Adds a ‘all special commands off’ command to the buffer. See [HL-SYS-001] for details.
4.3.8 Advanced sequences
seq_end_of_sequence(numCmds)
Adds an ‘end of sequence’ command to the buffer. See [HL-SYS-001] for details.
20
© Copyright 2026 Paperzz