> ## Appendix B. Using XTC

> Subsystems that desire a reliable data stream or datagram service will want to use XTC services: A transport layer over the target communications (TC) link layer.

> XTC is based on some of the ideas of TCP, with some features deleted because of the point-point nature of the TC. Either the target or the DeviceMate can actively open a connection or listen for a connection. The actual XTC library is almost identical on both ends. Since XTC is mainly symmetric, the rest of this document applies equally to the target or the DeviceMate unit, unless otherwise noted. The word "peer" is used to denote the target processor (TP) or the DeviceMate unit (DMU) when the distinction is not important.

> An established connection is referred to as a "channel," in order to distinguish it from a TCP "socket." Any subsystem (out of the 255 allowed) can make use of XTC services. The subsystem "subtypes" are used as selectors for a particular channel instance. One subtype, 0xFF, is reserved as a "broadcast" to all channels belonging to the given subsystem. 0x00 through 0x7F are reserved for direct subsystem use. This leaves a maximum of 127 channels per subsystem, with channel numbers ranging from 0x80 through 0xFE. This is a potentially large number of resources which may not be able to be supported simultaneously on the peer. Available resources will be limited to a configured number of channels. Each channel endpoint (analogous to TCP sockets) will specify channel state, buffers, RTT estimates and any other information associated with the channel. Each subsystem will have its own pool of channels so that each subsystem has a minimum guaranteed number of endpoints.

> When an subsystem initializes, it will send a "broadcast" NEG (negotiate) flag to reset any resources on the peer. All NEG packets contain a reason code and other negotiated information. The initial NEG broadcast specifies a subsystem initialization code. The peer will respond with a NEG (with initialize-acknowledge code) so that the originator knows that the peer is available and synchronized.

> NEG can also be sent to individual channels, in which case it embodies some of the properties of the TCP RST (reset) flag, but can also specify a reason code and other diagnostic information. Any protocol error will result in a NEG flag being sent in order to renegotiate the channel.

> The application and subtype fields from the TC header are part of the logical XTC header. The data portion of each TC packet contains a 5-byte header which contains flags, receive window, sequence number and acknowledgment number. SEQ/ACK numbers are 16 bits each. Flags and window are compressed into a single byte. There are 4 bits for the possible flags (SYN, ACK, FIN, NEG) and the available receive window is encoded in the remaining 4 bits which is interpreted as `floor(log2(windowsize))`. If the window size is zero, then a zero code is used. The peer must always interpret a window field of zero as meaning a closed window (not a window of 1). This logarithmic coding of available window provides fine resolution when the window is nearly closed, but very coarse resolution when it is half- to fully open. To compensate for this, each peer keeps track of the right edge of the window, using the fact that no peer is allowed to contract the window edge to the left.

> ### B.1 Library Support

> XTC clients (i.e.,subsystems that use XTC) must include in their code:

>     #use "dm_xtc.lib" (for Rabbit-based targets)
>     #include "dm_xtc.h"   (for nonRabbit-based targets)

> and in the companion subsystem on the DeviceMate unit there must appear the statement:

>     #use "targetproc_xtc.lib"

> ### B.2 Data Structures

> Each XTC client (both on the target and on the DeviceMate) must declare one instance of a `XTCApp` structure and at least one instance of a `XTCChan` structure. The latter structure must be initialized to zero by the subsystem. The `XTCApp` struct must have some of its fields initialized to appropriate values before the data structure is registered. Examples of doing this are in the subsystems that use XTC: `dm_var.lib`, `targetproc_var.lib`, etc.

> #### B.2.1 Registration

> On the DeviceMate unit, for each subsystem that uses XTC, an `XTCApp` structure must be registered using `targetproc_xtc_register()` before calling `targetproc_init()`.

> On the target, for each subsystem that uses XTC, an `XTCApp` structure must be registered using `devmate_xtc_register()` before calling `devmate_init()`.

> #### B.2.2 XTCApp Structure

> This data structure is defined in `tc_xtc.lib`. It contains fields that must be filled in by any subsystem wishing to use XTC services.

>     typedef struct _XTCApp{

> ### // Fields to set up before calling the register function

>        uint8 appno;         // Application code
>        uint8 numchans;      // Number of channels in following array
>        uint16 txbufsize;    // Transmit buffer size w/out TC header
>        uint16 rxbufsize;    // Receive buffer size w/out TC header
>        XTCChan * chans;     // Channel array

> ### // Fields initialized by the subsystem's _xxxx_init().

>        uint8 numtxbufs;     // # of transmit buffers (usually 1,
>                             // maybe 2 for high speed)
>        uint8 numrxbufs;     // Number of receive buffers
>        uint16 reqpacing;    // Our requested pacing (sent to peer).
>        uint8 aflags;        // Subsystem flags as follows:
>     #define XTC_AF_READY 0x01      // Subsystem is ready to establish
>                                    // channels with peer
>     #define XTC_AF_BCASTNEG 0x02   // Broadcast NEG, waiting for
>                                    // a response
>     #define XTC_AF_SERVER 0x80    // This is a DeviceMate app struct                                // (else TP)
>     #define XTC_AF_CONTROL 0x40  // DeviceMate unit: automatically
>                                  //   listen on channel 0 (control).
>                                  // Target processor: automatically
>                                  //   active open channel 0.
>                                  // If this flag is set in both, then
>                                  // the control channel will be opened
>                                  // whenever devmate_xtc_ready()
>                                  // or targetproc_xtc_ready()
>                                  // returns true.
>     #ifdef FUNCPTR_PROTOTYPES

>        void (*tc_handler)(_xtcappptr app, _TCHeader * hdr, faraddr_t data);

>     #else

>        void (*tc_handler)();     // Handler for app subtypes that
>                                  // are not XTC
>     #endif

> ### // the rest of the fields in this structure are internal or
> // initialized by devmate_xtc_init() or targetproc_xtc_init().

>               .
>               .
>               .
>     } XTCApp;

> #### B.2.3 XTC Configuration Macro

> #### TC_MAX_XTC_APPS

> Defaults to 4, which allows for the currently defined set of subsystems that use XTC services, namely TCP/IP, file system, web page variables and e-mail. This macro may be defined before the inclusion of `dm_xtc.lib`.

> ### B.3 XTC API

> ## _devmate_xtc_init

>     void _devmate_xtc_init(void);

> ### Description

> Initialize (or re-initialize) use of XTC layer.

> ### Library

> dm_xtc.lib (Rabbit-based targets)
> dm_xtc.c (nonRabbit-based targets)

> ## devmate_xtc_ready

>     int devmate_xtc_ready(XTCApp * app);

> ### Description

> Initiate a connection at the subsystem level, and test the connectivity state of the XTC subsystem. Returns positive when ready, 0 when trying to establish connectivity, or -1 if connectivity cannot be established.

> This function initiates the process of establishing connectivity, by sending a broadcast NEG packet to the peer. If the peer responds with a broadcast NEG then the subsystem is considered to be connectable and the function returns positive. If the peer responds with an "app not registered" system message, then it is assumed that the subsystem is not defined on the peer, and -1 is returned. (This may be because the DeviceMate unit has not registered the same subsystem number.) Otherwise zero is returned and the subsystem should keep trying.

> This function does not call `devmate_tick(),` so the subsystem should spin on this function using e.g.,

>     while (!devmate_xtc_ready(&MyApp)) devmate_tick();

> ### Parameters

> #### app

> This is a pointer to the subsystem's state structure.

> ### Return Value

> ³ `1`: Connection is established
> `0`: Trying to establish connectivity
> `-1`: Connectivity could not be established

> ### Library

> dm_xtc.lib (Rabbit-based targets)
> dm_xtc.c (nonRabbit-based targets)

> ## devmate_xtc_register

>     int devmate_xtc_register(XTCApp * app, uint16 rxlen, uint16 txlen);

> ### Description

> This function must be called before `devmate_init()`, once only for each subsystem that uses XTC. The caller should initialize the necessary fields in the `XTCApp` struct, including the channel array as follows: either memset the entire channel struct to zero (in which case the parameters will be used to allocate suitable buffers etc.) or memset the channel to zero except for the rx and/or tx xbuf. If either rx or tx xbuf has a non-zero `blen` field, then it is assumed to be already initialized. rxlen/txlen must be at least 2 greater than the MSS.

> ### Parameters

> #### app

> This is a pointer to the subsystem's state structure.

> #### rxlen

> Default buffer size for receive buffer

> #### txlen

> Default buffer size for transmit buffer

> ### Return Value

> `0`: Success
> `-1`: Error, too many subsystems
> `-2`/`-3`: Buffer size error

> ### Library

> dm_xtc.lib (Rabbit-based targets)
> dm_xtc.c (nonRabbit-based targets)

> ## xtc_abort

>     int xtc_abort(XTCApp * app, uint8 chan);

> ### Description

> Force a channel to close, informing the peer if there is an active session. This generally causes a NEG packet to be sent, and forces the channel to the closed state. Both sides of the session will receive a "reset" reason code if they test the channel using `xtc_error()`.

> If a session is established, but is immediately aborted with no transfer of data, then `xtc_estab()` will return -1, `xtc_error()` will return `XTC_NEGCODE_RESET`, and there will be no readable data.

> ### Parameters

> #### app

> This is a pointer to the subsystem's state structure.

> #### chan

> The particular connection that will be forcibly closed

> ### Return Value

> `0`

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_aread

>     int xtc_aread(XTCApp * app, uint8 chan, char * data, uint16 len);

> ### Description

> Read queued data, but only if the specified length of data is immediately available in the receive buffer.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> #### data

> Location of data to read

> #### len

> Number of bytes of data to read

> ### Return Value

> `0`: Not `len` amount of data available to read
> `-1`: Receive buffer not large enough to hold `len` amount of data
> `-2`: Channel is not readable
> `len`: Data was successfully removed from the receive queue

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_areadp

>     int xtc_areadp(XTCApp * app, uint8 chan, faraddr_t data, uint16 len);

> Same as `xtc_aread()`, except uses xmem address for data.

> ## xtc_awrite

>     int xtc_awrite(XTCApp * app, uint8 chan, char * data, uint16 len);

> ### Description

> Queue data for transmission, but only if there is sufficient space in the transmit buffer. The `a' stands for "atomic."

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> #### data

> Location of data to write

> #### len

> Number of bytes of data to write

> ### Return Value

> `0`: Data cannot be queued
> `-1`: Transmit buffer not large enough
> `-2`: Channel is not writable
> `len`: Data successfully queued

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_awritep

>     int xtc_awritep(XTCApp * app, uint8 chan, faraddr_t data, uint16 len);

> Same as `xtc_awrite()`, except uses xmem address for data.

> ## xtc_close

>     int xtc_close(XTCApp * app, uint8 chan);

> ### Description

> Indicate that the channel is closed for writing. The channel will generally still be readable until the peer also issues `xtc_close()`. If the other side never closes its side of the channel, then it will be necessary to use `xtc_abort()` to force the channel closed. If the channel is passively opened, with no session established, then it will be quietly closed.

> The return code may be safely ignored: it returns non-zero only if `xtc_close()` has already been called for this channel, or the channel does not exist.

> Note that the channel may be closed yet readable, i.e. the subsystem did not finish reading data. `xtc_readable()` is a better test for a closed channel when it is important that all data be read

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> ### Return Value

> `!0`: `xtc_close()` was already called or the channel does not exist

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_closed

>     int xtc_closed(XTCApp * app, uint8 chan);

> ### Description

> Returns non-zero only if the channel is not defined, or fully closed. After calling `xtc_close()`, the subsystem can spin on this function to wait for complete termination of the session.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> ### Return Value

> `0`: Channel is fully closed
> `!0`: Channel is not defined, or it is not fully closed

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_error

>     int xtc_error(XTCApp * app, uint8 chan);

> ### Description

> Returns the most recent error code from the channel. The code will be zero if the channel has successfully closed after a previous session, or is currently open. Otherwise, a non-zero error code may be returned in the case that the channel was reset (NEG) by the peer. The actual error code will be one of a documented set of "official" error codes, or, if not one of these, will be a diagnostic code to assist developers.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> ### Return Value

> See "Description"

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_estab

>     int xtc_estab(XTCApp * app, uint8 chan);

> ### Description

> This function checks the status of the connection. After an active or passive open, the subsystem should spin on `xtc_estab()` waiting for a non-zero return value. After `xtc_estab()` returns non-zero, the channel state should be examined using the other status functions. It is possible for `xtc_estab()`to return non-zero for a closed channel. This means that the channel became active, but was immediately reset by the peer. In this case, the return code will be negative, or this can be subsequently be tested using `xtc_error()`.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> ### Return Value

> `0`: Channel has been opened (active or passive) but not yet ready to transfer data

> `-1`: Channel closed and an error occurred in the previous session (`xtc_error()` will return a non-zero error code in this case)

> `>0`: Channel is readable, or successfully closed

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_flush

>     int xtc_flush(XTCApp * app, uint8 chan);

> ### Description

> Forces XTC to send the queued transmit data as soon as possible. Normally, there is no need to call this function, as `xtc_write()` will send data at the optimum point in time considering link efficiency. However, sometimes the subsystem needs the timeliest response, in which case this function can be used. Note that XTC uses the Nagle algorithm by default, however this can be overridden by a channel flag or by use of `xtc_flush()`.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> ### Return Value

> `0`: Queued data was transmitted
> `-1`: Channel not writable

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_listen

>     int xtc_listen(XTCApp * app, uint8 chan, int (*handler)());

> ### Description

> Passively open the specified channel. After passively opening a channel, the subsystem must spin on `xtc_estab()`. When `xtc_estab()` returns non-zero, a session is either currently open, or a transaction was received, or the channel was reset by the peer. At this point, any results should be garnered (or the channel may be used in streaming mode) then the channel may be closed and re-used with a new `xtc_listen()` call after `xtc_closed()` returns true.

> The handler function that may be passed as the third parameter has the following prototype:

>     int handler(XTCApp * app, XTCChan * c, xbuf * tx, long buf, uint16 len);

> `app` and `c` are pointers to the subsystem and channel contexts (which may not need to be accessed if the handler is devoted to a single channel). `tx` is a pointer to the transmit buffer, in which a response is to be placed. `buf` and `len` specify the physical address and length of the request data.

> A response is simple to add: the function `xbuf_append()` is called with `tx`, and the response data:

>     int xbuf_append(xbuf * cb, long data, uint16 dlen);

> The handler function should return the result from `xbuf_append()`, i.e. the number of bytes successfully queued, or -1 if an error occurred. If -1 is returned, the session is aborted so that the peer can tell (by examining the result of `xtc_error()`) that the transaction failed.

> The response should not be longer than `app->mss`. If it is longer, then the response will not be sent in a single segment. This should be transparent to the receiving peer apart from the longer time necessary, however, the intention of transaction mode is to allow quick request/response processing.

> If no handler function is specified (i.e. `NULL` is passed as the third parameter to `xtc_listen()`), a default response of zero data is generated. The request data can still be obtained in the mainline `xtc_listen()` loop, after `xtc_estab()` returns non-zero. If not actually read, the request data is discarded when `xtc_listen()` is next called.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> #### handler

> Pointer to function that will handle transaction mode requests. If this pointer is `NULL`, requests will still be accepted, but responses will contain no data.

> ### Return Value

> `0`: Channel was opened passively
> `-1`: Error, e.g., channel was already open or the channel number was not configured

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_open

>     int xtc_open(XTCApp * app, uint8 chan);

> ### Description

> Open a new channel.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure

> #### chan

> The XTC connection

> ### Return Value

> `0`: Success
> `-1`: Channel already open or doesn't exist

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_opts

>     int xtc_opts(XTCApp * app, uint8 chan, uint8 optnum, uint16 value)

> ### Description

> Specify channel or subsystem options. `optnum` specifies the option number (`XTC_OPT_*`) and `value` is a value appropriate for the specified option. Most options apply for the life of the subsystem, but some may only apply to the next or current session. Some options may apply to the subsystem as a whole, others to the specific channel number.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> #### optnum

> The option number. Actual options are:

> `XTC_OPT_SERVER`: subsystem to act as the DeviceMate

> `XTC_OPT_CONTROL`: subsystem automatically listens on control channel 0, if server; otherwise it actively opens the control channel

> `XTC_OPT_NONAG` : channel to bypass Nagle algorithm

> All options currently take a boolean parameter value: 0 = turn setting off, else turn it on.

> #### value

> An appropriate value for the specified option

> ### Return Value

> `0`: Option set successfully
> `-1`: Error

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_preread

>     int xtc_preread(XTCApp * app, uint8 chan, char * data, uint16 len);

> Same as `xtc_read()`, except that the data is not removed from the queue. This is a macro which invokes `xtc_prereadp()`.

> ## xtc_prereadp

>     int xtc_prereadp(XTCApp * app, uint8 chan, faraddr_t data, uint16 len);

> Same as `xtc_readp()`, except that the data is not removed from the queue.

> ## xtc_read

>     int xtc_read(XTCApp * app, uint8 chan, char * data, uint16 len);

> ### Description

> Read queued data, to a maximum of `len` bytes.

> Returns from 0 to len, or -1 if channel not in a readable state. A channel may be readable when closed, and indeed should not be re-opened until all queued data have been read, however if opened before that then the queued data will be discarded.

> If data is NULL, then the data is merely removed from the queue.

> This is a macro which invokes `xtc_readp()`.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> #### data

> Pointer to data to read

> #### len

> Number of bytes

> ### Return Value

> ³ `0`: Number of bytes read
> `-1`: Channel not readable

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_readable

>     int xtc_readable(XTCApp * app, uint8 chan);

> ### Description

> This function returns positive if the channel is currently readable. This means that there is either unread data in the receive buffer, or that the channel is still open and able to receive more data from the peer. A channel can be readable even after it is closed. Any unread data in the receive buffer is only discarded when the channel is re-opened.

> The return value also indicates the amount of data in the receive buffer. The number of bytes that may be read immediately (by calling `xtc_read()`) is obtained by subtracting 1 from the return value of this function.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> ### Return Value

> `0`: Channel is not in a readable state.

> `>0`: Channel is currently readable, subtracting 1 from this return value is the number of bytes that may be read immediately (by calling `xtc_read()`).

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_readp

>     int xtc_readp(XTCApp * app, uint8 chan, faraddr_t data, uint16 len);

> Same as `xtc_read()`, except uses xmem address for data.

> ## xtc_writable

>     int xtc_writable(XTCApp * app, uint8 chan);

> ### Description

> This function returns positive if the channel is currently writable. This means that the channel is open (but not necessarily established), and `xtc_close()` has not yet been called.

> The return value also indicates the number of bytes that may be immediately written to the transmit buffer (by calling `xtc_write()`). The amount of free space in the buffer is calculated by subtracting 1 from the return value.

> Note that it is possible to write to a channel that is not established. There is a limit to the amount of data which may be buffered, however the buffered data will be sent immediately when a connection is established.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> ### Return Value

> `0`: Channel is not in a writable state.

> `>0`: Channel is currently writable, this return value is the number of bytes that may be immediately written to the transmit buffer (by calling `xtc_write()`).

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_write

>     int xtc_write(XTCApp * app, uint8 chan, char * data, uint16 len)

> ### Description

> Queue data for transmission. The length parameter is defined as unsigned, however in practice the specified length should be less than or equal to `INT_MAX` (32767) since the return value, which reflects the amount actually written, is signed.

> If `xtc_writable()`-1 is positive, then that amount of data is guaranteed to be accepted by `xtc_write()` if there are no intervening XTC calls.

> `xtc_write()` may be called immediately after `xtc_open()`, providing the amount of data is less than or equal to `app->mss.`

> This is a macro which invokes `xtc_writep()`.

> ### Parameters

> #### app

> Pointer to the subsystem's state structure.

> #### chan

> The XTC connection

> #### data

> Pointer to data to read

> #### len

> Number of bytes to queue

> ### Return Value

> ³ `0`: Number of bytes queued (maximum number of bytes is `len`)
> `-1`: Channel not writable

> ### Library

> tc_xtc.lib (Rabbit-based targets)
> tc_xtc.c (nonRabbit-based targets)

> ## xtc_writep

>     int xtc_writep(XTCApp * app, uint8 chan, faraddr_t data, uint16 len);

> Same as `xtc_write()`, except uses xmem address for data.

Z-World http://www.zworld.com Voice: (530) 757-3737 FAX: (530) 757-3792 sales@zworld.com