home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 9
/
MEDIASHARE_09.ISO
/
basic
/
mklapi09.zip
/
MARKLIN.DOC
< prev
next >
Wrap
Text File
|
1993-03-02
|
108KB
|
3,092 lines
Märklin-Interface driver
and High Level Language
Application Programming Interface
for C-language and BASIC
Document Number RH-MKLAPI 0.9
March 2, 1993
Rob Hamerling
Vianen-ZH
The Netherlands
Phone: 31-3473-72136 (voice)
FIDO: 2:512/4.1098
Märklin-Interface driver
Versions 0.9 and up are NOT COMPATIBLE with earlier versions!
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
CONTENTS
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What is the Märklin-Interface-driver? . . . . . . . . . . . . . . . . 1
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Realisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Functional description . . . . . . . . . . . . . . . . . . . . . . . . 4
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Functional Requirements . . . . . . . . . . . . . . . . . . . . . . . 4
Provided Facilities . . . . . . . . . . . . . . . . . . . . . . . . . 5
Deliverables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Restrictions and Limitations . . . . . . . . . . . . . . . . . . . . . 7
Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
C-language framework . . . . . . . . . . . . . . . . . . . . . . . . . 7
| QuickBASIC framework . . . . . . . . . . . . . . . . . . . . . . . . . 8
Sample programs . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
OS/2 and DOS differences . . . . . . . . . . . . . . . . . . . . . . 10
Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Available Functions . . . . . . . . . . . . . . . . . . . . . . . . . 12
| mklclose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
| mklflush . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
| mklgetsn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
| mklgo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
| mklmsecs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
| mklopen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
| mklpoll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
| mklpurge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
| mklputc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
| mklsleep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
| mklstats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
| mklstop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
| mkltime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
| mkltrace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Macro Specifications . . . . . . . . . . . . . . . . . . . . . . . . 29
mklput1c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
mklput2c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
| Use of timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
| QuickBASIC Function Specifications . . . . . . . . . . . . . . . . . 30
Errors and Signals . . . . . . . . . . . . . . . . . . . . . . . . . 31
Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Application development considerations . . . . . . . . . . . . . . . 32
C-Compiler considerations . . . . . . . . . . . . . . . . . . . . . . 32
| MicroSoft QuickBASIC compiler 4.5 Considerations . . . . . . . . . . 32
Building an EXE-file . . . . . . . . . . . . . . . . . . . . . . . . 32
| C-language and DOS . . . . . . . . . . . . . . . . . . . . . . . . 33
| C-language and BASIC . . . . . . . . . . . . . . . . . . . . . . . 33
───────────────────────────────────────────────────────────────────────────
Contents ii
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| C-language and OS2 1.3 . . . . . . . . . . . . . . . . . . . . . . 34
| C-language and OS2 2.0+ . . . . . . . . . . . . . . . . . . . . . . 35
| Storage and performance . . . . . . . . . . . . . . . . . . . . . . . 35
Memory Utilisation . . . . . . . . . . . . . . . . . . . . . . . . 35
Processor utilisation . . . . . . . . . . . . . . . . . . . . . . . 36
Comments, Remarks, Bug-reports . . . . . . . . . . . . . . . . . . . 36
Appendix A. Summary of changes . . . . . . . . . . . . . . . . . . . 37
Appendix B. MKLAPI Internals . . . . . . . . . . . . . . . . . . . . 39
Communications Interface Specification . . . . . . . . . . . . . . . 39
Problems with OS/2 COM[xx].SYS . . . . . . . . . . . . . . . . . . . 41
Appendix C. Design Notes and Tips . . . . . . . . . . . . . . . . . 42
Polling Facility . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Multitasking . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Background polling task . . . . . . . . . . . . . . . . . . . . . . 43
OS/2 and DOS differences . . . . . . . . . . . . . . . . . . . . . . 44
Appendix D. Trace facility . . . . . . . . . . . . . . . . . . . . . 47
Trace records . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
─────────────────────
1 This document is processed: on March 2, 1993 at 20:36
───────────────────────────────────────────────────────────────────────────
Contents iii
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
INTRODUCTION
(C) Copyright - R. Hamerling, 1991, 1993
All Rights Reserved.
WHAT IS THE MäRKLIN-INTERFACE-DRIVER?
The Märklin-Interface-driver simplifies programming for model-railroads
which are controlled via a Märklin-Interface. It provides a
communications- and a timer-task, and a number of user callable routines
for elementary functions. It offers a comfortable high-level programming
interface and reliefs a programmer from 'low-level' tasks such as
controlling the communication with the Märklin-Interface, so that he can
concentrate on the railroad-control logic. It includes also a
multi-tasking facility, which is highly desirable for this realtime
environment.
PURPOSE
The driver has been developed for the following purposes:
■ To have an application programming interface (API) which is independent
of the operating system (i.c. OS/2 or DOS).
■ To provide a simple (high level) interface for a number of frequently
used basic control functions such as sending commands to trains and
switch points, and reading sensors.
■ To allow the mainline to be written completely in high-level programming
| language (i.c. C-language or QuickBASIC).
■ To obtain a buffered communications facility to the Märklin-Interface,
including automatic flow control as required by the Märklin-Interface.
■ To have 'background' tasks for a number of functions that should or
could be performed independently (and asynchronously) from the mainline
program.
■ To provide an accurate timer facility for time-dependent operations,
events and calculations.
REALISATION
This package offers a driver with all the functionality of the list in
"Purpose". The OS/2-driver and DOS-driver are completely different
implementations, due to the rather extreme differences in functionality
provided by OS/2 and DOS for this type of environment. However the
railroad control program may be unaware of the underlying operating system:
───────────────────────────────────────────────────────────────────────────
Introduction 1
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
the application programming interface is identical.
You may read a number of (possible) differences in "OS/2 and DOS
differences" on page 10.
REGISTRATION
This package is of the 'SHAREWARE' type: You may try it for a reasonably
short time (say 1 to 2 months). If you decide to use it for your own
railroad control program, you may show your appreciation and become a
'registered user'. After registration, I'll send you by mail:
■ A diskette (3-1/2", 720KB), with the following contents:
- The most recent version of all the drivers.
- Source-files of the sample program provided as executable in the base
package.
■ The complete and up-to-date printed documentation, as well as 2
documentation files on the diskette:
- A print-file, formatted for IBM Pro-Printer III.
- A file in OS/2 INF format (VIEW-able as online documentation like the
inline OS/2 Command Reference Manual).
After registration you are allowed to distribute the driver as integral
part of your own railroad control application programs. The registration
fee is 25 Dutch Guilders or equivalent of 15 US-Dollars. Mention the
purpose of you payment ("Märklin-Interface-driver"), and the destination
address of the additional material!
The package (not the material you get after registration) may be
distributed freely with under the following conditions:
■ it remains a separate and complete package
■ you do not apply changes of any kind
■ you do not make profit with it
Please send your comments and registration fee to:
───────────────────────────────────────────────────────────────────────────
Introduction 2
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
R. Hamerling
Vianen-ZH,
The Netherlands
Postbank acct#: 2087285
PC-Square: FIDOnet 2:512/4.1098
Before you ask: the source material of the drivers will not be published.
───────────────────────────────────────────────────────────────────────────
Introduction 3
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
FUNCTIONAL DESCRIPTION
This chapter describes the possibel use of this package.
OVERVIEW
The Märklin-Interface-driver package is a set of functions to enable direct
| communications support in a program written in C-language or BASIC for the
| MicroSoft QuickBASIC compiler 4.5(2) for the family of IBM Personal
| System/2 and compatibles.
| Note: The QuickBASIC driver is exactly the same as that for C-language, but
| has not been tested extensively with a full fledge train control program in
| BASIC, so beware of possible bugs. Please report possible problems with
| the driver as soon as possible. and accompany your report with as much
| details as might be relevant.
TERMINOLOGY
In this document I use a number of terms which should probably be clarified
first.
Interface The Märklin-Interface. (Märklin partnumber 6050)
Sensor The Märklin S88 encoder. (Märklin partnumber 6088). Sometimes
also called sensor-box or encoder.
Switch The railroad facility, Märklin K83 decoder (Märklin partnumber
6083) is used to control these switch points.
FUNCTIONAL REQUIREMENTS
The Märklin-Interface-driver must provide the following functionality:
■ Possibility to send commands to the Märklin-Interface in any sequence
and mix.
■ Builtin buffered communication with the Märklin-Interface.
■ Automatic flow control between PC and Märklin-Interface.
■ Time-base (clock) for for time-dependent control, independent of
─────────────────────
2 Please note that this driver is delivered in the form of .OBJ-files,
and therefore can be used only with compiled programs (other
.OBJ-files). QBASIC that comes with DOS 5.0 is not capable of
producing an .OBJ file, you'll need the MicroSoft QuickBASIC compiler
4.5 to use this driver with BASIC programs.
───────────────────────────────────────────────────────────────────────────
Functional description 4
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
hardware (processor) speed.
■ Automatic readout of sensor-boxes (Märklin S88 encoder): the mainline
must be able to obtain sensor positions instantaneously (without
waittime)
■ Priority mechanism: mainline activities must be handled with higher
priority than 'background' service processes.
■ Ability for emergency stops, regardless of the state of the program or
the model railroad.
PROVIDED FACILITIES
To fulfil the functional requirements, a 'driver' has been built. It
contains a number of service-routines (and for DOS also hardware interrupt
routines), and provides the following facilities:
■ Functions to send train and switch commands to the interface.
Two macro's for output of resp. 1 or 2 consecutive characters (the so
called 1-byte or 2-byte commands). With the 2-byte form the subroutines
ensure that the 2 characters are sent as 2 consecutive characters (not
interrupted by a 'background' task).
■ Functions to read sensors (S88-boxes).
This can either be done by immediate reading the status of the last
polling operation (if polling started). "Appendix C. Design Notes and
Tips" on page 42 contains details about this mechanism.
If the mainline is sending a command to the Märklin-Interface, polling
is automatically suspended (the command is treated with higher
| priority).
| ■ A 'shadow' of the system timer, but expressed in milliseconds since
| program start. This timer has with the OS/2-driver of MKLAPI a
| precision of 31.25 msecs, using standard OS/2 facilities (the timer
| tick). With the DOS-driver of MKLAPI the posibilities of the hardware
| PC timer are explored, giving a precision of 1 millisecond.
■ A trace facility is built in for easy program debugging. All output to
the interface can [optionally] be traced (OS/2 only) and formatted
later.
───────────────────────────────────────────────────────────────────────────
Functional description 5
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
DELIVERABLES
The shareware components of the Märklin-Interface-driver package are:
■ This documentation file: MARKLIN.DOC.
■ Header file for C-language: MARKLIN.H with function prototypes, data-
| and macro- definitions.
| ■ Include file for QuickBASIC: MARKLIN.INC with function prototypes.
| ■ 2 OS/2-object decks, MARKLIN2.OBJ (16-bits OS/2 version) and
| MARKLIN3.OBJ (32-bits OS/2 version), with a buffered multitasking
| communication interface, polling, timer-support and trace facility.
| ■ 2 DOS-object decks for C-language programs, SMARKIN.OBJ and
| LMARKLIN.OBJ, with the same functionality as the OS/2 drivers, (but
| without a trace facility). SMARKLIN is the object deck to be linked
| with your SMALL memory model program, LMARKLIN.OBJ is for LARGE memory
| model C-language programs. LMARKLIN.OBJ is also used for QuickBASIC
| programs.
■ TRAIN.EXE and TRAIN2.EXE, which are ready to run sample programs for a
DOS and OS/2 environment respectively. See "Sample programs" on page 9
for some characteristics of these programs.
■ MKLTRFMT.EXE, utility to interpret (format) the recorded trace file.
The registration package consists of:
■ Sources (in C-language) of a sample train control program that makes use
of the Märklin driver, usable for OS/2 and DOS ('fullscreen'
application)
■ All include and header files
■ All MAKE and DEF files, used for compilation with MicroSoft C-compiler
6.00a or equivalent, IBM C SET/2 compiler for 32-bits programs and
MicroSoft QuickBASIC compiler 4.5 for QuickBASIC programs.
PREREQUISITES
The package has been built with the following assumptions:
■ Your PC-hardware is 100% compatible with the productline of IBM Personal
Computers (PC, PC/XT, PC/AT, and all current models of the Personal
System/2 family), in particular the asynchronous communication adapters,
their port addresses, etc. and the hardware timer.
■ The operating system is either OS/2 1.2 or higher, or PC-DOS 2.1 or
MS-DOS 2.1 or higher. The package has been tested only with IBM PC/DOS
version 4.0 and 5.0, and with OS/2 version 1.3 and 2.0 (in OS/2
| session).
| ■ Your (16-bits) C-programs (OS/2 and DOS) will be compiled with IBM C/2
| compiler 1.1 or MicroSoft C-compiler 6.00a, for 32-bits C-programs IBM
| C SET/2 compiler is assumed. There may be some specific requirements on
| system hardware and software for these. Maybe Borland Turbo C compiler
| will work as well, but this has not been tested.
───────────────────────────────────────────────────────────────────────────
Functional description 6
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| ■ Your BASIC programs will be compiled with the MicroSoft QuickBASIC
| compiler 4.5.
RESTRICTIONS AND LIMITATIONS
The following restrictions apply:
■ One single port can be used between open and close of the COM-port to
the Märklin-Interface, all other functions apply to the port chosen at
| open-time.
| ■ The transmit buffer of the DOS-driver is 2048 bytes long, for OS/2 it
depends on COM[xx].SYS, or substitute.
■ Received data is transferred immediately to the sensor-array (64 bytes).
■ When the mainline is sending data to the Märklin-Interface and a
buffer-full situation arises, the data will be discarded. However it is
very unlikely that this will happen in real life.
■ If you read a sensor-box outside the polling-range, the response is
undefined.
TESTS
The driver has been tested with the following model railroad equipment:
■ Märklin Combined Control
■ 3 Märklin Digital locs
■ 3 Märklin K83 decoders, each connected to 4 switch points
■ 1 Märklin S88 encoder, with railroad-section sensoring
Some tests have been performed for a bigger environment (such as simulating
more than a single S88), but this does not guarantee that is works in a
real environment different than the one of the list above.
The driver has been tested with the following computer hardware:
■ IBM PC/AT-3 (8 Mhz 80286) and IBM PS/2 model 80 (16 MHz 80386).
■ IBM serial-parallel adapter (primary serial port: COM1).
C-LANGUAGE FRAMEWORK
A typical model railroad control program with this driver may look like:
───────────────────────────────────────────────────────────────────────────
Functional description 7
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
#include "marklin.h"
mklopen(1,2400); /* open COM1: */
mklpoll(5); /* 5 S88 boxes in yard */
while (key != ESC) { /* end program from keyboard */
if (kbhit()) { /* keyboard input */
if (key = getch()) { /* normal key (incl alt-numpad) */
switch(key) {
case '?': - - - - - /* your key, your function */
break;
case ESC: break; /* nothing now, exit program */
default: fprintf(stdout,"%c",BEL);
break; /* unsupported normal key */
}
}
else { /* 'special' key */
switch(key = getch()) { /* extended character */
case PgDn: - - - - - /* your 'extended' key function */
break;
default: fprintf(stdout,"%c",BEL);
break; /* unsupported 'extended' key */
}
}
}
for (i=0; i<MAXTRAIN; i++) { /* scan train matrix */
- - - - - /* train control function */
}
for (i=1; i<5, ++i) { /* scan S88 boxes */
mklgetsn(i); /* read sensor bits */
- - - - - - /* process changes */
}
if (!(mkltime()%5000)) { /* every 5 seconds */
- - - - - /* anything else */
}
mklsleep(); /* give up remainder of timeslice */
}
mklflush(); /* wait until output sent */
mklclose(); /* terminate */
Note: Above code is just a framework to show the general setup of a model
| railroad control program using the Märklin-Interface.
| QUICKBASIC FRAMEWORK
| An equivalent framework in QuickBASIC might look like:
───────────────────────────────────────────────────────────────────────────
Functional description 8
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| ' $INCLUDE: 'MARKLIN.INC'
| rc = mklopen(1,2400);
| mklpoll(5);
| key$ = INKEY$
| while key$ <> ESC$
| select case key$
| case '?'
| - - - - -
| case ESC
| - - - - -
| case else
| print "error key"
| end select
| for i=0 to MAXTRAIN
| - - - - -
| next i
| for i=1 to 5
| mklgetsn(i)
| - - - - - -
| next i
| if MOD(mkltime,5000) < 50 then
| - - - - -
| end if
| mklsleep
| key$ = INKEY$
| wend
| mklflush;
| mklclose;
| Note: This code may not be true and workable BASIC!
| The file MARKLIN.INC contains the DECLARE lines for all functions contained
| in LMARKLIN.OBJ. It should be included in a QuickBASIC program to obtain
| the correct calling conventions and activates syntax checking by the
| MicroSoft QuickBASIC compiler 4.5.
SAMPLE PROGRAMS
| After registration you will receive the sources a sample program (in
| C-language only!).
■ Control of 8 trains and several other possibilities, with the following
details:
- Speed is controlled from the computer keyboard with arrow (cursor)
keys: right-key is faster, left-key is slower, up-key is maximum for
this train, down is maximum backward for this train.
- The train for which the command is meant is selected with a
number-key (program provides control for trains 1 through 8). The
corresponding loc-address and other train properties are in a matrix
───────────────────────────────────────────────────────────────────────────
Functional description 9
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
(with individual entries for each train), such as minimum and maximum
speed in Märklin Central Unit values. The train addresses that are
programmed are 10 for train 1, 20 for train 2, etc until 80 for train
8.
- The speed-control is indirect: you tell the system the program
loc-speed, the program does mass-simulation ('slow' increase and
decrease of speed). The parameters for enertia simulation are part
of the train definitions.
- For each train its address, desired and actual train speed are
displayed (in color). Direction changes are buffered and automatic.
- The display also indicates direction and whether the extra function
is 'on' or 'off'.
| ■ Control of 4 Märklin K83 decoder for 16 railroad switch points. For
| each switch the position ('normal' or 'bound' in color) and its address
| is displayed. The keys are A-P for adresses 253-256, and 1-12
| respectively.
| ■ Polling of Märklin S88 encoder each with 16 sensors (or isolated
| railroad sections). The position is displayed real time, nothing but
| displaying is done with the information. 2 Märklin S88 encoder-boxes
| are being polled.
| ■ Sensor 16 of Märklin S88 encoder-box 1 is designated for speed
| measurement. The display shows the time (in milliseconds) between 2
| successive 'OFF-ON' transitions. If there is 1 train running and moving
along the same road, this facility can be used for calibrating speed
calculations for each speed-command-value.
■ Other keys:
Insert Set Function 'on'
Delete Set Function 'off'
End Stop polling
Home Restart polling
F3 Stop the program (has to be entered twice consecutively)
Esc Emergency Stop (issues the Märklin Central Unit STOP command)
Enter Resume (issues the Märklin Central Unit GO command)
The program may be started with 2 numeric parameters:
1. the first parameter indicates the COM-port to be used (1 for COM1, 2 for
COM2, etc.), The default is COM1.
2. The second parameter indicates the number of Märklin S88 encoder-boxes
to include in the polling mechanism. The default is 2.
OS/2 AND DOS DIFFERENCES
The OS/2-drivers differ from the DOS drivers:
■ The OS/2-drivers are written in C-language, the DOS drivers in
Assembler.
───────────────────────────────────────────────────────────────────────────
Functional description 10
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
■ The OS/2-driver makes use of the services provided by the standard OS/2
communications driver COM02.SYS (for PS/2) or COM01.SYS for others under
OS/2 version 1.3, and COM.SYS for OS/2 version 2.0. The DOS driver
interfaces directly with the PC hardware.
■ The OS/2-driver makes use of the standard OS/2 facilities for
multithreading (task signalling is done with semaphores). The DOS
driver performs a form of multi-tasking, driven by interrupts (the
| COM-port hardware and the standard DOS timer tick).
| ■ The DOS-drivers explore the possibilities of the hardware timer of the
| PC to obtain a accurate time values when needed. With the DOS
| timer-tick of 55 msec the average deviation would be about 28 msec.
| OS/2 does not allow access to the hardware by 'normal' applications,
| therefore the OS2.-drivers use standard OS/2 function calls. Since the
| OS/2 timer tick is 31.25 msec, the average deviation will be about 16
| msecs.
The sample program under DOS chokes the processor (takes all the cycles
that are available). This is OK in a typical single-task environment, but
not very suitable for a multitasking system. Under OS/2 a very simple
solution for this problem is to insert for example a DosSleep(30L) at the
end of the infinite (keyboard-) loop. There may be better solutions.
───────────────────────────────────────────────────────────────────────────
Functional description 11
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
SPECIFICATIONS
This chapter describes the use of the provided facilities.
AVAILABLE FUNCTIONS
The following user callable functions are provided:
mklopen Start the communication with the Märklin-Interface and the
background tasks.
mklclose Stop background tasks and shutdown the communication with
the Märklin-Interface.
mklputc Transmit 1 or 2 character-commands to the
Märklin-Interface.
mklflush Wait until all data transmitted.
mklpurge Discard remaining data in output buffer.
mklpoll Start or stop polling of Märklin S88 encoder boxes.
mklgetsn Obtain the status of 1 Märklin S88 encoder (when polling
active).
mklstop Set Märklin-Interface in 'stop'-state and stop polling
mklgo Set Märklin-Interface in 'go'-state and (optionally) resume
polling.
| mklmsecs Give accurate time in milliseconds since program start
| (only in DOS-drivers).
| mkltime Give time of last timer tick in milliseconds since program
| start.
| mklstats Provide statistics (activity counters).
mklsleep Give up the remainder of a time slice when running in a
multitasking environment.
mkltrace Start or stop recording data that is being sent to
| Märklin-Interface (only in OS/2-drivers).
The next sections contain the specifications of available functions of the
| Märklin-driver, in alphabetical sequence.
| Note: The descriptions for C-language and QuickBASIC are given both, but in
| the text mainly the C-language notations are used.
| MKLCLOSE
| Name mklclose - close communications with the Märklin-Interface.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 12
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| void mklclose(void);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE SUB MKLCLOSE CDECL ()
| Description The close-routine disables the communications task of the
| driver. It should be called before termination your
| program. Transmits and receives that were in progress will
| be terinated, data might be lost.
| Return value Nothing.
| Related functions "mklopen" on page 17
| Warning: Mklclose() is not a trivial function! It must be used when
| mklopen() has been called succesfully (under DOS). Otherwise your system
| may enter a hang-up situation when for no matter what reason your
| communications port gives an interrupt. So terminate your program always
| 'neatly' (so intercept Ctrl-Break in your program to prevent uncontrolled
| program termination)!
| MKLFLUSH
| Name mklflush - flush all buffered output.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 13
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| int mklflush(void);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION FLUSH% CDECL ()
| Description Wait until all output is sent to the Märklin-Interface. In
| other words: wait for empty transmit buffer before
| returning to caller. When the buffered data could not be
| flushed within 3 seconds, a timeout occurs. The remaining
| bytes in the transmit buffer will be purged and the purge
| statistics are updated accordingly.
| Return value Depending on success:
| ■ 0 when no more bytes to transmit
| ■ >0 timeout (3 seconds) with number of bytes (n) left in
| transmit buffer.
| ■ -1 (DOS) last byte in hardware buffer was not
| transmitted
| Related functions "mklpurge" on page 20
| MKLGETSN
| Name mklgetsn - get the bit-pattern of a single Märklin S88
| encoder.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 14
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| unsigned short int mklgetsn(short int sensor);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION MKLGETSN% CDECL (BYVAL SENSOR%)
| Description Get a single sensor-box word (16 bits) from the sensor
| array.
| This function does not generate any action to the
| Märklin-Interface and returns immediately. Polling will
| have to be started first, with mklpoll(), before the
| reading of sensors will give meaningful results. Reading
| outside the range 1..31, or higher than the value as
| specified with the latest mklpoll(maxsensor) or mklgo(
| maxsensor), will give unpredictable results.
| Return value A 16-bit word containing the current switch positions.
| MKLGO
| Name mklgo - send the 'go' command.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 15
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| int mklgo(short int maxsensor);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION MKLGO% CDECL (BYVAL MAXSENSOR%)
| Description Send the 'go'-command (ASCII 96) to the Märklin-Interface
| immediately.
| The value of MAXSENSOR has the same meaning and effect as
| in mklpoll (see "mklpoll" on page 18). Polling will be
| resumed if a non-zero parameter is specified.
| OS/2: The go-command is sent via a DevIOCtl operation (send
| immediate), and will be followed by a simulated XON. If
| there was buffered output (before the stop-state or after
| entering stop-state under OS/2 2.0), it will be transmitted
| now. If the 'go'-command could not be sent, for example if
| the Interface is not ready to accept data, an
| errorcondition is returned.
| DOS: The go-command is send just as regular data. The
| returncode is always zero.
| Return value Nothing.
| Related functions "mklstop" on page 25, "mklpoll" on page 18
| MKLMSECS
| Name mklmsecs - obtain time since program start in milliseconds.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 16
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| unsigned long int void mklmsecs(void);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION MKLMSECS& CDECL ()
| Description (DOS only!) Returns the exact time in milliseconds after
| program start without waiting for the next timer tick.
| This might be useful for more accurate timing for special
| purposes. Of course it takes some time to execute the
| necessary instructions to read the timer and format the
| information. On faster systems mklmsecs() gives the time a
| little more precise than on slower systems, but even on
| relatively slow systems it is much more precise than
| probably needed for the purpose of mode railroad control!
| If this very high precision is not needed, then use the
| function mkltime().
| (OS2.) This function is 100% equivalent to mkltime().
| Return value Time in milliseconds after program start.
| Related functions "mkltime" on page 27
| MKLOPEN
| Name mklopen - open communications line
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 17
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| void mklopen(short int port, short int speed);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE SUB MKLOPEN CDECL (BYVAL PORT%, BYVAL SPEED%)
| Description Open and initialise communications port driver, high
| resolution timer (DOS only), set all statistics counters to
| zero. The port-parameter may have a value of 1 to 4,
| indicating COM1: to COM4:. COM1 and COM2 are pretty
| standard, but COM3 and COM4 aren't. The following list
| shows my implementation of these ports.
| mklport base address IRQ INT vector addr
| -------- ------------ ----- ---------------
| COM1: 1 3F8 4 0030
| COM2: 2 2F8 3 002C
| COM3: 3 338 4 0030
| COM4: 4 238 3 002C
| Warning: ports 3 and 4 may conflict with other hardware
| and/or software. Use of these ports is is your
| responsibility, not that of the author of this package!
| Any port will always be initialised with 8-bit, no-parity,
| 2 stop-bits. The speed parameter should specify 2400,
| since it is the only speed supported by the
| Märklin-Interface. Maybe later other values?
| The mklopen routine will initialise the communications task
| and the timer.
| Disabling is performed by mklclose().
| Return value Nothing
| Related functions "mklclose" on page 12, "mklstats" on page 23
| MKLPOLL
| Name mklpoll - start periodic reading of Märklin S88 encoder.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 18
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| void mklpoll(unsigned int maxsensor);
| QuickBASIC
───────────────────────────────────────────────────────────────────────────
Specifications 19
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE SUB MKLPOLL CDECL (BYVAL MAXSENSOR%)
| Description Märklin S88 encoderboxes 1..MAXSENSOR will be read by a
| 'background' process.
| When starting the polling process a 'read with reset' is
| issued. This means that the switches are supposed to be of
| the 'permanent' type, not of the 'moment' type. This will
| be usable for example if you use them for sensing
| train-positions with isolated rail-sections.
| The responses of the read-operation are stored in a
| sensor-array. Each word of the array can be read
| individually at any time with mklgetsn().
| Polling can be started and stopped any moment. And even if
| started, it can be re-started (for example with a different
| maximum sensor value).
| Return value Nothing
| Related functions "mklgo" on page 15 and "mklgetsn" on page 14
| MKLPURGE
| Name mklpurge - purge output buffer
| C-language
| #include "marklin.h"
| void mklpurge(void);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE SUB MKLPURGE CDECL ()
| Description Discard current contents of output buffer. If the output
| buffer does contain any characters, these are not sent tot
| the Interface. After purging the current contents, control
| is immediately returned. See also "mklflush" on page 13.
| Note: This function is currently available in the driver
| for DOS.
| Return value Nothing.
| Related functions "mklflush" on page 13
───────────────────────────────────────────────────────────────────────────
Specifications 20
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| MKLPUTC
| Name mklputc - send 1 or 2 characters to the interface
| C-language
| #include "marklin.h"
| int mklputc(unsigned int word);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION MKLPUTC% CDECL (BYVAL WORD%)
| Description Send 1 or 2 characters to the Märklin-Interface. The
| 'word' is interpreted as two contiguous characters. The
| low order byte of the word is sent first, followed by the
| high-order byte. If the high is not sent when zero. The
| exception to this rule is: if the first byte is a
| switch-command (ASCII 33 or 34), then the second byte will
| be sent, even when zero.
| This function returns immediately, and does not wait for
| the bytes to be actually transmitted to the interface. The
| communications task will take care to send the buffered
| character(s) to the Märklin-Interface.
| Coding example to signal speed 8 to loc 27:
| rc = mklputc( 27*256 + 8)
| For C-language programs it is highly recommended to use the
| provided macro's for sending 1 or 2 character commands (see
| "Macro Specifications" on page 29).
| Warning: When there is no room in the output buffer, then
| both characters will be discarded.
| Return value 0 character(s) are accepted by the driver.
| -1 characters NOT accepted: output discarded.
| Note: If you use mklputc() while the driver is in 'stop-state' (see
| "mklstop" on page 25):
| ■ the OS/2-drivers issue a short high-pitch beep. With OS/2 2.0 the data
| might be buffered and transmitted after mklgo(). This depends on the
| used device driver for the COM-port. COM[xx].SYS does not buffer, but
| SIO.SYS does (until its 4KB buffer is full).
| ■ the DOS-drivers do not generate a warning and will discard the data
| until the stop-state is left via a call to mklgo().
───────────────────────────────────────────────────────────────────────────
Specifications 21
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| MKLSLEEP
| Name mklsleep - give up remainder of timeslice
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 22
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| void mklsleep(void);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE SUB MKLSLEEP CDECL ()
| Description When running a DOS-program in a multitasking environment
| (OS/2, Desqview, Windows, etc.), is is desirable to give
| control back to the multitasker, when the program does not
| need the processor for some time. This function is
| experimental, it may not work with all multitaskers.
| The use of mklsleep is not absolutely needed with
| pre-emptive multitaskers (like OS/2), and is strongly
| recommended with Windows and DesqView. In all cases it
| reduces CPU utilisation and leaves processor time for other
| tasks.
| Return value Nothing.
| MKLSTATS
| Name mklstats - obtain content of statistics counter.
| C-language
| #include "marklin.h"
| long int mklstats(int counter);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION MKLSTATS& CDECL (BYVAL counter%)
| Description Obtain value of an internal counter in MKLAPI for
| statistical purposes. All counters will be reset to zero
| with mklopen(), and can also be reset by a user program
| through specification of 0 (zero) as parameter.
| To read a counter specify a number in the range: 1 to 6.
| The counters (by number) have the following contents:
| 1 Number of accepted commands, including polling-commands
| (commands to read S88's). Since the we use a buffering
| mechanism, not all of these commands may have been
| transmitted actually!
| 2 Number of internally generated commands to read S88's
| ('polls').
───────────────────────────────────────────────────────────────────────────
Specifications 23
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| 3 Number of commands that have been discarded. Reasons
| may be:
| ■ system is in 'stop-state'
| ■ transmit buffer is full
| 4 Number of bytes that were transmitted. With the
| DOS-driver these bytes are actually transmitted to the
| COM-port, with OS/2 they were accepted by the device
| driver of the COM-port.
| 5 Number of received bytes (most likely as result
| commands to read S88's).
| 6 Number of bytes that were purged (discarded after first
| being accepted, but before actually being transmitted
| to the Märklin-Interface). Reasons may be:
| ■ there were commands buffered while mklstop() was
| called
| ■ mklflush() could not complete (timeout)
| ■ commands were in the transmit buffer during a call
| to mklpurge()
| Discarded commands are not counted as 'purged'.
| Note: Purging is not supported in the OS/2-drivers, so
| this counter should remain zero with OS/2 programs.
| Counters in the range 1 to 6 can be considered as permanent
| feature of MKLAPI. Counters in the range 7 to 15 are
| mainly for debugging purposes. The description below is
| for information purposes only, do not use them in your
| program, as they may be incorrect, their meaning changed in
| a next version of MKLAPI, or may not be active at all in
| the distributed drivers.
| 7 DOS: Number of calls to mklputc while the driver's
| transmit buffer was empty.
| 8 DOS: Number of calls to mklputc while the CTS signal is
| 'high'.
| 9 DOS: Number of calls to mklputc while the hardware
| communications buffer was empty.
| 10 DOS: Number of calls to mklputc whereby the first or
| only byte had to be put in the driver's communications
| buffer.
| 11 Number of calls to mklputc with a request for 2 bytes
| (second character always buffered).
| 12 DOS: Total number of interrupts processed by the
| interrupthandler for the asynchronous communications
───────────────────────────────────────────────────────────────────────────
Specifications 24
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| port.
| 13 DOS: Number of THRE interrupts.
| 14 DOS: Number of MSR interrupts (number of CTS signal
| changes).
| 15 DOS: Situations with a pending interrupt after a
| previous interrupt was processed.
| Specification of a counter number outside the indicated
| range will give unpredictable results.
| Return value Contents of the specified counter (zero after reset).
| Related functions "mklopen" on page 17
| MKLSTOP
| Name mklstop - send the 'stop' command.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 25
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| int mklstop(void);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION MKLSTOP% CDECL ()
| Description Send the 'stop'-command (ASCII 97) to the Märklin-Interface
| immediately. If polling was active at the time, it will be
| stopped.
| OS/2: The stop-command is sent via a DevIOCtl operation, so
| it will be sent ahead of data that might be in the transmit
| buffer. If it could not be sent, for example the Interface
| is not ready, an errorcode is returned. If OK, this is
| followed by a simulated XOFF command to indicate the
| COM-driver not to send yet buffered data to the
| Märklin-Interface. The transmit buffer is NOT purged,
| pending output is preserved. Transmission will can resumed
| after a simulated XON, which will be provided by mklgo().
| When the application continues to send commands, these will
| be discarded.
| DOS: The transmit buffer is purged and the stop-command is
| then sent as regular data. New output is not accepted
| anymore (it is discarded), until a mklgo() is issued.
| Warning: The 'stop' command could be sent by the mainline
| directly, but then would bypass the administrative
| functions of the driver. Any following command received by
| the Märklin-Interface other than 'go' will cause a
| permanent drop of the CTS signal, making the control over
| the railroad from the computer permanently unavailable.
| The only possibility to resume control then is by manually
| hitting the 'go' key on the Märklin Central Unit.
| Note: The timer does not stop with a mklstop(). This may
| cause strange effects from time-dependent calculations in
| your mainline!
| The 'stop' command might interfere with a 2-byte command of
| which the first byte was already transmitted, but the
| second byte not! In that case the 'stop' would not be
| recognised by the Märklin-Interface. Two consecutive
| 'stop'-commands will prevent the acceptation by the
| Märklin-Interface of any further commands from the
| computer. To prevent this undesired situations and make
| sure that the 'stop' command will be processed by the
| Märklin-Interface, MKLAPI precedes the 'stop'-command with
| a 'go'-command:
| ■ If there was no command in transmission, then in won't
| harm.
───────────────────────────────────────────────────────────────────────────
Specifications 26
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| ■ If a 'broken' 2-byte command was in progress, then the
| 'go'-byte will be interpreted by the Märklin-Interface
| as the second byte. This will probably have a different
| effect than was foreseen!
| Return value Nothing.
| Related functions "mklgo" on page 15
| MKLTIME
| Name mkltime - obtain time since program start in milliseconds.
| C-language
───────────────────────────────────────────────────────────────────────────
Specifications 27
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| #include "marklin.h"
| unsigned long int mkltime(void);
| QuickBASIC
| ' $INCLUDE: 'MARKLIN.INC'
| DECLARE FUNCTION MKLTIME& CDECL ()
| Description Returns the time in milliseconds after program start since
| it was updated with the last timer 'tick' (OS/2: 31.25
| msecs, DOS: 55 msecs).
| This is a little less accurate than mklmsecs, but consumes
| significantly less processor cycles.
| Return value Time in milliseconds after program start.
| Related functions "mklmsecs" on page 16
| MKLTRACE
| Name mkltrace - start or stop trace
| C-language
| #include "marklin.h"
| void mkltrace(short int signal);
| Description Start or stop tracing of all data that is being sent to the
| Märklin-Interface and record the information, including a
| timestamp into the file MARKLIN.TRC.
| When signal is NOT zero, then tracing will be started, or
| restarted (old trace data will be discarded in that case).
| When signal is zero the trace is stopped and the trace file
| closed.
| It is my intention to replace this 'on/off' switch with a
| trace level facility (selection of events or data to be
| traced).
| Note: Since a buffered communications interface is used,
| the recording of trace data takes place at the moment the
| data is sent to the buffer. So the timestamp does not
| reflect the exact transmission time. Especially at moments
| when Märklin-Interface does not accept data (for example
| when it is transmitting Märklin S88 encoder-data), there
| may be a significant time difference!
| The utility MKLTRFMT.EXE can be used to produce a formatted
| trace report. All commands are printed hexadecimal and
───────────────────────────────────────────────────────────────────────────
Specifications 28
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| interpreted.
| See for details about the trace facility and a sample
| output: "Appendix D. Trace facility" on page 47.
| Return value Nothing.
| Note: Tracing is not provided by the DOS-drivers, but a dummy function is
| provided for combined OS/2 and OS/2 programs.
MACRO SPECIFICATIONS
A number of C-language only macro's is provided to make specification of
some function-calls a little more simple, and to take care of possibly
needed data conversion.
MKLPUT1C
Name mklput1c - send a single character to the interface.
Usage #include "marklin.h"
void mklput1c(char);
Prototype in marklin.h
Description Macro to send a single character in the output buffer. The
macro will expand into a mklputc().
Return value See "mklputc" on page 21.
MKLPUT2C
Name mklput2c - send two characters to the interface.
Usage #include "marklin.h"
void mklput2c(char1,char2);
Prototype in marklin.h
Description Macro to send two consecutive character in the output
buffer. The characters will guaranteed be sent in the
given order, without the risk of intervening characters by
the polling mechanism. The macro will expand into a
mklputc().
Return value See "mklputc" on page 21.
───────────────────────────────────────────────────────────────────────────
Specifications 29
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| USE OF TIMER
| At program start with mklopen(), the system time is taken as base for the
| functions mkltime and mklmsecs. These functions return a value in
| milliseconds after mklopen().
| The OS/2-driver uses standard OS/2 facilities, which will allow a precision
| of about 16 msecs (the time is updated in OS/2 control blocks every 31.25
| msecs).
| The DOS-driver uses the system hardware to obtain the system time. This
| allows a precision of 1 msec (with the function mklmsecs()). The function
| mkltime() gives a precision of about 28 msecs, and takes less machine
| instructions, which might be sufficient for most purposes.
| The use of this timer facility provided by the MKLAPI-drivers has the
| following advantages:
| ■ It is independent of system (processor) speed and other tasks running in
| your system. Many sample programs use some kind of processing loop to
| obtain a 'wait'-period, which might be dependent on processor speed and
| 'choke' the processor, during which time no other useful work is
| possible, or at least it is pretty complicated.
| ■ It is available with very little processor cycles, so it is not needed
| to call a 'universal' compiler-provided timer routine, which are
| generally much more cycle consuming.
| The timer can be used for example for:
| ■ The application of an event-queue (for timed operations).
| ■ 'Wait'-intervals during without programming a loop.
| ■ Simulation of train mass (inertia) through gradually increasing or
| decreasing loc-speed.
| If you register this package, you'll receive a sample program which makes
| use of this feature.
| It is recommended to use mklsleep() in cyclic operations when running in a
| multitasking environment sucha as Windows, DesqView or in a DOS-session
| under OS/2.
| QUICKBASIC FUNCTION SPECIFICATIONS
| The functionality of the Märklin-driver for QuickBASIC is the same as for
| the drivers for C-language. However the following should be noted:
| ■ BASIC does not allow the underscore-sign ("_") in names, as is very
| common in C-language. Therefore the FUNCTIONS and DATA fields in the
| Märklin-driver for QuickBASIC have been adapted a little to BASIC
| conventions since in 0.9 of these drivers. All other differences are
| 'under the cover' (but see next item).
───────────────────────────────────────────────────────────────────────────
Specifications 30
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| ■ C-language uses by default a different way of parameter passing than
| BASIC, PASCAL and some other languages. But MicroSoft QuickBASIC
| compiler 4.5 allows the C-language convention to be used, and the
| Märklin-driver for QuickBASIC expects this convention to be used. This
| is reflected in the function specifications in MARKLIN.INC. If you use
| the MARKLIN.INC file (strongly recommended!), then you won't have to
| worry about these conventions.
ERRORS AND SIGNALS
The driver is designed not to disturb your screen with error-messages.
Therefore audiable signals are used to indicate unexpected problems. The
following list is valid for the OS/2-driver only:
very high pitch, long 4000 Hz, 300 msec: Märklin-Interface seems to be
long-term blocked. The transmit task (mklputc routine) is
waiting for a previous request to finish, but for some reason
it doesn't. Check the 'stop'-light on the Märklin Central Unit
if a stop-condition is the cause (manually set, or electrical
problem).
very high pitch, short 4000 Hz, 20 msec: Märklin-Interface The driver is
in stop-state, but some routine tries to send commands, which
are discarded.
high pitch, short 2000 Hz, 20 msec: A command-transmission did not finish
within the normal time. Too many commands may be queued, maybe
because of a program loop.
medium pitch, short 1000 Hz, 20 msec: a communications error occurred
(OS/2). Debugging information is sent to STDERR (which you
might have redirected to a log-file to prevent disturbance of
your screen).
The DOS-drivers do not produce audiable signals.
───────────────────────────────────────────────────────────────────────────
Specifications 31
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
INSTALLATION
APPLICATION DEVELOPMENT CONSIDERATIONS
| This MKLAPI is a program development tool with a C-language or QuickBASIC
compiler. You need MARKLIN.H (MARKLIN.INC for BASIC) at compile-time and
one of the .OBJ files at LINK-time. It is an addition to the compiler and
possibly other toolkits you may have for other purposes.
C-COMPILER CONSIDERATIONS
The following compiler properties apply.
■ The file MARKLIN.H must be #included in the program that references the
driver routines (you can use the same header-file for OS/2 and DOS).
| ■ Memory model: OS/2: LARGE; DOS: SMALL or LARGE (your choice)
| ■ Calling conventions: C
| ■ OS/2: The MT\INCLUDE's should be used with IBM C/2 compiler 1.1, since
| the driver is multithreaded. With MicroSoft C-compiler 6.00a the '/MT'
| parameter is sufficient, and with IBM C SET/2 compiler '/Gm' should be
| specified among other parameters.
■ Generate underbars: On (Turbo-C option).
Other compiler options are (probably) not of influence on the use of the
| Märklin-driver.
| MICROSOFT QUICKBASIC COMPILER 4.5 CONSIDERATIONS
| The QuickBASIC compiler is needed to create an object deck of your BASIC
| program. This OBJect file is combined with LMARKLIN.OBJ file as provided
| by this MKLAPI package to build an EXE-file with the LINK utility.
| ■ Calling conventions: C (DECLARE SUB|FUNCTION xxx CDECL ... etc)
BUILDING AN EXE-FILE
| One of the OBJect files should be included in the link-step with your own
| OBJect file(s). I prefer to Compile and LINK with the help of the (N)MAKE
| utility.
───────────────────────────────────────────────────────────────────────────
Installation 32
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| C-LANGUAGE AND DOS
| For the DOS sample application ("TRAIN") I use the following MAKE-file:
| ┌─────────────────────────────────────────────────────────────────────────┐
| │ │
| │ │
| │ # │
| │ # MAKE TRAIN: Marklin Digital Train Control program (DOS version) │
| │ # - SMARKLIN.OBJ and LMARKLIN.OBJ generated │
| │ # - SMALL memory model version user for train.exe │
| │ # │
| │ │
| │ MDL=L │
| │ CL=-c -Zl -Zp -G0 -W3 -AL -DDOS -Fotrain.obj -Ot │
| │ LK=/NOD /PACKC:65500 /ST:4000 │
| │ │
| │ train.exe: train.obj smarklin.obj lmarklin.obj │
| │ # LINK train+$(MDL)marklin, train $(LK), nul, $(MDL)LIBCER; │
| │ LINK train+$(MDL)marklin, train $(LK), nul, $(MDL)LIBCER; │
| │ │
| │ train.obj: train2.c train.h train.mak attrib.h attrib2.h common.h\ │
| │ matrix.h marklin.h │
| │ CL $(CL) train2.c │
| │ │
| │ smarklin.obj: marklin.asm marklin.h train.mak │
| │ MASM -Dsmall marklin.asm,smarklin; │
| │ │
| │ lmarklin.obj: marklin.asm marklin.h train.mak │
| │ MASM -Dlarge marklin.asm,lmarklin; │
| │ │
| │ │
| └─────────────────────────────────────────────────────────────────────────┘
| Note: It contains switches to control the use of large or small memory
| models.
| C-LANGUAGE AND BASIC
| For a simple test-program in QuickBASIC I use the following batch-file:
| ┌─────────────────────────────────────────────────────────────────────────┐
| │ │
| │ │
| │ rem │
| │ rem Build Marklin Digital Train Control program (DOS QuickBASIC version)│
| │ rem - LMARKLIN.OBJ copied from \C2\MARKLIN subdirectory │
| │ rem │
| │ BC train /A /C:1 /O /S; │
| │ if errorlevel 0 LINK train+\c2\marklin\lmarklin,/NOE,train; │
| │ │
| └─────────────────────────────────────────────────────────────────────────┘
───────────────────────────────────────────────────────────────────────────
Installation 33
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| Note: With MicroSoft QuickBASIC compiler 4.5 the LMARKLIN.OBJ need to be
| included in the link. models.
| C-LANGUAGE AND OS2 1.3
| For the 16-bits OS/2-sample application ("TRAIN2") I use the following
| MAKE-file for MicroSoft C-compiler 6.00a and IBM OS/2 Program Development
| Toolkit 1.2/1.3:
| ┌─────────────────────────────────────────────────────────────────────────┐
| │ │
| │ │
| │ # │
| │ # MAKE TREIN: Marklin Digital Train Control │
| │ # │
| │ # To be used with MicroSoft C-compiler 6.00a │
| │ # │
| │ # With IBM C/2 1.1 compiler specify '__IBMC2__' compiler option │
| │ # │
| │ # 'OS2' compiler variable needed for OS/2 object of TRAIN2! │
| │ # │
| │ │
| │ CL=-c -Zp -Zl -W3 -MT -DOS2 │
| │ LK=/A:16 /PACKC:65000 /NOI /NOD │
| │ L1=LLIBCMT OS2 │
| │ │
| │ train2.exe: train2.obj marklin2.obj train2.def │
| │ LINK train2+marklin2, $@ $(LK), NUL, $(L1), train2.def │
| │ │
| │ train2.obj: train2.c train2.h attrib2.h marklin.h common.h matrix.h │
| │ CL $(CL) train2.c │
| │ │
| │ marklin2.obj: marklin2.c │
| │ CL $(CL) marklin2.c │
| │ │
| │ │
| └─────────────────────────────────────────────────────────────────────────┘
| The contents of the corresponding LINK .DEF-file are:
| ┌─────────────────────────────────────────────────────────────────────────┐
| │ │
| │ │
| │ ; │
| │ ;******* Marklin Train Control Program Definition File (.DEF) ******** │
| │ ; For: 1) 16-bit version for OS/2 1.3 and MS C-compiler │
| │ ; 2) 32-bit version for OS/2 2.0 and IBM C Set/2 compiler │
| │ │
| │ NAME TRAIN2 WINDOWCOMPAT │
| │ │
| │ DESCRIPTION 'Marklin Train Control. Copyright (1991,93) Rob Hamerling' │
| │ PROTMODE │
───────────────────────────────────────────────────────────────────────────
Installation 34
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| │ HEAPSIZE 4096 │
| │ STACKSIZE 8192 │
| │ │
| └─────────────────────────────────────────────────────────────────────────┘
| C-LANGUAGE AND OS2 2.0+
| For the 32-bits OS/2-sample application ("TRAIN3"), the following MAKE-file
| is appropriate for IBM C SET/2 compiler and IBM OS/2 Program Development
| Toolkit 2.0:
| ┌─────────────────────────────────────────────────────────────────────────┐
| │ │
| │ │
| │ # │
| │ # MAKE TREIN: Marklin Digital Train Control program │
| │ # │
| │ │
| │ CL=/c /G3 /Gd+ /Gm+ /MS /Re /Se /Sm /Ss -DOS2 │
| │ LK=/NOI /PACKC:65500 /ALIGN:4 /BASE:0x10000 /EXEPACK │
| │ │
| │ train3.exe: train3.obj marklin3.obj │
| │ link386 $**, $@ $(LK), NUL, , train2.def │
| │ │
| │ train3.obj: train2.c │
| │ icc $(CL) /Fotrain3.obj train2.c │
| │ │
| │ marklin3.obj: marklin2.c marklin.h │
| │ icc $(CL) /Fomarklin3.obj marklin2.c │
| │ │
| │ │
| └─────────────────────────────────────────────────────────────────────────┘
| Note: The same .DEF-file is used as for the 16-bit version.
| STORAGE AND PERFORMANCE
| There is yet not much to say about storage and performance of the driver.
| It is highly optimised code, and probably only a minor part of the 'real'
| railroad control program.
MEMORY UTILISATION
It is difficult to say how many storage is occupied by the OS/2-version of
the Märklin-driver.
The DOS-version requires about 4K bytes of storage.
───────────────────────────────────────────────────────────────────────────
Installation 35
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
PROCESSOR UTILISATION
You might be curious about the cycles that will be consumed by the polling
task. I've done some measurements under OS/2 version 1.3 with the sample
program TRAIN2. On an 8 Mhz AT (80286) the polling takes between 10% and
12% of the processor time (difference in processor utilisation between
polling ON and OFF). This number is practically independent of the number
of Märklin S88 encoder's that are specified for polling, but the polling
frequency is also lower!
COMMENTS, REMARKS, BUG-REPORTS
If there are bugs, requirements or questions about this Märklin-driver, the
documentation or the sample program (that you get when you register),
please send me a message through the FIDO network. You can find my name
and node-(point)-number in the introduction of this document.
Enjoy and good luck with your program development! May this driver lead to
a very attractive and succesful model railroad control program!
Do not 'forget' to register!
───────────────────────────────────────────────────────────────────────────
Installation 36
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
APPENDIX A. SUMMARY OF CHANGES
0.7 First 'official' release: June 1992
0.8 released: October 1992
■ The time-base value in mkltime has been changed from 55 msec to 1
msec! (updating of mkltime still on timer-tick basis: once per 55
msecs in DOS, once per 31.25 msecs in OS/2).
■ DOS: High precision timer routine added: mklmsecs(). This gives
the period since line to opening of communication with
Märklin-Interface with 1 msec accuracy.
■ OS/2: Trace facility added (see also "Appendix D. Trace facility"
on page 47), start and stop of trace via procedure call
mkltrace(). Output to and input from the Märklin-Interface is
traced. A trace-file formatting utility (MKLTRFMT.EXE) is added
to package. I have tried to add this trace facility also in the
DOS driver, but I did not cucceed so far. It is rather
complicated to use DOS facilities during interrupt handling
(tracing must be located in the com-port and timer interrupt
routines).
■ A procedure 'mklsleep' added to make your DOS-program 'friendly'
for some popular multitasking environments (such DOS-box of OS/2,
Desqview, Windows).
■ DOS: mklflush times out after 3 seconds when transmit buffer could
not be flushed.
■ Some bugs fixed:
- mklflush() of OS/2 version watched the INput in stead of OUTput
queue.
- DOS: DTR and RTS now turned off before finishing program.
0.9 released: March 1993
■ A 32-bits driver for OS/2 2.0+ (MARKLIN3.OBJ) has been added, with
same functionality as MARKLIN2, including the new features below!
■ 'MKLAPI' now also useable by programs translated with the
MicroSoft QuickBASIC compiler 4.5. Since QuickBASIC does not
allow underscores in names, all externally used names have been
changed, for example: mklopen() is now called mklopen(). The
C-language calling convention must be specified in the source (see
MARKLIN.INC), and the file LMARKLIN.OBJ should be used with LINK.
All function specifications have been changed, and additions made
for program development with MicroSoft QuickBASIC compiler 4.5.
■ mkltime() is not anymore an external variable, but a function
returning the value of the time, expressed in milliseconds, but
with the precision of the timer tick.
■ mklmsecs() now also a function returning the time, but in exact
milliseconds (DOS only).
■ With the OS/2 drivers, the transmissions in STOP-state (after
mklstop) may now be buffered in stead of discarded (until buffer
full, then discarded). This depends on the COM.SYS device
drivers, or replacements thereof.
■ After the first mklstop subsequent calls of mklstop are ignored
and nothing sent to the Märklin-Interface until mklgo has been
called.
───────────────────────────────────────────────────────────────────────────
Appendix A. Summary of changes 37
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
■ mklstop() and mklgo() now give a returncode (0 = OK, otherwise a
transmission problem exists).
■ Simple Switchpoint test program (incl c-source) added to MKLAPI
package.
■ Added counters for and a function mklstats() for statistical
purposes and debugging.
■ Polling optimised: a single 'reset after read S88' (192) is issued
after mklpoll() and mklgo(), subsequently only 'read group of n
S88s' (128+n) commands are sent periodically (previously both
commands were sent after each interval).
───────────────────────────────────────────────────────────────────────────
Appendix A. Summary of changes 38
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
APPENDIX B. MKLAPI INTERNALS
This appendix describes a number of design arguments for this driver and
explains decisions where a choice had to be made.
COMMUNICATIONS INTERFACE SPECIFICATION
| The Märklin-Interface contains a device driver level communication facility
| with between computer and Märklin-Interface, but with a rather high level
| interface for the application programmer. It contains many basic
| functions, that otherwise have to be programmed yourself. However, it
| enforces a specific organisation of your program and has some limitations.
| Some of the internals of the communications task are briefly explained to
| show why it works as it works now, and may prevent questions. On the other
| hand, it may trigger suggestions for changes! Feel free to go in
| discussion with me!
| Wiring Only the Read (RD), write (TD) and Clear-to-Send (CTS) lead
| are connected. Thus using DTR and RTS from the computer
| will have no effect of any kind and obviously DSR and DCD
| (sometimes also called CD or RLSD) will not be used by the
| Märklin-Interface Nevertheless DTR and RTS are set by the
| driver with mklopen(). This allows for the use of a
| break-out box and/or another computer in stead of the
| Märklin-Interface for debugging of your program (since a PC
| commmunications program usually needs these leads to be
| active). The driver itself works properly without the DSR
| and DCD leads.
| Speed The Märklin-Interface allows only 2400 bps, and 8-bits
| data, NO parity, and 2 stop bits. These are the built-in
| defaults of the driver, however a different speed can be
| specified at open-time (might be useful for test and
| debugging).
| FIFO So called FIFO hardware buffering, provided by the newer
| UART-chips (such as 16550 AFN) on asynchronous
| communication ports is handled as follows by the drivers:
| ■ The DOS-driver does not actively support FIFO-mode, but
| FIFO-support is in plan.
| ■ The OS/2-MKLAPI uses the facilities of the device driver
| COM[xx].SYS for operation of the COM-port. When FIFO is
| is active for the COM-port before opening, it is left
| active and uses this feature. Use the MODE-command to
| control this feature.
FIFO-mode may not provide a considerable improvement:
■ The Märklin-Interface operates strictly half-duplex, it
| is either in receive mode, or in transmit mode. During
| data transfer (either way) CTS is dropped while
| transmitting each command-byte and may remain low for a
───────────────────────────────────────────────────────────────────────────
Appendix B. MKLAPI Internals 39
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| 'considerable' time while command interpretation is in
| progress and S88-positions are being sent back to the
| computer. This does not suit very well with the FIFO
| for transmit buffering. It might be useful for receive,
| since in many cases at least 2 bytes are received per
| S88. being read. The support for this is in
| consideration.
| ■ Since the speed is 2400 bps, most systems can easily
| keep up with the non-buffered mode of operation. The
| highly effective interrupt handler of the DOS-driver may
| make the netto effect of reduced CPU-cycles for
| interrupt handling only minimal.
| But FIFO-mode may be helpful in a multitasking environment.
| Use the MODE command with BUFFER=ON, to activate it, when
| desired.
Output flow control The CTS signal is dropped by Märklin-Interface during
data transfer (during receive and transmit: the
Märklin-Interface is strictly half-duplex). The CTS signal
is used for 'hardware output flow control' from the
computer. So the transmit routines will not send data when
CTS is not high, but will automatically resume transmission
when CTS rises and the buffer contains any data to
transmit.
DOS Although not strictly needed, the DOS-version of the
Märklin-driver has the transmit interrupt (THRE) active to
be able to run the driver against a full-duplex interface
(with continuous CTS), such as another PC with a diagnostic
communications program. The transmit interrupt uses the
same code as the MSR interrupt.
For initial testing of programs without actually running a
model railroad, you could use a 'wrap-plug' to partially
simulate the Märklin-Interface. The RTS signal (raised by
the driver) is feeded back to CTS, so the driver is always
| able transmit.
| If also send and receive (genarlly pins 2 and 3) leads are
| wrapped back, then the transmitted data is treated as S88
| response. This may cause
Input flow control There is no form of input flow control allowed by the
Märklin-Interface: there is no way to signal the
Märklin-Interface to stop sending. This will not be a
problem for the driver, since there is enough buffering and
CPU-power to process the low volume input in time.
XON/XOFF flow control Not used. This type of flow-control is not supported
by the Märklin-Interface, since the commands for the
Märklin-Interface may contain these characters!
───────────────────────────────────────────────────────────────────────────
Appendix B. MKLAPI Internals 40
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
OS/2: The standard COM[xx].SYS of OS/2 allows simulated
XON/XOFF. A DosDevIOCtl-'XOFF' is issued to stop
transmitting buffered data when a 'stop'-command has to be
transmitted. A DosDevIOCtl-'XON' is issued when a
subsequent 'go'-command is issued.
Null stripping The OS/2 COM[xx].SYS allows null stripping. There are at
least 2 reasons for this feature not to be activated:
■ Märklin S88 encoder's may respond with all bits zero
■ Switch 256 is addressed as ASCII 0.
Command parsing The driver does not interpret the data it sends to the
Märklin-Interface. It means that it is completely the
responsibility of the mainline to ensure proper command
sequences.
Note: The driver does not send automatically a
switch-'relax' command (ASCII 32) after a switch command
(ASCII 33 or 34)! You may write a shell for Märklin
command syntax checking.
PROBLEMS WITH OS/2 COM[XX].SYS
The Com-port driver of some versions of OS/2 for non-PS/2 machines
(COM01.SYS) does have some known problems, such as:
■ READ and WRITE timout specifications cannot be changed from the built-in
default of 1 minute.
When encountering this kind of problems, I could recommend Gerry Rozema's
replacement driver for AT-type machines (COM16540.SYS, or COM16550.SYS, as
| appropriate for your system's COM-port). For OS/2 2.0 there is also a
| driver SIO.SYS by Ray Gwinn, that might be useful when having problems with
| the standard OS/2 2.0 drivers.
These alternative drivers are available on Bulletin Boards such as
PC-Square in The Netherlands (FIDO node 2:512/4, telephone 31.79.424107).
───────────────────────────────────────────────────────────────────────────
Appendix B. MKLAPI Internals 41
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
APPENDIX C. DESIGN NOTES AND TIPS
POLLING FACILITY
MULTITASKING
There are many situations in real-time programming, where you want the
system to do something for you, while in the meantime you would like to do
something else in the mainline (before the first piece of program
completes).
An example of this is reading sensor boxes. While you have to wait for the
response of the Märklin S88 encoder, you might want to update your screen,
read data from disk, or process keyboard input. In many sample programs
that I have seen, the wait is frequently done in the form of a short loop
(a for- or while-statement). This means that the processor is working, in
fact consuming cycles, while you cannot do anything (unless you make a more
'complicated' loop). And in many cases you have to experiment with this
loop to get the needed wait-interval (not too long and not too short).
Running the same program on a machine with a different processor-speed,
requires a change in the loop.
A solution for this is to have multiple programs to run simultaneously.
Executing multiple programs (tasks) in parallel is called multi-tasking.
Since we are generally dealing with a single micro processor, the tasks are
simultaneaously present in memory, but only 1 of them is actually
processing. There must be some mechanism to switch the processor between
the tasks.
Some operating environments have standard facilities for this (OS/2,
Windows), but DOS doesn't. Under DOS you have to do it yourself. By
intercepting hardware interupts, or the timer-tick interrupt it is possible
to implement a kind of task-switching.
The polling mechanism in the Märklin-driver is a form of multi-tasking.
For OS/2 it uses the standard OS/2 facilities (called multi-threading), for
DOS it uses the system timer to execute periodical actions independently
from the main-program, and also the hardware interrupts of the asynchronous
communications port to perform some communications work. So in fact there
are two 'extra' tasks in the polling mechanism:
■ Periodically send read-commands to the Märklin-Interface.
■ Receive the responses and put them in the appropriate place in the
sensor-array.
Although you don't have to bother about the polling mechanism, it does have
some influence on the design of your railroad control program. These
practical aspects are explained below.
───────────────────────────────────────────────────────────────────────────
Appendix C. Design Notes and Tips 42
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
BACKGROUND POLLING TASK
The driver generates read-sensor commands in the following way:
1. After polling is activated (with mklpoll(s)), periodically a sensor-read
command is transmitted.
2. The receive-part of the communications task is signalled that a response
from the Märklin-Interface should be expected, and for which S88 the
input is destined. The receive continues (or a read is re-issued) as
long as not all expected input is received, or an unexpected long time
had to be waited.
3. After processing the response, the system waits some time before issuing
a new poll.
4. Even if for some reason the previous poll did not finish within about
one sec, a new poll-command is issued (poll timeout).
5. If the transmit routine is in use by the mainline program (such as for
sending train-commands), polling is suspended for a short while (shorter
than the normal polling interval). After such 'slow-poll' situation,
normal polling intervals are respected again.
The Märklin-Interface documentation indicates that the average time to read
the last poll-response is between 45 and 300 milliseconds, depending on how
many Märklin S88 encoder's are being read. The polling task in the driver
uses a poll interval (time between receiving the last data and sending the
next poll-command) of about 100 msecs.
From 'life'-tests I have concluded:
■ The poll implemented interval is short enough to signal occupied
isolated sections of the railroad in time for most cases.
■ The poll interval is long enough to allow sending of many commands from
the mainline between the polls. To make this sure I also built a
priority mechanism in the polling routine: it waits with generating a
poll if another program uses mklputc() routine!
■ The frequency of the polls is low enough to ensure that not all CPU
cycles are spent on polling, in stead of 'real' work.
| Polling is implemented as follows:
| 1. After calling mklpoll() of mklgo() with a non-zero parametervalue a
| '192' byte is transmitted, meaning that the Interface will RESET the
| bits with next read-sensor commands.
| 2. Periodically a '128 + MAXSENSOR' byte, meaning that the Interface will
| report a group of sensors, up till the limit that was specified with the
| (latest) mklpoll() of mklgo().
───────────────────────────────────────────────────────────────────────────
Appendix C. Design Notes and Tips 43
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
Note: This mechanism is suitable for detection of occupied railroad
sections, whereby the sensor-bit is set again by the train (after being
read and reset by the Märklin-Interface) for example in the case of
contact-rails or isolated sections. As long as there is a pair of wheels
making contact, the sensor-bit is reported as 'set' (1).
You have to be careful with specifying more Märklin S88 encoder boxes in
the mklpoll() than you really have in your model railroad yard.
■ It is not useful, since the Märklin-Interface will return all zeroes for
not-connected Märklin S88 encoder's.
■ During the time the Märklin-Interface sends the responses to the
computer, no commands are accepted by the Interface.
So specifying more Märklin S88 encoders than really active will unnecessary
downgrade the responsiveness of your program. You might decide to stop
polling during processor-intensive work, or not to use polling at all.
Note:
■ This driver does not yet support physically reading of individual
Märklin S88 encoders.
■ It is also not possible to use polling with no-reset (command 128 in
stead of 192).
■ The driver will allow read-commands from the mainline, but will
intercept the response and not return them to the mainline! It
interpretes all responses if were caused by its own polling activity.
If polling is active the driver stores the input in the sensor array.
If polling is not active the OS/2 driver leaves input data in the buffer
of COM[xx].SYS, which will eventually fill-up! In either case it will
disturb the polling mechanism if is active or will be activated. So do
not send from your mainline commands that will cause the
Märklin-Interface to send data!
OS/2 AND DOS DIFFERENCES
Although all versions of this Märklin-driver offer a consistent application
programming interface for communication with the Märklin-Interface, it is
most likely that there will be differences between the programs using
either of them. Some of these differences might be:
■ When running in a multitasking environment, the program should give
other tasks the chance to run (yield the processor).
- With OS/2 other tasks will get some control automatically
(pre-emptive multi-tasking), but nevertheless the program should use
DosSleep() when it does not need the processor for some time.
- DOS: apart from the built-in multitasking of the Märklin-driver which
controls itself, you probably won't run other programs. In that case
| you will not have to release the processor.
| - When running a DOS-program under another multitasker (Windows,
───────────────────────────────────────────────────────────────────────────
Appendix C. Design Notes and Tips 44
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
| Desqview), periodic calls of mklsleep are recommended.
■ The OS/2 driver makes use of the standard multitasking (multithreading)
facilities and therefore should specify /MT for MicroSoft C-compiler
6.00a or use include-files from the \INCLUDE\MT directory when using
the IBM C/2 compiler 1.1, The different include-search might be
indicated with a compiler option (-I for most C-compilers).
The DOS driver should use the normal include directory.
■ The OS/2 driver requires the LARGE memory model, compiler options
| (/Alfu), and use the LLIBCMT (multitasking!) library for LINK. The
| DOS-version is for the SMALL (/AS) or LARGE memory model (/AL), use the
| resepctively the SLIBCE or LLIBCE library with LINK.
| ■ The standard OS/2-driver (COM[xx].SYS) will not accept new output data
| in stop-state, but will transmit possibly retained data (from before
| mklstop) after a call to 'mklgo'. Some alternative drivers (such as
| SIO.COM) do accept new data from mklputc, but keep it internally
| buffered. No more data is accepted when the buffer is full. After
| mklgo all buffered data, old and new, will be transmitted.
| The DOS-drivers refuse all new output data in stop-state.
■ It is an absolute must, that the Märklin-driver under DOS is terminated
with a call to mklclose() to de-activate the interrupts for com-port and
timer. Therefore it is recommended to use a routine to intercept Ctrl-C
or Ctrl-Break actions from the keyboard.
Under OS/2 this is not necessary: the system takes care of cleanup after
terminating a program, regularly or not.
In both cases it is recommended to direct the Ctrl-C signal to a
controlled finish of your railroad control program: you probably do not
want to terminate your program with uncontrolled running trains!
■ The display of information about the state of your railroad on the
computer screen will probably use different techniques, such as the way
cursor and color will be used:
1. OS/2: Presentation Manager (graphics)
2. DOS: Windows (graphics)
3. ANSI escape-sequences (compatible between OS/2 and DOS)
The sample program you'll receive after registration is a single source
for environments 1 and 3. My own programs are primarily for OS/2 and I
prefer to use the OS/2 facilities and those of the Program Development
Toolkit as good as possible. For instance I use VIO-routines for color
and cursor manipulation.
To be able to run my sample program under DOS, I included some extra
routines in the header-file. These routines translate color and cursor
manipulations with OS/2 VIO-calls into equivalent ANSI escape sequences.
When ANSI is active under DOS (with DEVICE=[path]\ANSI.SYS in
───────────────────────────────────────────────────────────────────────────
Appendix C. Design Notes and Tips 45
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
CONFIG.SYS), the visual effects are the same as with the OS/2 version.
When there is no possibility to use the same code for OS/2 and DOS, you
might consider using a compiler variable (with the -D compiler option) to
distinguish which pieces of codes are OS/2 or DOS specific. See for an
example the MAKE-files in the MARKLIN package.
───────────────────────────────────────────────────────────────────────────
Appendix C. Design Notes and Tips 46
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
APPENDIX D. TRACE FACILITY
TRACE RECORDS
The trace facility produces the following records (8 bytes each):
long int timestamp; /* value of mkltime */
int fl:1, /* flag: 0=output, 1=input */
nn:7, /* (in start-of-trace record) trace source */
/* MKLAPI: DOS = 1; OS/2 1.x = 2; OS/2 2.x = 3 */
sw:8; /* S88 box number on input */
char c1, /* first character */
c2; /* second character */
The first record after starting a trace contains 0xFF as first and second
character.
SAMPLE
The output of the trace formatting program MKLTRFMT will look like:
time I/O cmd data description
------------ --- --- ---- --------------------------------------
45.050 Start of trace (MKLAPI OS/2 1.x)
+0.045 O 1A 13 Loc 19 speed 10 Funktion=ON
+0.350 O 22 3F switchpoint 63: branch off
+0.760 O 20 switchpoint release
+1.850 O C0 read S88's with reset
+4.850 O 82 read S88 1 t/m 2
+4.881 I 1801 S88 1 ON=4,5,16
+4.881 I 090E S88 2 ON=,8,13,14,15
+5.000 O 61 STOP
This is not a complete trace, just some parts to show the essentials.
MKLTRFMT.EXE is a 'family mode' application: it will run under OS/2 and
DOS. No parameters are required, but you may specify the input filename
[including path] if your trace is in another directory or named other than
MKLAPI.TRC, which is the default (output filename of MKLAPI).
MKLTRFMT writes the output to 'stdout', which is normally the computer
display. But the output may be redirected to your printer or to a file.
So you could use for example the command:
MKLTRFMT >TRACE.FMT
───────────────────────────────────────────────────────────────────────────
Appendix D. Trace facility 47
Märklin-Interface driver
───────────────────────────────────────────────────────────────────────────
so that you could look afterwards with a text editor or file browse utility
in TRACE.FMT for the formatted trace.
───────────────────────────────────────────────────────────────────────────
Appendix D. Trace facility 48