Remote Access Protocol

Release 1.1 July 19, 2006
Copyright ©1989 through 2005. All Rights Reserved - Ample Technology

Introduction

The Remote Access Protocol, or RAP, allows for remote control and configuration of AmplePower products via either a computer or another AmplePower product. Throughout this manual, the system being remotely controlled is referred to as the target and the system doing the remote control is referred to as the host.

Information is communicated between the systems in packets of ascii text. All packets are terminated by a newline character (ascii value 0x0A, commonly represented as the '\n' character).

Note that carriage returns are simply ignored if a terminal emulator running on the host sends a carriage return ('\r') followed by a newline ('\n') to terminate a line. The target will always terminate packets with a newline only.

In the packet descriptions, a sequence of characters in angle brackets is only a symbolic representation of that portion of the packet. The angle brackets are not part of the actual packet. For example, to query the value of the 'b1v' variable, '<name>' is simply replaced with 'b1v'.

All communication is initiated by the host system. The host sends a request packet and waits for the target to respond with either a response packet or an error packet. If the target is unable to fulfill the request, an error packet is returned.

Source code for an example packet parser can be obtained from Ample Technology upon request.

Serial Port Configuration

The serial port configuration parameters are listed in Table 3.

To avoid dropped characters during packet transfers to the target, the host should insert a small delay (nominally 5 milliseconds) after sending each character.

After a packet has been sent to the target, the host should wait for a reply from the target before sending the next packet.

It is possible to send multiple packets as a batch by simply ignoring the reply from the target and inserting a delay (nominally 50-100 milliseconds) between packets. The idea here is to allow scripting of the packets via a simple text file that can be sent directly to the serial port with a terminal emulator (HyperTerminal on Windows, or minicom on Linux). A downside of this approach is that packet errors may not be caught by the host.

Error Packet Format

If an error occurs while the target system is processing a packet, the response will be:

E<nn>\n

where <nn> is a two digit, hexadecimal error code. Possible error codes are listed in Table 2.

Error packets do not include a CRC.

Data Packet Format

Data packets can be either requests or responses. In either case, the format of a data packet is:

$<data>#<crc>\n

where $ denotes the start of the packet, <data> is the packet's data, # marks the end of the data and <crc> is an optional 16 bit Cyclic Redundancy Checksum (CRC). The newline character terminates the transmission. The <data> part of the packet should not contain the $, # or newline characters.

If the <crc> is present, it must be exactly 4 hexadecimal digits (case is ignored). The target will generate an error if the CRC is invalid. The CRC calculation will include the leading $ and trailing # characters in addition to the <data> portion of the packet.

If the host wishes to use CRC's for packet transmission, the C function shown in the Example CRC16 Function section can be used to calculate the CRC value. An example of using that function is shown in the Example CRC16 Usage section.

The target will always generate the CRC when sending data packets.

The various data packet types are summarized in Table 1. A detailed description of request packet types and the expected responses is given in the following sections of this manual.

The Object Dictionary

The target system contains a database of objects which is referred to as the dictionary. The objects within the dictionary are either variables or executable functions. All accessible variable objects are readable, while a subset of those are writable.

All objects are referenced by either name (<name>) or index (<idx>). Accessing an object by index is more efficient for the target system, but the indices are not guaranteed to be invariant from one firmware version to the next. Object names will be consistent across firmware updates.

Every reply from the target will include both the index and the name of the object. This is done to allow multiple target systems on a network to all reply to a single broadcast request (by name) and have all the replies be unique via embedding of a node id in the index.

The index (<idx>) part of a target response is five hexadecimal digits in big-endian byte order. The first two digits (aka the MSB) represent a node number and the last three digits (aka the LSB) represent the dictionary index within the node. In a single node system, the node value will always be zero.

For brevity, only dictionary access requests made by name are shown in the discussions which follow. In all cases, the same access request can be made by replacing '<name>' with '%<idx>', where the index is a 5 digit, zero padded, hexadecimal number.

Querying an Object's Data Type

Why does the host need to know about data types? So it can program setpoints that match the rules for the conversion functions embedded with the variable in the dictionary. These rules are enforced to cut down on user input errors.

The type information also supplies meaning to some variables beyond their numerical value. For instance, an 8-bit variable may be a simple boolean that matches a yes/no answer to a configuration question. Here a yes is represented by a one value and a zero indicates no.

Other variables represent states within finite state machine logic, where their numerical value indicates the present state of the machine.

Finally, other variables are bit fields, or masks, where each bit in the mask indicates a particular condition.

To get data type information, the host sends:

$?t<name>#

The target replies with:

$?t<idx>=<name>:<t>,<b>,<p>,<d>#

with this significance:
$\bullet$ <t> is the object type ...
r - object is a readable variable;
w - object is a writable variable; or
f - object is an executable function.
$\bullet$ <b> is the size in bits (decimal integer).
$\bullet$ <p> is a polyglot of information ...
s - variable is signed;
u - variable is unsigned;
b - variable is a boolean;
v - variable is state vector.
m - variable is bit field/mask; or
t - variable is text string.
$\bullet$ <d> is the number of acceptable decimal points, typically 1 or 2.

Note: If an object is a function, then the remainder of the type information is that of the return value for the function.

Tip: The host system can build up it's own (name, index, type) table for all objects in the dictionary by querying object types in a loop starting with index zero and incrementing the index until the target returns an `Invalid Index' error code. The host would need to rebuild it's table after a firmware update in the target to re-map names to indices.

Querying an Object's Description

Every object in the target dictionary has both a short and a long description string associated with it.

To request the short description string, the host sends:

$d<name>#

The target responds with:

$d<idx>=<name>:<len>,<str>#

where <len> is a hexadecimal value in big-endian format which specifies the length (in bytes) of the <str> part of the packet.

Note that no terminating zero is sent with the string and <len> does not include one either. This holds for all strings transferred via the RAP protocol.

To request the long description string, the host sends:

$D<name>#

The target responds with (format is the same as for the short description):

$D<idx>=<name>:<len>,<str>#

Long descriptions are intended as help for a given variable and are used for that purpose with the user interface via terminal emulation. In that user interface, short descriptions are used as a terse description for the variable and are usually concatenated with the value for that variable when displayed.

Querying a Variable's Value

The value of a variable is requested using the following format:

$?v<name>#

The target responds with:

$?v<idx>=<name>:<val>#

The format of <val> depends on the type of the object. For text string variables, <val> will be in the form '<len>,<str>'. For bit field or mask variables, <val> will be a hexadecimal value in big-endian byte order. For all other variable types, <val> will be a decimal number, possibly having a decimal point.

Querying a Mask Variable's Information

Bit fields or masks have a text description associated with each bit in the mask. The description for any bit can be obtained by sending a query with one bit set.

The host sends the string:

$?m<name>:<mask>#

where <mask> is a hexadecimal number.

The target replies with the string.

$?m<idx>=<name>,<mask>:<len>,<str>#

where <len> is a hexadecimal value in big-endian format which specifies the length (in bytes) of the <str> part of the packet. A request for a mask without a text description will return a zero length.

Querying a State Vectors's Information

State variable objects have a text description associated with numeric values of the variable. The description for any value can be obtained by sending a query with that value.

The host sends the string:

$?S<name>:<state>#

where <state> is a decimal number.

The target replies with the string.

$?S<idx>=<name>,<state>:<len>,<str>#

where <len> is a hexadecimal value in big-endian format which specifies the length (in bytes) of the <str> part of the packet. A request for a state vector without a text description will return a zero length.

Setting a Variable's Value

To set a variable's value, host sends the string:

$s<name>:<val>#

The target replies with the same string.

$s<idx>=<name>:<val>#

The decimal point precision is enforced by the target according to the variable's data type specification. An error is returned if the precision does not match the specification.

Executing a Function Call

Some names belong to functions, i.e. `start_engine'. The host can instruct the target system to execute a function by sending:

$e<name>#

The target responds with:

$e<idx>=<name>:<res>#

where <res> is the result returned by the function.

If parameters are required for the function they are passed as a comma separated list after the name of the function:

$e<name>:<arg1>,...,<argN>#

The target responds with:

$e<idx>=<name>,<arg1>,...,<argN>:<res>#

Example CRC16 Function

uint16_t
update_crc16 (uint16_t crc, uint16_t data)                        
{                                                                 
    int i;

    for (i = 8; i; i--)
    {
        if ((data ^ crc) & 0x0001)
            crc = (crc >> 1) ^ 0xA001;
        else
            crc >>= 1;
        data >>= 1;
    }
    return crc;
}

Example CRC16 Usage

#include <stdio.h>
#include <inttypes.h>

struct tc_t {
    uint16_t exp; /* Expected CRC value. */
    uint8_t *buf; /* The test string. */
};

static struct tc_t tests[] = {
    {0x35c0, "M"},
    {0xff01, "T"},
    {0x23b6, "THE"},
    {0xb96e, "THE,QUICK,BROWN,FOX,"
             "0123456789"},
    {0, NULL}
};

int
main (int argc, char ** argv)
{
    uint16_t crc16;
    uint8_t *ptr;
    struct tc_t *tt = tests;

    while (tt->buf)
    {
        crc16 = 0;
        ptr = tt->buf;

        while (*ptr)
        {
            crc16 = update_crc16 (crc16,
                                  *ptr);
            ptr++;
        }
        printf ("crc of \"%s\"\n",
                tt->buf);
        printf ("    crc16 = 0x%04X ",
                crc16);
        printf (": expected = 0x%04X\n",
                tt->exp);

        tt++;
    }
    return 0;
}

Tables


Table 1: Summary of packet types
Request Reply Description


?v<name>
?v%<idx>

?v<idx>=<name>:<val> Query object's value.


?d<name>
?d%<idx>

?d<idx>=<name>:<len>,<str> Query object's short description.


?D<name>
?D%<idx>

?D<idx>=<name>:<len>,<str> Query objects's long description.


?t<name>
?t%<idx>

?t<idx>=<name>:<t>,<b>,<p>,<d> Query object's data type.


?m<name>:<mask>
?m%<idx>:<mask>

?m<idx>=<name>,<mask>:<len>,<str> Query mask variable's information.


?S<name>:<state>
?S%<idx>:<state>

?S<idx>=<name>,<state>:<len>,<str> Query state variable's information.


s<name>:<val>
s%<idx>:<val>

s<idx>=<name>:<val> Set variable to value.


e<name>
e%<idx>

e<idx>=<name>:<res> Execute a function on the target system.


e<name>:<arg1>,...,<argN>
e%<idx>:<arg1>,...,<argN>

e<idx>=<name>,<arg1>,...,<argN>:<res> Execute a function with arguments.








Table 2: Error Codes
Error Code Description
E01 Invalid CRC.
E02 Name is not in the dictionary.
E03 Object is not writable.
E04 Object is not a function.
E05 Programmed value is out of range.
E06 Decimal point error.
E07 Only decimal digits accepted.
E08 Malformed Packet.
E09 Invalid Query.
E0A Invalid Operation.
E0B Variable is not a mask type.
E0C Variable is not a state vector.
E0D Invalid Index.
E0E Invalid State.
E0F Invalid Mask.
E10 Input too long.
E11 Programmer Bug.
E12 Not Implemented.



Table 3: Serial Port Configuration
Parameter Value
Speed 19200
Parity None
Data Bits 8
Stop Bits 1
Hardware Flow Control Off
Software Flow Control Off


Notes:

Ample Power products are manufactured by Ample Technology, 2442 NW Market St., #43, Seattle, WA 98107 - USA

\epsfig{file=global/images/ps/AP.EPS,width=1.25in}


Visit http://www.amplepower.com