client version of coap

Dependencies:   nRF24L01P cantcoap3

Dependents:   client3

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;
+}