1 /*
2  * server-coap.h -- LwIP example
3  *
4  * Copyright (C) 2013-2016 Christian Amsüss <chrysn@fsfe.org>
5  * Copyright (C) 2018-2021 Jon Shallow <supjps-libcoap@jpshallow.com>
6  *
7  * SPDX-License-Identifier: BSD-2-Clause
8  *
9  * This file is part of the CoAP library libcoap. Please see README for terms
10  * of use.
11  */
12 
13 #include "coap_config.h"
14 #include <coap3/coap.h>
15 
16 coap_context_t *main_coap_context;
17 
18 static coap_time_t clock_offset;
19 /* changeable clock base (see handle_put_time()) */
20 static coap_time_t my_clock_base = 0;
21 static coap_resource_t *time_resource = NULL; /* just for testing */
22 
23 #ifndef min
24 # define min(a,b) ((a) < (b) ? (a) : (b))
25 #endif
26 
27 void
hnd_get_time(coap_resource_t * resource,coap_session_t * session,const coap_pdu_t * request,const coap_string_t * query,coap_pdu_t * response)28 hnd_get_time(coap_resource_t *resource, coap_session_t  *session,
29              const coap_pdu_t *request, const coap_string_t *query,
30              coap_pdu_t *response) {
31   unsigned char buf[40];
32   size_t len;
33   coap_tick_t now;
34   coap_tick_t t;
35 
36   /* FIXME: return time, e.g. in human-readable by default and ticks
37    * when query ?ticks is given. */
38 
39   /* if my_clock_base was deleted, we pretend to have no such resource */
40   response->code =
41     my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
42 
43   if (my_clock_base)
44     coap_add_option(response, COAP_OPTION_CONTENT_FORMAT,
45                     coap_encode_var_safe(buf, sizeof(buf),
46                     COAP_MEDIATYPE_TEXT_PLAIN),
47                     buf);
48 
49   coap_add_option(response, COAP_OPTION_MAXAGE,
50           coap_encode_var_safe(buf, sizeof(buf), 0x01), buf);
51 
52   if (my_clock_base) {
53 
54     /* calculate current time */
55     coap_ticks(&t);
56     now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
57 
58 
59     if (query != NULL
60         && coap_string_equal(query, coap_make_str_const("ticks"))) {
61       /* output ticks */
62       len = snprintf((char *)buf, sizeof(buf), "%u", (unsigned int)now);
63       coap_add_data(response, len, buf);
64     }
65   }
66 }
67 
68 void
init_coap_resources(coap_context_t * ctx)69 init_coap_resources(coap_context_t *ctx) {
70   coap_resource_t *r;
71 #if 0
72   r = coap_resource_init(NULL, 0, 0);
73   coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index);
74 
75   coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
76   coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"General Info\""), 0);
77   coap_add_resource(ctx, r);
78 #endif
79   /* store clock base to use in /time */
80   my_clock_base = clock_offset;
81 
82   r = coap_resource_init(coap_make_str_const("time"), 0);
83   if (!r)
84     goto error;
85 
86   coap_resource_set_get_observable(r, 1);
87   time_resource = r;
88   coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time);
89 #if 0
90   coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time);
91   coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
92 #endif
93   coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
94   /* coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Internal Clock\""), 0); */
95   coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"ticks\""), 0);
96   coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""), 0);
97 
98   coap_add_resource(ctx, r);
99 #if 0
100 #ifndef WITHOUT_ASYNC
101   r = coap_resource_init(coap_make_str_const("async"), 0);
102   coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async);
103 
104   coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
105   coap_add_resource(ctx, r);
106 #endif /* WITHOUT_ASYNC */
107 #endif
108 
109   return;
110  error:
111   coap_log(LOG_CRIT, "cannot create resource\n");
112 }
113 
server_coap_init(void)114 void server_coap_init(void)
115 {
116   coap_address_t listenaddress;
117 
118   coap_address_init(&listenaddress);
119 
120   /* looks like a server address, but is used as end point for clients too */
121   listenaddress.addr = *(IP_ANY_TYPE);
122   listenaddress.port = COAP_DEFAULT_PORT;
123 
124   coap_set_log_level(LOG_DEBUG);
125   main_coap_context = coap_new_context(&listenaddress);
126 
127   LWIP_ASSERT("Failed to initialize context", main_coap_context != NULL);
128   clock_offset = 1; /* Need a non-zero value */
129   init_coap_resources(main_coap_context);
130 }
131 
server_coap_poll(void)132 void server_coap_poll(void)
133 {
134   static coap_time_t last_time = 0;
135   coap_tick_t ticks_now;
136   coap_time_t time_now;
137 
138   coap_ticks(&ticks_now);
139   time_now = coap_ticks_to_rt(ticks_now);
140 
141   if (last_time != time_now) {
142     /* This takes place once a second */
143     last_time = time_now;
144     coap_resource_notify_observers(time_resource, NULL);
145   }
146   coap_check_notify(main_coap_context);
147 }
148