> ## Chapter 3. DeviceMate Feature Set

> The DeviceMate feature set is implemented by certain software subsystems.

> The subsystems are:

> - E-Mail
> - File System
> - Message Logging
> - Remote Program Download (Rabbit-based targets only)
> - Watchdogs
> - TCP and UDP Sockets
> - Web Page Variables

> This chapter is about the subsystems running on the target: their configuration and an overview of their APIs. The configuration of the companion subsystems that run on the DeviceMate are discussed in chapter 4 starting on page 29.

> #### Library Support for Target Devices

> An application program running on the target device must ask for all subsystems it wants to use. This is done using the macros shown in the table below.

> Subsystem Name | Request for Service Macro | Libraries for Rabbit-Based Targets
> E-mail | `USE_TC_SMTP` | dm_smtp.lib
> File System | `USE_TC_FS` | dm_fs.lib
> Message Logging | `USE_TC_LOG` | dm_log.lib
> Remote Program Download | `USE_TC_LOADER` | None
> TCP/IP | `USE_TC_TCPIP` | dm_tcp.lib
> Watchdogs | `USE_TC_WD` | dm_wd.lib
> Web Page Variables | `USE_TC_VAR` | dm_var.lib

> The macro must be defined in the application program. For example:

>     #define USE_TC_VAR        // requesting the web page variables subsystem

> After the request for service macros are defined, the application code must include one of the following statements:

>     #use "tc_conf.lib"        // for Rabbit-based targets
>     #include "tc_conf.h"      // for nonRabbit-based targets

> NOTE | In the rest of this chapter, instead of citing the files needed for both Rabbit and nonRabbit targets, only the `.lib` file will be mentioned.

> The `tc_conf.lib` file uses the request for service macros to determine which subsystem libraries to include. For example if `USE_TC_VAR` is defined, then `tc_conf.lib` pulls in `dm_var.lib`.

> The remote program download macro, `USE_TC_LOADER`, does not work the same way as the other request for service macros. There is no `dm_*.lib` file associated with it because the target is not running an application when the remote download feature is being used. If the downloaded program is a DeviceMate application, then including the statement `#define` `USE_TC_LOADER` in its code will configure the correct serial port for continued communication with the DMU while the downloaded program is running.

> #### Serial Port Macros

> The sample programs use serial port D by default. This can be changed by defining a serial port macro in the application code. The macros are considered in the order they appear below, e.g., if the macro for serial port B is defined, then serial port B is used unless `DEVMATE_SERA` is defined; the others (C and D) are not considered even if they are defined.

> `DEVMATE_SERA`: Define this macro with `#define` to use serial port A.

> `DEVMATE_SERB`: Define this macro with `#define` to use serial port B.

> `DEVMATE_SERC`: Define this macro with `#define` to use serial port C.

> `DEVMATE_SERD`: Define this macro with `#define` to use serial port D.

> If the Development Board that came with the DeviceMate Development Kit is being used with the RS232 connector, then there are some hard-wired restrictions regarding serial ports. Please see the DeviceMate Getting Started Manual for more information.

> Please note that serial port A is used by the programming cable. This is also the serial port used by the target used when the DeviceMate is remotely downloading a program to it.

> The speed of data transfer through the serial port defaults to 115200 bps. This can be overwritten by the macro `DEVMATE_SERIAL_SPEED`. This value must match `TARGETPROC_SERIAL_SPEED` on the DeviceMate side.

> #### Required Function Calls for Target Applications

> There are 2 functions that must be called by any application running on the embedded target device. A call to `devmate_init()` is required to initialize target communications with the DeviceMate unit. To process packets and otherwise drive the system, repeated calls to `devmate_tick()` must be made. This is usually done in a tight, endless loop:

>     for (;;) {
>        devmate_tick();
>             .
>             .
>             .
>     }

> #### Using µC/OS-II

> The maximum number of events supported by µC/OS-II is defined by the macro `OS_MAX_EVENTS`. This macro includes the number of semaphores, message mailboxes and any message queues being used by µC/OS-II. Two must be added to `OS_MAX_EVENTS` for each of the DeviceMate subsystems that are used; also, one must be added if any of the included subsystems use XTC.

> In the application code, follow the define of `OS_MAX_EVENTS` with a `#use "ucos2.lib"` statement. This ensures that the definition supplied outside of the library is used, rather than the default in the library. Also the inclusion of `ucos2.lib` must happen before the inclusion of any DeviceMate libraries. `OSInit()` and `OSStart()` must be called by the application to initialize and start the operating system.

> For more information on the Dynamic C implementation of µC/OS-II please see the Dynamic C User's Manual. See sample programs `var_ucos.c` and `fs_ucos.c` for examples of using DeviceMate subsystems and µC/OS-II.

> NOTE | µC/OS-II is not available in the DeviceMate Special Edition of Dynamic C. It is available in Dynamic C Premier. The same is true for sample programs `var_ucos.c` and `fs_ucos.c`.

> ### 3.1 TCP/IP Subsystem

> This subsystem makes both TCP and UDP sockets available to the target. The target can actively or passively open a TCP socket via the DeviceMate; the target can read and write the socket; the target can close or abort the socket; the target can check socket status and can ask whether or not an error has occurred.

> This API allows TCP/IP functionality, including UDP and DNS lookups, to be accessed from the target. The target may send and receive data from an open UDP socket.

> The TCP/IP subsystem on the DeviceMate side runs a complete TCP/IP stack.

> #### 3.1.1 Configuration Macros for TCP/IP Subsystem

> These macros may be defined in the application running on the target before the inclusion of the library `tc_conf.lib`.

> #### DEVMATE_TCP_DEBUG

> Defaults to not defined. If defined, then Dynamic C debugging is turned on for all functions herein.

> #### DEVMATE_TCP_MAXCHANS

> Defaults to 4. This is the maximum number of XTC channels allowed.

> #### DEVMATE_TCP_MAXRESOLVE

> Defaults to 1. Specifies the maximum number of concurrent DNS (Domain Name Server) lookups. Set to 0 if DNS is not required.

> #### DEVMATE_TCP_MAXSOCK

> Defaults to 4. Maximum number of sockets (implemented as XTC "channels") that are allowed. Generally, this limits the number of sockets on the target since the target is assumed to be more resource-constrained than the DeviceMate. The actual maximum is determined by the minimum value configured on the target or DeviceMate unit. Note that this value does not include the so-called "control" channel (channel 0). Available socket numbers run from 1 to `DEVMATE_TCP_MAXCHANS` inclusive. The function `devmate_tcp_maxsocket()` returns the actual negotiated maximum socket number.

> #### DEVMATE_TCP_NUMRXBUF

> Defaults to 3. Specifies the number of target communications receive buffers. A higher number allows greater performance, at the expense of additional memory usage.

> #### DEVMATE_TCP_NUMTXBUF

> Defaults to 1. Specifies the number of target communications transmit buffers. Do not set higher than 2. 2 is only necessary if the highest possible speed is required.

> #### DEVMATE_TCP_TCBUFSIZE

> Defaults to 133, which allows for 128-byte data packets plus the 5-byte XTC header.

> #### DEVMATE_TCP_XTCBUFSIZE

> Defaults to 256. Must be greater than or equal to `DEVMATE_TCP_TCBUFSIZE` - 5.

> #### 3.1.2 API Functions for TCP/IP Subsystem

> The functions in `dm_tcp.lib` are nonblocking, i.e. they all set some internal state, but return immediately (possibly without actually accomplishing their intended goal). Thus, it is usually necessary to call the same function multiple times in order to complete the action, a necessity noted in the description of the function.

> Most of the functions require a "socket" parameter. Unlike the native `dcrtcp.lib` TCP stack, where socket parameters are pointers to structures, sockets in this library are simply small numbers that are selected by the applications. Note that the socket number space is shared between TCP and UDP sockets. For applicatons with resource constraints, sockets should be closed when not in use. Allocation of socket numbers is entirely the application's responsibility.

> Only a limited number of sockets may be in use at any one time. This number is configured in `tc_tcp.lib` via the `DEVMATE_TCP_MAXSOCK` define. This number defaults to 4, but may be overridden by the application. The total number of sockets is the minimum of the number configured for the target and the DeviceMate unit. This minimum number is available by calling the `devmate_tcp_maxsocket()` function, after `devmate_sock_init()`. The returned number may be less than `DEVMATE_TCP_MAXSOCK` if the DeviceMate unit does not support as many sockets as the target.

> #### 3.1.2.1 Functions Grouped by Task

> The TCP/IP API functions below are linked to their full description in Chapter 5 "Function Reference for Target Applications." Here the functions are listed to show what is available.

> #### Initialize connection to DeviceMate:

>     devmate_sock_init()
>     devmate_tcp_status()

> #### Open TCP or UDP sockets:

>     devmate_tcp_open()
>     devmate_tcp_listen()
>     devmate_udp_open()

> #### Check socket status:

>     devmate_tcp_isestablished()
>     devmate_tcp_error()
>     devmate_tcp_readable()
>     devmate_tcp_writable()
>     devmate_tcp_isclosed()

> #### Read or write TCP (stream) data:

>     devmate_tcp_fastread()
>     devmate_tcp_preread()
>     devmate_tcp_fastwrite()

> #### Close socket:

>     devmate_tcp_close()
>     devmate_tcp_abort()
>     devmate_udp_close()

> #### Read or write UDP (packet) data:

>     devmate_udp_sendto()
>     devmate_udp_send()
>     devmate_udp_recvfrom()
>     devmate_udp_recvdata()

> #### Miscellaneous:

>     devmate_ip_resolve()
>     devmate_tcp_maxsocket()

> #### 3.1.3 TCP and UDP Sample Program

> Could the perpetual flashing of "12:00" on VCRs and microwave ovens be a thing of the past? Yes, if their controller can be made to talk to a DeviceMate!

> Specifically, in the sample program `tctcp_time.c`, the TCP/UDP tunneling facility of the DeviceMate is used to connect to a sequence of Time servers. The target handles the Time protocol, which is extremely simple, leaving the DeviceMate to handle the details of the ethernet/internet connection.

> This is the basis for something useful. The nominated server(s) are queried for their UTC time. (UTC is the international time standard.) The result from each server is adjusted for the network delay (assumed to be half of the round-trip time). If there were more than 2 servers, then the servers whose times were "most distant" from the average of the others are discarded, until a minimum of 2 or half the original number of servers remain. The final computed time is the average of the remaining servers. If all remaining servers are within about 60 seconds of each other, then the discarding process is cut short.

> If no servers can be found, the current real-time clock is used (`SEC_TIMER`).

> When the time is computed, the target processor then opens its own Time and Daytime servers (RFC868 and RFC867). You can then telnet to port 13 on this processor to obtain the current time, or at least its best guess at the time.

> Note that UDP is used to query the servers, but the target allows both TCP and UDP queries to its server sockets.

> #### 3.1.3.1 Running tctcp_time.c

> The source code for this sample program is available in the `samples\dmtarget` folder. For brevity's sake, the code is not reproduced here. It is recommended that users run this sample program to learn more about it.

> #### 3.1.3.2 Porting Note

> This demo (`tctcp_time.c`) is written for a Rabbit-based target. However, since DeviceMate functionality is specifically intended to be platform-independent, this program should work (with minor modifications) on other processors. The main areas to examine are:

> - `SEC_TIMER` - define this to be a macro which returns the number of seconds since some convenient epoch. The Rabbit 2000 uses 1980. The RFC specifies midnight January first 1900. Redefine the `EPOCH_DIFF` symbol to be the correct number of seconds between the epochs. Must be a `uint32` value.
> - `MS_TIMER` - should be a macro returning the number of milliseconds since an arbitrary epoch (e.g. bootup time). Should be a `uint16` or `uint32` value. The actual resolution does not have to be 1ms. 1/10 second would be OK.
> - `#use` - change to appropriate `#include`(s).
> - `format_timestamp()` - change this function to convert timestamps to a readable format.
> - `main()` - examine the DeviceMate setup etc.

> ### 3.2 E-Mail Subsystem

> The DeviceMate can be configured to send e-mail on behalf of the target. There is a target-side library to handle the SMTP protocol and connect to a mail server through a DeviceMate running TCP/IP services.

> The library `dm_smtp.lib` is a modification of the regular `smtp.lib` in Dynamic C. The API is nearly identical. The functions are described in chapter 5 starting on page 74.

> #### 3.2.1 E-Mail Sample Program

> This sample program illustrates the e-mail subsystem. The e-mail subsystem is a layer on top of the TCP/IP subsystem. This requires that a call to initialize the TCP/IP subsystem be made for any application that uses the e-mail subsystem.

> #### Program Name: smtp.c

>     #define USE_TC_SMTP

>     #ifdef CC_VER
>        #memmap xmem
>        #use "tc_conf.lib"
>     #else
>        #include "tc_conf.h"
>        #include <stdio.h>
>     #endif

>     #define MY_SMTP_SERVER "mail.somewhere.org"
>     #define MY_SMTP_DOMAIN "somewhere.org"

>     #define FROM "Devmate@somewhere.org"
>     #define TO  "nobody@nowhere.org,everybody@everywhere.org"
>     #define SUBJECT "test mail"

>     int main(){
>        char message[256];
>        devmate_init();

>        printf("devmate_sock_init: %d\n",
>          devmate_sock_init(NULL, NULL, NULL, NULL, NULL, NULL)
>          );

>        devmate_smtp_setserver(MY_SMTP_SERVER);
>        devmate_smtp_setdomain(MY_SMTP_DOMAIN);

>        strcpy(message,
>          "Warning!\r\nTemperature in the computer room over 40 deg C!"
>          );

>        devmate_smtp_sendmail(TO, FROM, SUBJECT, message);

>        while (devmate_smtp_mailtick() == DM_SMTP_PENDING);

>        if (devmate_smtp_status() == DM_SMTP_SUCCESS)
>           printf("Message sent\n");
>        else
>           printf("Error sending message\n");
>        while (1)
>           devmate_tick();
>     }

> #### 3.2.2 Configuration Macros for E-Mail Subsystem

> These macros may be defined in the application running on the target before the inclusion of the library `tc_conf.lib`.

> #### DEVMATE_SMTP_DOMAIN

> The domain name to state when connecting to an SMTP server. This defaults to "" (none). Some SMTP servers require a client to declare it's domain name when connecting though, so this macro should be defined to an appropriate domain name.

> #### DEVMATE_SMTP_SERVER

> Defaults to "" (none). String constant defining the default SMTP server. This may be overridden at runtime using `devmate_smtp_setserver()`.

> #### DEVMATE_SMTP_SOCK

> Defaults to 2. Specifies the TCP/IP subsystem socket number to use when calling `devmate_smtp_mailtick()`. This may be overridden at runtime using `devmate_smtp_setsocket()`.

> #### DEVMATE_SMTP_TIMEOUT

> Defaults to 300. Specifies timeout for sending mail, in seconds. Whenever a response is received from the mail server, this timeout is reset.

> ### 3.3 Web Page Variables Subsystem

> The target sends requests to the DeviceMate to create a variable or update a variable's value using the API in `dm_var.lib`. The variable is stored on the DeviceMate and is displayed whenever a web page containing the variable is displayed.

> #### 3.3.1 Using the File System Subsystem

> The file system subsystem may be used to upload the files that contain variable references. This will be convenient for uploading the initial HTML file to the DeviceMate unit. After that, the web page variable subsystem can be used to update the variables in the HTML file without having to upload the entire file.

> #### 3.3.2 Displaying the Variables on Web Pages

> Variables can be updated on web pages using SSI commands in the HTML code. SSI commands are an extension of the HTML comment command. The web page's HTML code must contain a line similar to:

>     <!--#echo var="variable_name" -->

> This expression will be replaced by the value of `variable_name` by the web server when the page is requested by a web browser.

> #### 3.3.3 Frequency of Variable Updates

> It is important to limit the rate of variable updates. Updating too frequently may flood the serial line. Notice that in `var.c`, an update is limited to once every 10 seconds. The updates should occur as frequently as the information is needed on the DeviceMate side, as opposed to the frequency with which new values may become available on the target side.

> #### 3.3.4 Variables Sample Program

> If `TC_USE_VAR` is defined on the DeviceMate unit and the target, then the application `samples\dmunit\devmate.c` runs an HTTP server that accepts variable updates from the target that is running `samples\dmtarget\var.c`. The variables can be viewed by a web browser by requesting `var.shtml` at the DeviceMate's IP address. Do a refresh from the browser to see the updates.

> #### Program Name: var.c

>     #define DEVMATE_VAR_MAXVARS 10
>     #define USE_TC_VAR

>     #ifdef CC_VER
>        #memmap xmem
>        #use "tc_conf.lib"
>     #else
>        #include "tc_conf.h"
>        #include <stdio.h>
>     #endif

>     int main(void){
>        long starttime, oldseconds, seconds;
>        char strvar[20];
>        float floatvar;

>        devmate_init();

>        starttime = SEC_TIMER;
>        oldseconds = 0;
>        seconds = 0;
>        strcpy(strvar, "Good bunny.");
>        floatvar = 42.42;

>        devmate_var_add("seconds", &seconds, VAR_INT32, "%ld", 0, VAR_SERVER_HTTP);

>        devmate_var_add("string", strvar, VAR_STRING, "%s", 20, VAR_SERVER_HTTP);

>        devmate_var_add("float", &floatvar, VAR_FLOAT32, "%f", 0, VAR_SERVER_HTTP);

>        for (;;) {
>           devmate_tick();
>           seconds = SEC_TIMER - starttime;
>           if (((seconds % 10) == 0) && (seconds > oldseconds)) {
>              oldseconds = seconds;
>              devmate_var_update("seconds");
>              devmate_var_update("string");
>              devmate_var_update("float");
>              floatvar += 3.14159;
>              if (strvar[0] == 'G')
>                 strcpy(strvar, "Bad bunny.");
>              else
>                 strcpy(strvar, "Good bunny.");
>           }
>        }
>     }

> #### 3.3.5 Configuration Macros for Variables Subsystem

> These macros may be defined in the application running on the target before the inclusion of the library `tc_conf.lib`.

> #### DEVMATE_VAR_DEBUG

> This macro is not defined by default. If defined, then debugging information will be output as the program executes.

> #### DEVMATE_VAR_MAXDATA

> Defaults to 32. This defines the maximum length of the data (or contents) for a variable.

> #### DEVMATE_VAR_MAXFORMAT

> Defaults to 8. This defines the maximum length of the printf-style format specifier for a variable, including the `NULL` terminator.

> #### DEVMATE_VAR_MAXNAME

> Defaults to 8. This defines the maximum length of a variable name, including the `NULL` terminator. This macro determines the maximum length of the argument `char` `*` `name` taken by many of the API functions.

> #### DEVMATE_VAR_MAXVARS

> Defaults to 10. Specifies the number of variables for which the target processor will keep information. This limits the number of variables that you can add. Note that the DeviceMate may not accept as many variables as specified here. See SSPEC_MAXSPEC for more information.

> #### DEVMATE_VAR_NUMRXBUFS

> The number of variable receive buffers on the target. Defaults to 2.

> #### DEVMATE_VAR_NUMTXBUFS

> The number of variable transmit buffers on the target. Defaults to 1.

> #### DEVMATE_VAR_TCBUFSIZE

> Defaults to 133, which allows for 128-byte data packets plus the 5-byte XTC header.

> #### DEVMATE_VAR_XTCBUFSIZE

> This defaults to 128. This is used for XTC streams as the default buffer size for XTC.

> ### 3.4 File System Subsystem

> The file system feature allows the embedded target to off load the running of the file system to the DeviceMate. The target can create and delete files on the DeviceMate where the files can be added to the `zserver.lib` spec table and thereby accessed over the Internet. For information on `zserver.lib`, please see the Dynamic C TCP/IP User's Manual.

> #### 3.4.1 File System Configuration

> The Dynamic C file system (FS2) must be set up on the DeviceMate before the file system subsystem can be used by the target. If you are using one of the the sample program supplied by Z-World that makes use of the file system subsystem (e.g., `devmate_fs.c`) you will probably have to make some code changes to it to configure FS2 according to your needs.

> #### 3.4.2 File System Sample Program

> The application `samples\dmtarget\` `fs_tiny.c` makes minimal use of the file system subsystem. It will contact the DeviceMate and upload some files to it that will be made available to a web server on the DeviceMate. After running this application, the web page should be visible at:

>     http://[devmate_ip]/index.html

> #### Program Name: fs_tiny.c

>     #ximport "samples/tcpip/http/pages/static.html" index_html
>     #ximport "samples/tcpip/http/pages/rabbit1.gif" rabbit1_gif

>     // #define FORMAT
>     #define USE_TC_FS
>     #use "tc_conf.lib"
>     DMFile file;

>     // Send a file to the DeviceMate, and return it's file ID
>     int send_file(long data, char *name){
>        auto int retval;
>        auto long big_len;
>        auto int length, offset, writesize;
>     #define BUFSIZE 64
>        auto char buf[BUFSIZE];
>        auto FNumber id;
>        if(TC_SUCCESS == devmate_fs_idlookupB(&file, name, &id, 0))
>           devmate_fs_deleteB(&file, id, 0);
>        if(xmem2root((char *)&big_len, data, 4))
>           exit(1);
>        length = (int)big_len;
>        offset = 0;

>        printf("Opening file '%s'...\n",name);

>        while(TC_PENDING == (retval = devmate_fs_open(&file, 0, name, TC_FS_FLAGS_NEWID)))

>           devmate_tick();
>        if(TC_SUCCESS != retval)
>           exit(2);
>        printf("Sending the file...\n");
>        while(offset < length) {
>           writesize = length - offset;
>           if(writesize > BUFSIZE)
>              writesize = BUFSIZE;
>           if(xmem2root(buf, data + 4 + offset, writesize))
>              exit(3);
>           retval = devmate_fs_append(&file, buf, writesize);
>           if(-1 == retval)
>              exit(4);
>           offset += retval;
>           devmate_tick();
>        }
>        printf("Send complete - closing the file...\n");
>        while(TC_PENDING == (retval = devmate_fs_close(&file,&id)))
>           devmate_tick();
>        if(TC_SUCCESS != retval)
>           exit(5);
>        printf("File '%s' sent correctly!\n",name);
>        return id;
>     }

> #### Program Name: fs_tiny.c (continued)

>     void main(){
>        int rv;
>        long timeout;
>        FNumber index_file, logo_file, test_id;

>        serDclose();
>        devmate_init();

>     #ifdef FORMAT
>        rv = devmate_fs_syncB(&file,TC_FS_FORMAT,0);
>     #else
>        rv = devmate_fs_syncB(&file,0,0);
>     #endif
>        if(TC_SUCCESS != rv) {
>           printf("Error in init!\n");
>           exit(-1);
>        } else {
>           printf("INIT was successfull!\n");
>        }
>        /*
>         * Send some data
>         */
>        index_file = send_file(index_html,"/index.html");
>        logo_file = send_file(rabbit1_gif,"/rabbit1.gif");

>        printf("All done!\n");
>     }

> #### 3.4.2.1 Blocking vs. NonBlocking Functions

> In a working environment, blocking functions are almost never the way to go. They are resource hogs. Their one advantage is that they simplify the code and if the holding on to resources is not an issue they are useful alternatives to their nonblocking counterparts. The sample program above, `fs_tiny.c`, uses blocking functions. Look at `samples\dmtarget\fs_gen.c` to see an example using the file system with nonblocking functions.

> ### 3.5 Message Logging Subsystem

> This feature allows the target controller to log variable-length messages to the DeviceMate unit. All records are time-stamped and sent immediately to the DeviceMate for storage.

> The message logging subsystem uses XTC services.

> #### 3.5.1 Message Filtering

> All messages have a priority code and a facility number. The logging subsystem can key on either or both of these when determining if a message should be logged. The default condition is to allow all messages to be logged. This can be changed by API functions devmate_log_setfacilityfilter() and devmate_log_setpriorityfilter().

> Priority codes are 3 bits. There are no defined priority codes. You may wish to use the standard "syslog" encoding as follows:

> 0: Emergency; 1: Alert; 2: Critical; 3: General errors; 4: Warning; 5: Notice; 6: Informational; 7: Debug

> Facility numbers are 5 bits. There are no defined facility numbers. Facilities are intended to be used as a way to separate messages by categories. For example, an application may define a facility number for analog inputs and another facility number for analog outputs. Up to 32 facilities may be defined.

> #### 3.5.2 Message Logging Sample Program

> The application `samples\dmtarget\log100.c` demonstrates the use of DeviceMate to perform logging. It sends 100 "random" log messages to various destinations.

> #### Program Name: log100.c

>     #define USE_TC_LOG
>     #ifdef CC_VER
>        #memmap xmem
>        #use "tc_conf.lib"
>     #else
>        #include "tc_conf.h"
>        #include <stdio.h>
>     #endif

>     int main(){
>        auto int i, rc;
>        auto uint16 timer;
>        auto char buf[116];
>     #define NUM_TEST_MESSAGES 3
>        static const char * test_messages[NUM_TEST_MESSAGES] =
>           {"Z-World","Rabbit Semiconductor","Talk Async Serial!"};
>     #define NUM_TEST_INTERVALS 5
>        static const uint16 test_intervals[NUM_TEST_INTERVALS] =
>           {1000, 100, 100, 300, 700};
>        devmate_init(); // Initialize target communications
>     reopen_log:
>        devmate_log_init();
>        while (!devmate_log_status()) devmate_tick();
>        for (i = 0; i < 100; i++) { // send test messages
>           sprintf(buf, "Log message %d.  %s", i, test_messages[i%NUM_TEST_MESSAGES]);
>           // alternate between facility 0 and 1
>           rc = devmate_log_put((i&1)<<3, buf, strlen(buf));
>           switch (rc) {
>              case 0: // normal
>                 break;
>              case 1: // not buffered, trying again in 400 ms
>                 timer = (uint16)MS_TIMER + 400;
>                 while ((int16)((uint16)MS_TIMER - timer) < 0)
>                    devmate_tick();
>                 i--;
>                 continue;
>              case -2: // message too long
>                 break;
>              default: // logging unavailable, attempt to re-establish
>                 goto reopen_log;
>           }
>           timer = (uint16)MS_TIMER + test_intervals[i%NUM_TEST_INTERVALS];
>           while ((int16)((uint16)MS_TIMER - timer) < 0)
>              devmate_tick();
>        }
>        while (1)
>           devmate_tick();
>        return 0;
>     }

> The `samples\dmunit\logxtc.c` program must be running on the DeviceMate unit to give `log100.c` someone to talk to.

> #### 3.5.3 Data Types

> Log data may take any form defined in the application. The data is sent by the message logging subsystem in binary format, i.e., a null terminator is not needed. Messages consist of a binary string of length 0 to 115 bytes.

> #### 3.5.4 Storage of Logging Messages

> Logging messages may be stored in several places. On the DeviceMate unit they may be stored in an xmem buffer or in one or more files in FS2. (If FS2 and Flash memory are used, remember that Flash memory is limited by how many times it can be updated and should be used only when updates occur at most every couple of minutes.) Messages can also be logged to stdout.

> In the sample program `log100.c`, messages alternate between facility 0 and 1. The default mapping maps facility 0 to the xmem buffer since the application running on the DeviceMate unit (`logxtc.c`) has defined `LOG_USE_XMEM`. The default mapping maps facility 1 to the stdio window.

> The storage options are determined by the application running on the DeviceMate unit. If FS2 is used, it must be set up on the DeviceMate prior to running an application on the target that makes use of it.

> #### 3.5.5 Message Logging Configuration Macros

> #### DEVMATE_LOG_TCBUFSIZE

> This is the maximum number of bytes for the TC buffer. Defaults to 128+5

> #### DEVMATE_LOG_XTCBUFSIZE

> This is the maximum number of bytes for the XTC buffer. Defaults to 256

> #### DEVMATE_LOG_NUMRXBUF

> This is the maximum number of message logging receive buffers on the target. Defaults to 1.

> #### DEVMATE_LOG_NUMTXBUF

> This is the maximum number of message logging transmit buffers on the target. Defaults to 1.

> ### 3.6 Software Watchdogs Subsystem

> Software watchdogs are basically decrementing timers that can alert the outside world that something is wrong. They minimize the amount of time that a target can stay in an unknown state by requiring the target to periodically communicate that everything is okay. The watchdog subsystem API allows the target to create and hit watchdogs.

> XTC services are not used by this subsystem.

> #### 3.6.1 Watchdog Sample Program

> This program is intended to be run on the target. It sets up a number of watchdogs on the DeviceMate and keeps hitting them. See `\samples\dmunit\wd.c` for the DeviceMate program intended to run with this program.

> #### Program Name: wd.c

>     #define USE_TC_WD
>     #ifdef CC_VER          // if this is Dynamic C
>        #memmap xmem
>        #use "tc_conf.lib"
>     #else                 // else this is a nonRabbit target

>        #include "tc_conf.h"
>        #include <stdio.h>

>     #endif

>     int main(void)
>     {
>        int rc;
>        uint16 nexthit;
>        devmate_init();

>        // Setup watchdogs. Wait 5 seconds for response.
>        if ((rc = devmate_wd_init(5000)) != DEVMATE_WD_ACKED) {
>           printf("devmate_wd_init: failed %d\n", rc);
>           exit(19);
>        }
>        // Add watchdog called FIDO. Wait 5 seconds for response.
>        // Watchdog must be hit every 12 sec.
>        rc = devmate_wd_add("FIDO", 12000, 5000);
>        if (rc != DEVMATE_WD_ACKED) {
>           printf("devmate_wd_add: unexpected response %d\n", rc);
>           exit(20);
>        }
>        for(;;) {
>           devmate_tick();
>           // Hit watchdog every 2 seconds
>           if ((int16)((uint16)MS_TIMER - nexthit) > 0) {
>              devmate_wd_hit("FIDO");
>              nexthit = (uint16)MS_TIMER + 2000;
>           }
>        }
>     }

> #### 3.6.2 Watchdog Subsystem Configurable Variables

> These macros may be defined in the application running on the target before the inclusion of the library `tc_conf.lib`.

> #### DEVMATE_WD_MAXPENDING

> This is the maximum number of concurrent watchdogs on the target. Defaults to 12.

> #### DEVMATE_WD_RETRANSTIME

> Amount of time to wait before retransmitting a request. Defaults to 500 ms.

> #### DEVMATE_WD_HITTIME

> Minimum amount of time to wait before transmitting a watchdog hit. Defaults to 200 ms.

> #### DEVMATE_TXSPEED

> Minimum amount of time to wait before transmitting another watchdog packet. Defaults to 50 ms.

> #### DEVMATE_WD_NUMTXBUF

> This is the maximum number of transmit buffers available to the watchdog subsystem on the target. Default is 2.

> #### DEVMATE_WD_NUMRXBUF

> This is the maximum number of receive buffers available to the watchdog subsystem on the target. Default is 2.

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