source: mainline/uspace/app/date_cfg/date_cfg.c@ 9f945464

Last change on this file since 9f945464 was 651dde7, checked in by Wayne Thornton <wmthornton-dev@…>, 5 months ago

Fixed formatting issues in 'date_cfg' code

No changes to code, except to remove extra tabs and whitespaces.

  • Property mode set to 100644
File size: 12.0 KB
Line 
1/*
2 * Copyright (c) 2025 Wayne Michael Thornton (WMT) <wmthornton-dev@outlook.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup date_cfg
30 * @{
31 */
32/** @file Date configuration application (in UI)
33 */
34
35#include <gfx/coord.h>
36#include <stdio.h>
37#include <str.h>
38#include <stdlib.h>
39#include <ui/fixed.h>
40#include <ui/label.h>
41#include <ui/pbutton.h>
42#include <ui/entry.h>
43#include <ui/resource.h>
44#include <ui/ui.h>
45#include <ui/window.h>
46#include <device/clock_dev.h>
47#include <loc.h>
48#include <time.h>
49#include "date_cfg.h"
50
51static void wnd_close(ui_window_t *, void *);
52static void ok_clicked(ui_pbutton_t *, void *);
53static void set_clicked(ui_pbutton_t *, void *);
54static errno_t get_current_time(struct tm *);
55static errno_t set_system_time(struct tm *);
56static void update_time_display(date_cfg_t *);
57static errno_t parse_date_time(date_cfg_t *);
58
59static ui_window_cb_t window_cb = {
60 .close = wnd_close
61};
62
63static ui_pbutton_cb_t button_cb = {
64 .clicked = ok_clicked
65};
66
67static ui_pbutton_cb_t set_button_cb = {
68 .clicked = set_clicked
69};
70
71/** Window close button was clicked.
72 *
73 * @param window Window
74 * @param arg Argument (date_cfg)
75 */
76static void wnd_close(ui_window_t *window, void *arg)
77{
78 date_cfg_t *date_cfg = (date_cfg_t *) arg;
79 ui_quit(date_cfg->ui);
80}
81
82/** OK button was clicked.
83 *
84 * @param button Button that was clicked
85 * @param arg Argument (date_cfg)
86 */
87static void ok_clicked(ui_pbutton_t *button, void *arg)
88{
89 date_cfg_t *date_cfg = (date_cfg_t *) arg;
90 ui_quit(date_cfg->ui);
91}
92
93/** Set button was clicked.
94 *
95 * @param button Button that was clicked
96 * @param arg Argument (date_cfg)
97 */
98static void set_clicked(ui_pbutton_t *button, void *arg)
99{
100 date_cfg_t *date_cfg = (date_cfg_t *) arg;
101 errno_t rc;
102
103 rc = parse_date_time(date_cfg);
104 if (rc != EOK) {
105 printf("Error parsing date/time. Please use format DD/MM/YYYY and HH:MM:SS\n");
106 return;
107 }
108
109 rc = set_system_time(&date_cfg->current_time);
110 if (rc != EOK) {
111 printf("Error setting system time.\n");
112 return;
113 }
114
115 update_time_display(date_cfg);
116}
117
118/** Get current system time.
119 *
120 * @param t Pointer to tm structure to store time
121 * @return EOK on success, error code otherwise
122 */
123static errno_t get_current_time(struct tm *t)
124{
125 category_id_t cat_id;
126 service_id_t *svc_ids = NULL;
127 size_t svc_cnt;
128 service_id_t svc_id;
129 char *svc_name = NULL;
130 errno_t rc;
131
132 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
133 if (rc != EOK)
134 return rc;
135
136 rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
137 if (rc != EOK)
138 return rc;
139
140 if (svc_cnt == 0) {
141 free(svc_ids);
142 return ENOENT;
143 }
144
145 rc = loc_service_get_name(svc_ids[0], &svc_name);
146 if (rc != EOK) {
147 free(svc_ids);
148 return rc;
149 }
150
151 rc = loc_service_get_id(svc_name, &svc_id, 0);
152 if (rc != EOK) {
153 free(svc_name);
154 free(svc_ids);
155 return rc;
156 }
157
158 async_sess_t *sess = loc_service_connect(svc_id, INTERFACE_DDF, 0);
159 if (!sess) {
160 free(svc_name);
161 free(svc_ids);
162 return EIO;
163 }
164
165 rc = clock_dev_time_get(sess, t);
166
167 free(svc_name);
168 free(svc_ids);
169 return rc;
170}
171
172/** Set system time.
173 *
174 * @param t Pointer to tm structure containing new time
175 * @return EOK on success, error code otherwise
176 */
177static errno_t set_system_time(struct tm *t)
178{
179 category_id_t cat_id;
180 service_id_t *svc_ids = NULL;
181 size_t svc_cnt;
182 service_id_t svc_id;
183 char *svc_name = NULL;
184 errno_t rc;
185
186 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
187 if (rc != EOK)
188 return rc;
189
190 rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
191 if (rc != EOK)
192 return rc;
193
194 if (svc_cnt == 0) {
195 free(svc_ids);
196 return ENOENT;
197 }
198
199 rc = loc_service_get_name(svc_ids[0], &svc_name);
200 if (rc != EOK) {
201 free(svc_ids);
202 return rc;
203 }
204
205 rc = loc_service_get_id(svc_name, &svc_id, 0);
206 if (rc != EOK) {
207 free(svc_name);
208 free(svc_ids);
209 return rc;
210 }
211
212 async_sess_t *sess = loc_service_connect(svc_id, INTERFACE_DDF, 0);
213 if (!sess) {
214 free(svc_name);
215 free(svc_ids);
216 return EIO;
217 }
218
219 rc = clock_dev_time_set(sess, t);
220
221 free(svc_name);
222 free(svc_ids);
223 return rc;
224}
225
226/** Update time display entry fields.
227 *
228 * @param date_cfg Date configuration structure
229 */
230static void update_time_display(date_cfg_t *date_cfg)
231{
232 char date_str[32];
233 char time_str[32];
234
235 snprintf(date_str, sizeof(date_str), "%02d/%02d/%d",
236 date_cfg->current_time.tm_mday,
237 date_cfg->current_time.tm_mon + 1,
238 1900 + date_cfg->current_time.tm_year);
239
240 snprintf(time_str, sizeof(time_str), "%02d:%02d:%02d",
241 date_cfg->current_time.tm_hour,
242 date_cfg->current_time.tm_min,
243 date_cfg->current_time.tm_sec);
244
245 ui_entry_set_text(date_cfg->date_entry, date_str);
246 ui_entry_set_text(date_cfg->time_entry, time_str);
247}
248
249/** Parse date and time from entry fields.
250 *
251 * @param date_cfg Date configuration structure
252 * @return EOK on success, error code otherwise
253 */
254static errno_t parse_date_time(date_cfg_t *date_cfg)
255{
256 const char *date_str = ui_entry_get_text(date_cfg->date_entry);
257 const char *time_str = ui_entry_get_text(date_cfg->time_entry);
258 int day, month, year;
259 int hour, min, sec;
260
261 if (sscanf(date_str, "%d/%d/%d", &day, &month, &year) != 3)
262 return EINVAL;
263
264 if (sscanf(time_str, "%d:%d:%d", &hour, &min, &sec) != 3)
265 return EINVAL;
266
267 if (day < 1 || day > 31 || month < 1 || month > 12 || year < 1900)
268 return EINVAL;
269
270 if (hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59)
271 return EINVAL;
272
273 date_cfg->current_time.tm_mday = day;
274 date_cfg->current_time.tm_mon = month - 1;
275 date_cfg->current_time.tm_year = year - 1900;
276 date_cfg->current_time.tm_hour = hour;
277 date_cfg->current_time.tm_min = min;
278 date_cfg->current_time.tm_sec = sec;
279
280 return EOK;
281}
282
283/** Run Date Configuration on display server. */
284static errno_t date_cfg(const char *display_spec)
285{
286 ui_t *ui = NULL;
287 ui_wnd_params_t params;
288 ui_window_t *window = NULL;
289 date_cfg_t date_cfg;
290 gfx_rect_t rect;
291 ui_resource_t *ui_res;
292 errno_t rc;
293
294 rc = ui_create(display_spec, &ui);
295 if (rc != EOK) {
296 printf("Error creating UI on display %s.\n", display_spec);
297 return rc;
298 }
299
300 ui_wnd_params_init(&params);
301 params.caption = "Date Configuration";
302 params.placement = ui_wnd_place_center;
303
304 if (ui_is_textmode(ui)) {
305 params.rect.p0.x = 0;
306 params.rect.p0.y = 0;
307 params.rect.p1.x = 45;
308 params.rect.p1.y = 15;
309 } else {
310 params.rect.p0.x = 0;
311 params.rect.p0.y = 0;
312 params.rect.p1.x = 350;
313 params.rect.p1.y = 275;
314 }
315
316 memset((void *) &date_cfg, 0, sizeof(date_cfg));
317 date_cfg.ui = ui;
318
319 rc = ui_window_create(ui, &params, &window);
320 if (rc != EOK) {
321 printf("Error creating window.\n");
322 return rc;
323 }
324
325 ui_window_set_cb(window, &window_cb, (void *) &date_cfg);
326 date_cfg.window = window;
327
328 ui_res = ui_window_get_res(window);
329
330 rc = ui_fixed_create(&date_cfg.fixed);
331 if (rc != EOK) {
332 printf("Error creating fixed layout.\n");
333 return rc;
334 }
335
336 /* Create date label */
337 rc = ui_label_create(ui_res, "Date:", &date_cfg.date_label);
338 if (rc != EOK) {
339 printf("Error creating date label.\n");
340 return rc;
341 }
342
343 if (ui_is_textmode(ui)) {
344 rect.p0.x = 2;
345 rect.p0.y = 5;
346 rect.p1.x = 7;
347 rect.p1.y = 6;
348 } else {
349 rect.p0.x = 20;
350 rect.p0.y = 80;
351 rect.p1.x = 100;
352 rect.p1.y = 100;
353 }
354
355 ui_label_set_rect(date_cfg.date_label, &rect);
356 ui_fixed_add(date_cfg.fixed, ui_label_ctl(date_cfg.date_label));
357
358 /* Create date entry */
359 rc = ui_entry_create(window, "", &date_cfg.date_entry);
360 if (rc != EOK) {
361 printf("Error creating date entry.\n");
362 return rc;
363 }
364
365 if (ui_is_textmode(ui)) {
366 rect.p0.x = 8;
367 rect.p0.y = 5;
368 rect.p1.x = 28;
369 rect.p1.y = 6;
370 } else {
371 rect.p0.x = 120;
372 rect.p0.y = 80;
373 rect.p1.x = 250;
374 rect.p1.y = 100;
375 }
376
377 ui_entry_set_rect(date_cfg.date_entry, &rect);
378 ui_fixed_add(date_cfg.fixed, ui_entry_ctl(date_cfg.date_entry));
379
380 /* Create time label */
381 rc = ui_label_create(ui_res, "Time:", &date_cfg.time_label);
382 if (rc != EOK) {
383 printf("Error creating time label.\n");
384 return rc;
385 }
386
387 if (ui_is_textmode(ui)) {
388 rect.p0.x = 2;
389 rect.p0.y = 7;
390 rect.p1.x = 7;
391 rect.p1.y = 8;
392 } else {
393 rect.p0.x = 20;
394 rect.p0.y = 120;
395 rect.p1.x = 100;
396 rect.p1.y = 140;
397 }
398
399 ui_label_set_rect(date_cfg.time_label, &rect);
400 ui_fixed_add(date_cfg.fixed, ui_label_ctl(date_cfg.time_label));
401
402 /* Create time entry */
403 rc = ui_entry_create(window, "", &date_cfg.time_entry);
404 if (rc != EOK) {
405 printf("Error creating time entry.\n");
406 return rc;
407 }
408
409 if (ui_is_textmode(ui)) {
410 rect.p0.x = 8;
411 rect.p0.y = 7;
412 rect.p1.x = 28;
413 rect.p1.y = 8;
414 } else {
415 rect.p0.x = 120;
416 rect.p0.y = 120;
417 rect.p1.x = 250;
418 rect.p1.y = 140;
419 }
420
421 ui_entry_set_rect(date_cfg.time_entry, &rect);
422 ui_fixed_add(date_cfg.fixed, ui_entry_ctl(date_cfg.time_entry));
423
424 /* Create Set button */
425 rc = ui_pbutton_create(ui_res, "Set", &date_cfg.set_button);
426 if (rc != EOK) {
427 printf("Error creating Set button.\n");
428 return rc;
429 }
430
431 ui_pbutton_set_cb(date_cfg.set_button, &set_button_cb, (void *) &date_cfg);
432
433 if (ui_is_textmode(ui)) {
434 rect.p0.x = 2;
435 rect.p0.y = 13;
436 rect.p1.x = 13;
437 rect.p1.y = 14;
438 } else {
439 rect.p0.x = 20;
440 rect.p0.y = 235;
441 rect.p1.x = 120;
442 rect.p1.y = rect.p0.y + 28;
443 }
444
445 ui_pbutton_set_rect(date_cfg.set_button, &rect);
446 ui_fixed_add(date_cfg.fixed, ui_pbutton_ctl(date_cfg.set_button));
447
448 /* Create OK button */
449 rc = ui_pbutton_create(ui_res, "OK", &date_cfg.ok_button);
450 if (rc != EOK) {
451 printf("Error creating OK button.\n");
452 return rc;
453 }
454
455 ui_pbutton_set_cb(date_cfg.ok_button, &button_cb, (void *) &date_cfg);
456
457 if (ui_is_textmode(ui)) {
458 rect.p0.x = 17;
459 rect.p0.y = 13;
460 rect.p1.x = 28;
461 rect.p1.y = 14;
462 } else {
463 rect.p0.x = 125;
464 rect.p0.y = 235;
465 rect.p1.x = 225;
466 rect.p1.y = rect.p0.y + 28;
467 }
468
469 ui_pbutton_set_rect(date_cfg.ok_button, &rect);
470 ui_pbutton_set_default(date_cfg.ok_button, true);
471
472 ui_fixed_add(date_cfg.fixed, ui_pbutton_ctl(date_cfg.ok_button));
473
474 ui_window_add(window, ui_fixed_ctl(date_cfg.fixed));
475
476 /* Get current time and update display */
477 rc = get_current_time(&date_cfg.current_time);
478 if (rc != EOK) {
479 printf("Error getting current time.\n");
480 return rc;
481 }
482
483 update_time_display(&date_cfg);
484
485 rc = ui_window_paint(window);
486 if (rc != EOK) {
487 printf("Error painting window.\n");
488 return rc;
489 }
490
491 ui_run(ui);
492
493 ui_window_destroy(window);
494 ui_destroy(ui);
495
496 return EOK;
497}
498
499static void print_syntax(void)
500{
501 printf("Syntax: date_cfg [-d <display-spec>]\n");
502}
503
504int main(int argc, char *argv[])
505{
506 const char *display_spec = UI_ANY_DEFAULT;
507 errno_t rc;
508 int i;
509
510 i = 1;
511 while (i < argc && argv[i][0] == '-') {
512 if (str_cmp(argv[i], "-d") == 0) {
513 ++i;
514 if (i >= argc) {
515 printf("Argument missing.\n");
516 print_syntax();
517 return 1;
518 }
519
520 display_spec = argv[i++];
521 } else {
522 printf("Invalid option '%s'.\n", argv[i]);
523 print_syntax();
524 return 1;
525 }
526 }
527
528 if (i < argc) {
529 print_syntax();
530 return 1;
531 }
532
533 rc = date_cfg(display_spec);
534 if (rc != EOK)
535 return 1;
536
537 return 0;
538}
539
540/** @}
541 */
Note: See TracBrowser for help on using the repository browser.