cetic / 6lbr

A deployment-ready 6LoWPAN Border Router solution based on Contiki
github.com/cetic/6lbr/wiki
Other
338 stars 195 forks source link

Using 6lbr-demo CoAP - Blockwise #191

Open msolters opened 8 years ago

msolters commented 8 years ago

Hi @laurentderu,

I thought maybe this would be a less obnoxious way for me to ask about the details of the CETIC CoAP library located inside the 6lbr-demo/apps/coap folder.

Having referenced examples/er-rest-examples, I now have some basic semblance of an idea how the CoAP library may make client requests.

  //  (1) Set the IP of our CoAP server to bbbb::1
  uip_ipaddr_t server_ipaddr;
  uip_ip6addr(server_ipaddr, 0xbbbb, 0, 0, 0, 0, 0, 0, 0x1);

  static coap_packet_t request[1];

  coap_init_engine();

  //  (2) Construct a CoAP message: confirmable; POST coap://[bbbb::1]/test/me
  char *test_url = "/test/me";
  coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0);
  coap_set_header_uri_path(request, test_url);

  //  (3) Post payload should read "hello world"
  const char msg[] = "hello world!";
  coap_set_payload(request, (uint8_t *)msg, sizeof(msg) - 1);

  // DEBUG: printf server hostname
  //PRINT6ADDR(&server_ipaddr);
  //PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT));

  COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request,
                        client_chunk_handler);

I can process the data the server responds inside of the function client_chunk_handler.

Now, here's where I get lost. This example uses the function COAP_BLOCKING_REQUEST; but by examining block-transfer.c I see there is a function:

COAP_BLOCKING_REQUEST_BLOCK(ctx, server_addr, server_port, request, request_callback)

What is ctx? I understand it is a context_t type object, but it is not clear to me how to generate or use the object. I would take a guess that it is somehow related to how we track whether there are more blocks incoming from the server? Is it necessary to handle the logic of sending requests to the server asking for more blocks, or does this happen behind the scenes?

Or am I misunderstanding the API, and it is possible to use the simpler COAP_BLOCKING_REQUEST to get block2 information from the server?

Thank you again for your time and patience. Your help and expertise is greatly appreciated by the IoT community!

msolters commented 8 years ago

For posterity, I will attach below the gist of the solution I arrived at. My solution may not be the most elegant one, but it gets the job done.

I just wrap my COAP_BLOCKING_REQUEST call in a while loop that can only break once I have received all the bytes I was expecting. The same request will just be retriggered to continue if the whole message isn't there.

I'm not sure if there's anything like this that will automate the receiving of block information that I'm unaware of, built into the coap app provided. The real purpose of this issue should be there needs to be proper documentation for the CoAP API.


int bytes_received = 0;
char *request_url = "/example_url";

void
coap_chunk_handler(void *response)
{
    //  Parse the payload from the CoAP response and print it
  const uint8_t *chunk;
  int len = coap_get_payload(response, &chunk);
  bytes_received += len;
  printf("%.*s\n", len, chunk);
}

int main() {
  //  (1) Initialize CoAP engine & request object
  static uip_ipaddr_t server_ipaddr;
  uip_ip6addr(&server_ipaddr, 0xbbbb, 0, 0, 0, 0, 0, 0, 0x1); // bbbb::1 is our example host
  coap_init_engine();
  static coap_packet_t request[1];

  int coap_request_count = 0;
  while ( true ) {
    PRINTF("\n-----CoAP Request %u Started-----\n", coap_request_count);

    //  (2) Construct a blockwise CoAP GET request
    coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0);
    coap_set_header_uri_path(request, request_url);
    //  By adding a block2 header to our request, the server will know this is
    //  a blockwise data transfer.  We want chunks of 256 bytes.
    coap_set_header_block2(request, 0, 0, 256);
    char my_payload_msg[] = "hello world!";
    coap_set_payload(request, my_payload_msg, sizeof(my_payload_msg));

    //  (3) Issue a GET request to the CoAP server
    //      coap_chunk_handler will process incoming data.
    COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, coap_chunk_handler);

    //  The CoAP request will block until failure/completion, then we get here:
    PRINTF("-----CoAP Request %u Terminated-----\n\n", coap_request_count);

    if (bytes_received > SOME_KNOWN_CRITERIA) {
      break;
    } else {
      coap_request_count++;
    }
  }