From 4300a565fbf639cb800eab813ee2a3a07f4f22a2 Mon Sep 17 00:00:00 2001
From: Waldemar Schmidt <waldemar.schmidt2@haw-hamburg.de>
Date: Mon, 4 Apr 2022 14:43:39 +0200
Subject: [PATCH] Add sensor CoAP resources

---
 08-coap-basic/server.c | 82 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)

diff --git a/08-coap-basic/server.c b/08-coap-basic/server.c
index 6a9e01c..5c23d6a 100644
--- a/08-coap-basic/server.c
+++ b/08-coap-basic/server.c
@@ -24,13 +24,20 @@
 static ssize_t _riot_board_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
 
 /* [TASK 2: add the prototype of your resource handler here] */
+static ssize_t _led_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx);
 
 /* [TASK 2: declare the array of LEDs here] */
+static const gpio_t leds[] = {
+    LED0_PIN,
+    LED1_PIN,
+    LED2_PIN,
+};
 
 /* CoAP resources. Must be sorted by path (ASCII order). */
 static const coap_resource_t _resources[] = {
     /* [TASK 2: register your CoAP resource here] */
-    { "/riot/board", COAP_GET, _riot_board_handler, NULL },
+    { "/led/", COAP_GET | COAP_PUT | COAP_MATCH_SUBTREE, _led_handler, NULL },
+    { "/riot/board", COAP_GET, _riot_board_handler, NULL }
 };
 
 /* a gcoap listener is a collection of resources. Additionally we can specify
@@ -53,9 +60,82 @@ void server_init(void)
     gcoap_register_listener(&_listener);
 
     /* [TASK 2: initialize the GPIOs here] */
+    for (unsigned i = 0; i < ARRAY_SIZE(leds); i++) {
+    gpio_init(leds[i], GPIO_OUT);
+    gpio_set(leds[i]);
+}
 }
 
 /* [TASK 2: implement the LED handler here] */
+static ssize_t _led_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx)
+{
+    (void) ctx; /* argument not used */
+
+    /* implement your handler here */
+
+    char uri[CONFIG_NANOCOAP_URI_MAX] = { 0 };
+    /* get the request path, to know which LED is being requested */
+    if (coap_get_uri_path(pdu, (uint8_t *)uri) <= 0) {
+        /* reply with an error if we could not parse the URI */
+        return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST);
+    }
+
+    /* find the LED number, the URI should be /led/<number> */
+    char *led_str = uri + strlen("/led/");
+    unsigned led_number = atoi(led_str);
+
+    /* verify that the number is valid, respond with an error otherwise */
+    if (led_number >= ARRAY_SIZE(leds)) {
+        return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST);
+    }
+
+
+    ssize_t resp_len = 0;
+    int led_status = 0;
+    unsigned method = coap_method2flag(coap_get_code_detail(pdu));
+
+    switch (method) {
+    case COAP_PUT: /* on PUT, we set the status of the LED based on the payload */
+        /* check if there is a payload with a LED status */
+        if (pdu->payload_len) {
+            led_status = atoi((char *)pdu->payload);
+        } else {
+            return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST);
+        }
+
+        if (led_status) {
+            gpio_clear(leds[led_number]);
+        } else {
+            gpio_set(leds[led_number]);
+        }
+        return gcoap_response(pdu, buf, len, COAP_CODE_CHANGED);
+
+    case COAP_GET: /* on GET, we return the status of the LED in plain text */
+        /* initialize the CoAP response */
+        gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT);
+
+        /* set the content format to plain text */
+        coap_opt_add_format(pdu, COAP_FORMAT_TEXT);
+
+        /* finish the options indicating that we will include a payload */
+        resp_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);
+
+        /* get the current status of the LED, which is the inverted value of the GPIO */
+        led_status = !gpio_read(leds[led_number]);
+
+        /* based on the status, write the value of the payload to send */
+        if (led_status) {
+            pdu->payload[0] = '1';
+        } else {
+            pdu->payload[0] = '0';
+        }
+        resp_len++;
+        return resp_len;
+    }
+
+
+    return 0;
+}
 
 /*
  * Server callback for /riot/board. Accepts only GET.