client version of coap
Dependencies: nRF24L01P cantcoap3
Diff: coapClient.cpp
- Revision:
- 0:6a6f97ca5572
- Child:
- 1:1d936c763440
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/coapClient.cpp Fri Jan 18 14:12:24 2019 +0000 @@ -0,0 +1,155 @@ +// +// Created by Kamil Mykitiuk on 2019-01-17. +// + +#include <cstring> +#include "CoapClient.h" + + +bool match_uri(CoapPDU& coapPDU, char* uri) { + char respone_uri[32]; + int len = 0; + coapPDU.getURI(respone_uri, 32, &len); + return strcmp(uri, respone_uri) == 0; +} + + +bool isExpectedResponse(CoapPDU& response, u_int16_t message_id, char* uri) { + return match_uri(response, uri) && response.getType() == CoapPDU::COAP_ACKNOWLEDGEMENT && + response.getMessageID() == message_id; +} + +bool CoapClient::isAck(CoapPDU& response, u_int16_t message_id, char* uri) { + if (response.validate()) { + if (isExpectedResponse(response, message_id, uri)) { + return true; + } else { + sendReset(response.getMessageID()); // if this is not what we wanted, inform server about error + } + } + return false; +} + + +/* send reset to server + * + * @return 0 if successful + * -4 if radio is not working properly + * */ +int CoapClient::sendReset(uint16_t message_id) { + CoapPDU reset = CoapPDU(); + reset.setMessageID(message_id); + reset.setType(CoapPDU::COAP_RESET); + int ret = this->radioWrapper.write(reset.getPDUPointer(), reset.getPDULength()); + if (ret < 0) { + return RADIO_NOT_WORKING; + } else { + return 0; + } +} + +/* send get request to given uri of connected server + * + * @return number of saved bytes in provided buffer or + * -1 if server responded ambiguously; + * -2 if server timed out; + * -3 if provided buffer is to small to save response, + * -4 if if radio is not functioning properly + * */ +int CoapClient::get(uint8_t* buffer, int len, char* uri) { + CoapPDU coapPDU = CoapPDU(); + uint16_t messageId = preparePDU(coapPDU); + coapPDU.setCode(CoapPDU::COAP_GET); + coapPDU.setURI(uri); + + uint8_t returnBuffer[radioWrapper.packetSize()]; + int timeout = this->listeningTimeout; + for (int i = 0; i < this->retransmissionLimit; i++) { + int ret = radioWrapper.write(coapPDU.getPDUPointer(), coapPDU.getPDULength()); // send empty payload to get uri + + if (ret < 0) { + return RADIO_NOT_WORKING; + } + + int readLen = radioWrapper.read(returnBuffer, radioWrapper.packetSize(), timeout); // add timeout param + if (readLen > 0) { // if something is recieved process it + CoapPDU response(returnBuffer, len, readLen); + if (isAck(response, messageId, uri)) { + if (std::memcmp(response.getTokenPointer(), this->token, + static_cast<size_t>(response.getTokenLength())) == 0) { + if (response.getPayloadLength() >= len) { + std::memcpy(buffer, response.getPayloadPointer(), + static_cast<size_t>(response.getPayloadLength())); + return response.getPayloadLength(); + } else { + return SMALL_BUFFER; + } + } else { + return SERVER_RESPONSE_AMBIGOUS; + } + } + } else if (readLen < 0) { + return RADIO_NOT_WORKING; + } + timeout *= 2; + } + return SERVER_TIMED_OUT; +} + +/* send post request to given uri of connected server + * + * @return 0 if operation has been completed successfully + * -1 if server responded ambiguously; + * -2 if server timed out; + * -4 if radio is not working properly + * */ +int CoapClient::post(uint8_t* buffer, int len, char* uri) { + CoapPDU coapPDU = CoapPDU(); + uint16_t messageId = preparePDU(coapPDU); + coapPDU.setCode(CoapPDU::COAP_POST); + + coapPDU.setURI(uri); + coapPDU.setPayload(buffer, len); + uint8_t returnBuffer[radioWrapper.packetSize()]; + int timeout = this->listeningTimeout; + for (int i = 0; i < this->retransmissionLimit; i++) { + + int ret = radioWrapper.write(coapPDU.getPDUPointer(), coapPDU.getPDULength()); + if (ret < 0) { + return RADIO_NOT_WORKING; + } + int readLen = radioWrapper.read(returnBuffer, radioWrapper.packetSize(), timeout); // add timeout param + if (readLen > 0) { // if something is recieved process it + CoapPDU response(returnBuffer, len, readLen); + if (isAck(response, messageId, uri)) { + if (response.getCode() == CoapPDU::COAP_CREATED && + std::memcmp(response.getTokenPointer(), this->token, + static_cast<size_t>(response.getTokenLength())) == 0) { + return 0; + } else // if server hasn't responded properly + return SERVER_RESPONSE_AMBIGOUS; + } + } else if (readLen < 0) { + return RADIO_NOT_WORKING; + } + timeout *= 2; + } + return SERVER_TIMED_OUT; +} + +uint16_t CoapClient::preparePDU(CoapPDU& coapPDU) { + coapPDU.setVersion(1); + coapPDU.setType(CoapPDU::COAP_CONFIRMABLE); + coapPDU.setMessageID(this->message_counter); + coapPDU.setToken(this->token, 4); + return this->message_counter++; +} + +CoapClient::CoapClient(uint8_t* token, int retransmissionLimit, int timeout, RadioWrapper& radio) : radioWrapper(radio), + listeningTimeout( + timeout), + retransmissionLimit( + retransmissionLimit) { + std::memcpy(this->token, token, 4); + this->message_counter = 16; +}