Skip to content

WTP: Getting Started

Qifan Lu edited this page Oct 2, 2017 · 2 revisions

WTP: Getting Started

This tutorial will help you get started with the WTP API.
For the design, details and issues of WTP please refer to other wiki articles.

Create WTP Endpoints

The first step to use WTP is to create WTP endpoints. For the server (computer) side, we create an instance of the WTPServer class:

from wtp import WTPServer

# Create WTP server endpoint
server = WTPServer(
    antennas=[1],
    n_tags_per_report=1,
)

In the demo code shown above, we create a WTP server endpoint that accepts incoming WTP connections through antenna 1 on the RFID reader and receives 1 tag report each time from the reader.

To start the WTP server, call WTPServer.start() with the IP address and (optionally) the port of the reader:

# Connect to RFID reader and start
server.start("192.168.1.13")

As for the WISP (client) side, we declare the endpoint variable and initialize it with wtp_init():

wtp_t client;

//Initialize client WTP endpoint
wtp_init(
    &client,
    //EPC data memory
    epc_data_mem,
    //EPC data memory size
    EPC_DATA_MEM_SIZE,
    //Read memory
    read_mem,
    //BlockWrite memory
    blockwrite_mem,
    //Initial sliding window size
    64,
    //Timeout
    10,
    //Buffer size for transmit control
    200,
    //Buffer size for receiving control
    200,
    //Capacity of sending messages
    5,
    //Capacity of receiving messages
    5
);

Hook the RFID Loop

The WTP client library provided three hook functions: wtp_before_do_rfid(), wtp_load_read_mem() and wtp_handle_blockwrite(). You need to call these functions when specific RFID event happens:

//Read and BlockWrite flag
bool read_flag = false;
bool blockwrite_flag = false;

//Read callback
void read_callback(void) {
    read_flag = true;
}

//BlockWrite callback
void blockwrite_callback(void) {
    blockwrite_flag = true;
}
//Register Read and BlockWrite callback
WISP_registerCallback_READ(read_callback);
WISP_registerCallback_BLOCKWRITE(blockwrite_callback);

while (true) {
    //Call "wtp_before_do_rfid" before doing RFID
    wtp_before_do_rfid(&client);

    //Do RFID
    WISP_doRFID();

    //Call "wtp_load_read_mem" after RFID Read
    if (read_flag) {
        wtp_load_read_mem(&client);
        read_flag = false;
    }
    //Call "wtp_handle_blockwrite" after RFID BlockWrite
    if (blockwrite_flag) {
        wtp_handle_blockwrite(&client);
        blockwrite_flag = false;
    }
}

In theory, we can directly call wtp_load_read_mem() inside read_callback() and call wtp_handle_blockwrite() inside blockwrite_callback(). But since these two functions aren't optimized and take a long time to run, they can cause the WISP RFID routines to fail, so now we only set up flags inside the Read and BlockWrite callback and call the WTP hook functions outside the WISP RFID routines.

Open and Accept Connection

With the client endpoint we already created, the next step is to connect to the server side. This is done with wtp_connect():

WIO_CALLBACK(on_connected) {
    //Do anything you want after the connection is fully opened
    //...

    return WIO_OK;
}
//Add connected event callback
wtp_on_event(&client, WTP_EVENT_OPEN, NULL, on_connected);

//Connect to WTP server
wtp_connect(&client);

The demo client code above registers a callback for the connection open event, and then starts to connect to the server side. The event will be triggered when both the upstream and the downstream connection is opened, and the callback will then be invoked.

For the server side, it handles every new incoming WTP connection (or client) through the server connect event callback:

@server.on("connect")
def on_connect(connection):
    # Print WISP ID
    print("New client: %d" % connection.wisp_id)
    # Do whatever you want with the connection
    # ...

Send and Receive Data

Now that a bidirectional connection has been open for both sides, it's time to send and receive data between the WISP and the computer. Let's first send some data from the computer to the WISP:

# Send callback
def send_cb(_):
    print("Send succeeded!")

# Send data to WISP
connection.send(b"12345").addCallback(send_cb)

Function WTPConnection.send() takes a bytes-like object and sends its content to the WISP side. Because the sending process is asynchronous, it returns a Twisted Deferred object that will be resolved when the client side reports that the whole message is fully sent.

To receive the message at the WISP side, we use wtp_recv():

//Received bytes counter
uint16_t n_recv_bytes = 0;

WIO_CALLBACK(on_recv) {
    //Received data is wrapped inside a WIO buffer
    wio_buf_t* buf = (wio_buf_t*)result;

    //Update counter
    n_recv_bytes += buf->size;

    return WIO_OK;
}
//Receive data from server
wtp_recv(&client, NULL, on_recv);

The process is similar when we send data from WISP to computer, except we use wtp_send() at the client side and WTPConnection.recv() at the server side:

WIO_CALLBACK(on_sent) {
    //Do whatever you want here after the data is sent
    //...

    return WIO_OK;
}
//Send data to server
wtp_send(&client, "abcde", 5, NULL, on_sent);
# Keeps receiving and printing data from client
def recv_cb(msg_data):
    print("Received %s" % msg_data)
    connection.recv().addCallback(recv_cb)

# Kick start
connection.recv().addCallback(recv_cb)