1.. _coap_server_interface: 2 3CoAP server 4########### 5 6.. contents:: 7 :local: 8 :depth: 2 9 10Overview 11******** 12 13Zephyr comes with a batteries-included CoAP server, which uses services to listen for CoAP 14requests. The CoAP services handle communication over sockets and pass requests to registered 15CoAP resources. 16 17Setup 18***** 19 20Some configuration is required to make sure services can be started using the CoAP server. The 21:kconfig:option:`CONFIG_COAP_SERVER` option should be enabled in your project: 22 23.. code-block:: cfg 24 :caption: ``prj.conf`` 25 26 CONFIG_COAP_SERVER=y 27 28All services are added to a predefined linker section and all resources for each service also get 29their respective linker sections. If you would have a service ``my_service`` it has to be 30prefixed with ``coap_resource_`` and added to a linker file: 31 32.. code-block:: c 33 :caption: ``sections-ram.ld`` 34 35 #include <zephyr/linker/iterable_sections.h> 36 37 ITERABLE_SECTION_RAM(coap_resource_my_service, Z_LINK_ITERABLE_SUBALIGN) 38 39Add this linker file to your application using CMake: 40 41.. code-block:: cmake 42 :caption: ``CMakeLists.txt`` 43 44 # Support LD linker template 45 zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) 46 47 # Support CMake linker generator 48 zephyr_iterable_section(NAME coap_resource_my_service 49 GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} 50 SUBALIGN ${CONFIG_LINKER_ITERABLE_SUBALIGN}) 51 52You can now define your service as part of the application: 53 54.. code-block:: c 55 56 #include <zephyr/net/coap_service.h> 57 58 static const uint16_t my_service_port = 5683; 59 60 COAP_SERVICE_DEFINE(my_service, "0.0.0.0", &my_service_port, COAP_SERVICE_AUTOSTART); 61 62.. note:: 63 64 Services defined with the ``COAP_SERVICE_AUTOSTART`` flag will be started together with the CoAP 65 server thread. Services can be manually started and stopped with ``coap_service_start`` and 66 ``coap_service_stop`` respectively. 67 68Sample Usage 69************ 70 71The following is an example of a CoAP resource registered with our service: 72 73.. code-block:: c 74 75 #include <zephyr/net/coap_service.h> 76 77 static int my_get(struct coap_resource *resource, struct coap_packet *request, 78 struct sockaddr *addr, socklen_t addr_len) 79 { 80 static const char *msg = "Hello, world!"; 81 uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; 82 struct coap_packet response; 83 uint16_t id; 84 uint8_t token[COAP_TOKEN_MAX_LEN]; 85 uint8_t tkl, type; 86 87 type = coap_header_get_type(request); 88 id = coap_header_get_id(request); 89 tkl = coap_header_get_token(request, token); 90 91 /* Determine response type */ 92 type = (type == COAP_TYPE_CON) ? COAP_TYPE_ACK : COAP_TYPE_NON_CON; 93 94 coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token, 95 COAP_RESPONSE_CODE_CONTENT, id); 96 97 /* Set content format */ 98 coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, 99 COAP_CONTENT_FORMAT_TEXT_PLAIN); 100 101 /* Append payload */ 102 coap_packet_append_payload_marker(&response); 103 coap_packet_append_payload(&response, (uint8_t *)msg, sizeof(msg)); 104 105 /* Send to response back to the client */ 106 return coap_resource_send(resource, &response, addr, addr_len, NULL); 107 } 108 109 static int my_put(struct coap_resource *resource, struct coap_packet *request, 110 struct sockaddr *addr, socklen_t addr_len) 111 { 112 /* ... Handle the incoming request ... */ 113 114 /* Return a CoAP response code as a shortcut for an empty ACK message */ 115 return COAP_RESPONSE_CODE_CHANGED; 116 } 117 118 static const char * const my_resource_path[] = { "test", NULL }; 119 COAP_RESOURCE_DEFINE(my_resource, my_service, { 120 .path = my_resource_path, 121 .get = my_get, 122 .put = my_put, 123 }); 124 125.. note:: 126 127 As demonstrated in the example above, a CoAP resource handler can return response codes to let 128 the server respond with an empty ACK response. 129 130Observable resources 131******************** 132 133The CoAP server provides logic for parsing observe requests and stores these using the runtime data 134of CoAP services. An example using a temperature sensor can look like: 135 136.. code-block:: c 137 138 #include <zephyr/kernel.h> 139 #include <zephyr/drivers/sensor.h> 140 #include <zephyr/net/coap_service.h> 141 142 static void notify_observers(struct k_work *work); 143 K_WORK_DELAYABLE_DEFINE(temp_work, notify_observers); 144 145 static int send_temperature(struct coap_resource *resource, 146 const struct sockaddr *addr, socklen_t addr_len, 147 uint16_t age, uint16_t id, const uint8_t *token, uint8_t tkl, 148 bool is_response) 149 { 150 const struct device *dev = DEVICE_DT_GET(DT_ALIAS(ambient_temp0)); 151 uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; 152 struct coap_packet response; 153 char payload[14]; 154 struct sensor_value value; 155 double temp; 156 uint8_t type; 157 158 /* Determine response type */ 159 type = is_response ? COAP_TYPE_ACK : COAP_TYPE_CON; 160 161 if (!is_response) { 162 id = coap_next_id(); 163 } 164 165 coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token, 166 COAP_RESPONSE_CODE_CONTENT, id); 167 168 if (age >= 2U) { 169 coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); 170 } 171 172 /* Set content format */ 173 coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, 174 COAP_CONTENT_FORMAT_TEXT_PLAIN); 175 176 /* Get the sensor data */ 177 sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP); 178 sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &value); 179 temp = sensor_value_to_double(&value); 180 181 snprintk(payload, sizeof(payload), "%0.2f°C", temp); 182 183 /* Append payload */ 184 coap_packet_append_payload_marker(&response); 185 coap_packet_append_payload(&response, (uint8_t *)payload, strlen(payload)); 186 187 return coap_resource_send(resource, &response, addr, addr_len, NULL); 188 } 189 190 static int temp_get(struct coap_resource *resource, struct coap_packet *request, 191 struct sockaddr *addr, socklen_t addr_len) 192 { 193 uint8_t token[COAP_TOKEN_MAX_LEN]; 194 uint16_t id; 195 uint8_t tkl; 196 int r; 197 198 /* Let the CoAP server parse the request and add/remove observers if needed */ 199 r = coap_resource_parse_observe(resource, request, addr); 200 201 id = coap_header_get_id(request); 202 tkl = coap_header_get_token(request, token); 203 204 return send_temperature(resource, addr, addr_len, r == 0 ? resource->age : 0, 205 id, token, tkl, true); 206 } 207 208 static void temp_notify(struct coap_resource *resource, struct coap_observer *observer) 209 { 210 send_temperature(resource, &observer->addr, sizeof(observer->addr), resource->age, 0, 211 observer->token, observer->tkl, false); 212 } 213 214 static const char * const temp_resource_path[] = { "sensors", "temp1", NULL }; 215 COAP_RESOURCE_DEFINE(temp_resource, my_service, { 216 .path = temp_resource_path, 217 .get = temp_get, 218 .notify = temp_notify, 219 }); 220 221 static void notify_observers(struct k_work *work) 222 { 223 if (sys_slist_is_empty(&temp_resource.observers)) { 224 return; 225 } 226 227 coap_resource_notify(&temp_resource); 228 k_work_reschedule(&temp_work, K_SECONDS(1)); 229 } 230 231CoAP Events 232*********** 233 234By enabling :kconfig:option:`CONFIG_NET_MGMT_EVENT` the user can register for CoAP events. The 235following example simply prints when an event occurs. 236 237.. code-block:: c 238 239 #include <zephyr/sys/printk.h> 240 #include <zephyr/net/coap_mgmt.h> 241 #include <zephyr/net/coap_service.h> 242 243 #define COAP_EVENTS_SET (NET_EVENT_COAP_OBSERVER_ADDED | NET_EVENT_COAP_OBSERVER_REMOVED | \ 244 NET_EVENT_COAP_SERVICE_STARTED | NET_EVENT_COAP_SERVICE_STOPPED) 245 246 void coap_event_handler(uint32_t mgmt_event, struct net_if *iface, 247 void *info, size_t info_length, void *user_data) 248 { 249 switch (mgmt_event) { 250 case NET_EVENT_COAP_OBSERVER_ADDED: 251 printk("CoAP observer added"); 252 break; 253 case NET_EVENT_COAP_OBSERVER_REMOVED: 254 printk("CoAP observer removed"); 255 break; 256 case NET_EVENT_COAP_SERVICE_STARTED: 257 if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { 258 struct net_event_coap_service *net_event = info; 259 260 printk("CoAP service %s started", net_event->service->name); 261 } else { 262 printk("CoAP service started"); 263 } 264 break; 265 case NET_EVENT_COAP_SERVICE_STOPPED: 266 if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { 267 struct net_event_coap_service *net_event = info; 268 269 printk("CoAP service %s stopped", net_event->service->name); 270 } else { 271 printk("CoAP service stopped"); 272 } 273 break; 274 } 275 } 276 277 NET_MGMT_REGISTER_EVENT_HANDLER(coap_events, COAP_EVENTS_SET, coap_event_handler, NULL); 278 279CoRE Link Format 280**************** 281 282The :kconfig:option:`CONFIG_COAP_SERVER_WELL_KNOWN_CORE` option enables handling the 283``.well-known/core`` GET requests by the server. This allows clients to get a list of hypermedia 284links to other resources hosted in that server. 285 286API Reference 287************* 288 289.. doxygengroup:: coap_service 290.. doxygengroup:: coap_mgmt 291