Tanganelli / CoAPthon

CoAPthon is a python library to the CoAP protocol aligned with the RFC
MIT License
221 stars 130 forks source link

How can I post big chuck of data to Contiki Server running on a microcontroller? #138

Open anesh1992 opened 5 years ago

anesh1992 commented 5 years ago

This is my post handler in contiki;

#define MAX_PLUGFEST_BODY    2048
#define MAX_PLUGFEST_PAYLOAD 64 + 1       /* +1 for the terminating zero, which is not transmitted */

static int32_t large_update_size = 0;
static uint8_t large_update_store[MAX_PLUGFEST_BODY] = { 0 };
static unsigned int large_update_ct = TEXT_PLAIN;
EVENT_RESOURCE(res_configuration,
               "title=\"ELEMENT TYPE\"; obs",
        NULL,
        res_post_put_handler_configuration,
            res_post_put_handler_configuration,
               NULL,
           NULL
               );

static void
res_post_put_handler_configuration(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
    coap_packet_t *const coap_req = (coap_packet_t *)request;
    uint8_t *incoming = NULL;
    size_t len = 0;

    unsigned int ct = -1;
    REST.get_header_content_type(request, &ct);
//  if(!REST.get_header_content_type(request, &ct)) {
//      REST.set_response_status(response, REST.status.BAD_REQUEST);
//      const char *error_msg = "NoContentType";
//      REST.set_response_payload(response, error_msg, strlen(error_msg));
//      return;
//  }

    if((len = REST.get_request_payload(request, (const uint8_t **)&incoming))) {
        if(coap_req->block1_num * coap_req->block1_size + len <= sizeof(large_update_store)) {
          memcpy(large_update_store + coap_req->block1_num * coap_req->block1_size, incoming, len);
          large_update_size = coap_req->block1_num * coap_req->block1_size + len;
          large_update_ct = ct;

          REST.set_response_status(response, REST.status.CREATED);
          coap_set_header_block1(response, coap_req->block1_num, 0,
                                 coap_req->block1_size);
        } else {
          REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE);
          REST.set_response_payload(
            response,
            buffer,
            snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.",
                     sizeof(large_update_store)));
          return;
        }
      } else {
        REST.set_response_status(response, REST.status.BAD_REQUEST);
        const char *error_msg = "NoPayload";
        REST.set_response_payload(response, error_msg, strlen(error_msg));
        return;
      }
}

Python code;

from coapthon.client.helperclient import HelperClient
import socket, struct, time
import json
from coapthon import defines
import time
from coapthon.resources.resource import Resource
from coapthon.utils import parse_blockwise

conductor_host = "fd00::XXXX:XXXX:XXXX:XXXX"
port = 5683
path ="configure/res_configuration"

client = HelperClient(server=(conductor_host, port))
length = len("{\"CONDUCTOR\":\"0\",\"Device Name\":\"BOH\", \"IPV6\":\"XXXX::XXXX:XXXX:XXXX:XXXX\", \"Element Type ID\":\"17\"}")
value = parse_blockwise(length)
print(value)
response = client.post(path = path, \
    payload = "{\"CONDUCTOR\":\"0\",\"Device Name\":\"BOH\", \"IPV6\":\"fd00::fd00:fd00:49bf:fd00\", \"Element Type ID\":\"17\"}", \
    accept = defines.Content_types["text/plain"],   \
    block1= value)
print (response.pretty_print())

The problem is, complete string is not reaching to microcontroller board running post handler, I am not sure if problem is in microcontroller code or python code. Can somebody please hint me where is the problem? At least, if python test code is correct or not? Thanks! -Anesh

Tanganelli commented 5 years ago

Hi,

why do you explicitly use parse_blockwise? Please take a look at https://github.com/Tanganelli/CoAPthon3/blob/master/coverage_test.py line number 434 for a working block tranfert.

Il giorno gio 14 feb 2019 alle ore 18:36 anesh1992 notifications@github.com ha scritto:

This is my post handler in contiki;

define MAX_PLUGFEST_BODY 2048

define MAX_PLUGFEST_PAYLOAD 64 + 1 / +1 for the terminating zero, which is not transmitted /

static int32_t large_update_size = 0; static uint8_t large_update_store[MAX_PLUGFEST_BODY] = { 0 }; static unsigned int large_update_ct = TEXT_PLAIN; EVENT_RESOURCE(res_configuration, "title=\"ELEMENT TYPE\"; obs", NULL, res_post_put_handler_configuration, res_post_put_handler_configuration, NULL, NULL );

static void res_post_put_handler_configuration(void request, void response, uint8_t buffer, uint16_t preferred_size, int32_t offset) { coap_packet_t const coap_req = (coap_packet_t )request; uint8_t *incoming = NULL; size_t len = 0;

unsigned int ct = -1; REST.get_header_content_type(request, &ct); // if(!REST.get_header_content_type(request, &ct)) { // REST.set_response_status(response, REST.status.BAD_REQUEST); // const char *error_msg = "NoContentType"; // REST.set_response_payload(response, error_msg, strlen(error_msg)); // return; // }

if((len = REST.get_request_payload(request, (const uint8_t *)&incoming))) { if(coap_req->block1_num coap_req->block1_size + len <= sizeof(large_update_store)) { memcpy(large_update_store + coap_req->block1_num coap_req->block1_size, incoming, len); large_update_size = coap_req->block1_num coap_req->block1_size + len; large_update_ct = ct;

    REST.set_response_status(response, REST.status.CREATED);
    coap_set_header_block1(response, coap_req->block1_num, 0,
                           coap_req->block1_size);
  } else {
    REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE);
    REST.set_response_payload(
      response,
      buffer,
      snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.",
               sizeof(large_update_store)));
    return;
  }
} else {
  REST.set_response_status(response, REST.status.BAD_REQUEST);
  const char *error_msg = "NoPayload";
  REST.set_response_payload(response, error_msg, strlen(error_msg));
  return;
}

}

Python code;

from coapthon.client.helperclient import HelperClient import socket, struct, time import json from coapthon import defines import time from coapthon.resources.resource import Resource from coapthon.utils import parse_blockwise

conductor_host = "fd00::XXXX:XXXX:XXXX:XXXX" port = 5683 path ="configure/res_configuration"

client = HelperClient(server=(conductor_host, port)) length = len("{\"CONDUCTOR\":\"0\",\"Device Name\":\"BOH\", \"IPV6\":\"XXXX::XXXX:XXXX:XXXX:XXXX\", \"Element Type ID\":\"17\"}") value = parse_blockwise(length) print(value) response = client.post(path = path, \ payload = "{\"CONDUCTOR\":\"0\",\"Device Name\":\"BOH\", \"IPV6\":\"fd00::fd00:fd00:49bf:fd00\", \"Element Type ID\":\"17\"}", \ accept = defines.Content_types["text/plain"], \ block1= value) print (response.pretty_print())

The problem is, complete string is not reaching to microcontroller board running post handler, I am not sure if problem is in microcontroller code or python code. Can somebody please hint me where is the problem? At least, if python test code is correct or not? Thanks! -Anesh

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/Tanganelli/CoAPthon/issues/138, or mute the thread https://github.com/notifications/unsubscribe-auth/AGb2-jCjQFZ0zuDz0v6m3Ny5KLbYBjPhks5vNZ6YgaJpZM4a8GH- .

anesh1992 commented 5 years ago
client = HelperClient(server=(conductor_host, port))
response = client.post(path = path, \
    payload = "{\"CONDUCTOR\":\"0\",\"Device Name\":\"BOH\", \"IPV6\":\"fd00::fd00:fd00:49bf:fd00\", \"Element Type ID\":\"17\"}")
print (response.pretty_print())

Is client.post () is taking care of big data? Or do I need to pass any argument to tell post() method that it's a long string? Microcontroller running post handler resource, not recieving NUM, M and SZX as it should. the size of the block (SZX); whether more blocks are following (M); the relative number of the block (NUM) within a sequence of blocks with the given size.

anesh1992 commented 5 years ago

I did something like this and ity's working. But, It seems to me that, this is not a correct way of blockwise transfer. I made M always 1 that means server knows that more data is coming from client, when in last block when no payload is there, i am not changing M to 0, that is why getting bad request (but that is okay for me know).

def post_configuration (host, path, payload):
    lst = list (parse_blockwise(len(payload)))
    lst [1] = 1
    value = tuple(lst)
    client = HelperClient(server=(host, port))
    request = Request()
    request.code = defines.Codes.POST.number
    request.type = defines.Types["CON"]
    request.destination = (host, port)
    request.uri_path = path
    request.content_type = defines.Content_types["text/plain"]
    request.payload = payload
    request.block1 = value
    request._mid = 10
    response = client.send_request(request)
    print (response.pretty_print())
    client.stop()
anesh1992 commented 5 years ago

@Tanganelli In the above code if I will not use parse_blockwise then I will have to hard code as you did in your test code https://github.com/Tanganelli/CoAPthon3/blob/master/coverage_test.py#L452. Is there any API for big data transfer that takes care of request.block1 = value and just I need to call that? Is above code is correct? If not what is wrong? Thanks!

anesh1992 commented 5 years ago

@Tanganelli I am really stuck with this block-wise transfer, With code here https://github.com/Tanganelli/CoAPthon/issues/138#issuecomment-466110902 I posted, able to send data and sometimes not, can you please provide example code for block-wise transfer? This is the payload I want to send, length of payload could change.

"{'0_1|0000_1100': [3, 2, 4, 20.0, 22.22, -0.56, 0.28],'0_1|1100_2400': [3, 2, 4, 20.0, 22.22, -0.56, 0.28],'2_3|0000_2400': [2, 2, 4, 20.0, 22.22, -0.56, 0.56],'4|0000_1400': [2, 2, 4, 20.0, 22.22, -0.56, 0.56],'4|1400_2400': [2, 2, 4, 20.0, 22.22, -0.56, 0.56],'5_6|0000_0900': [2, 2, 4, 20.0, 22.22, -0.56, 0.56],'5_6|0900_1900': [2, 2, 4, 20.0, 22.22, -0.56, 0.56],'5_6|1900_2400': [2, 2, 4, 20.0, 22.22, -0.56, 0.56]}"