diff --git a/cccs-examples.mk b/cccs-examples.mk index 6df66ab..07fa7a5 100644 --- a/cccs-examples.mk +++ b/cccs-examples.mk @@ -16,6 +16,7 @@ SUBDIRS := \ cccs-data-request-example \ + cccs-maintenance-status-example \ cccs-upload-binary-file-example \ cccs-upload-data-points-example diff --git a/cccs-maintenance-status-example/Makefile b/cccs-maintenance-status-example/Makefile new file mode 100644 index 0000000..4927b6d --- /dev/null +++ b/cccs-maintenance-status-example/Makefile @@ -0,0 +1,40 @@ +# +# Copyright 2023, Digi International Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. +# + +BINARY := cccs-maintenance-status-example + +CFLAGS += -Wall + +CFLAGS += $(shell pkg-config --cflags cccs) +LDLIBS += $(shell pkg-config --libs --static cccs) + +SRCS := $(wildcard *.c) +OBJS := $(SRCS:.c=.o) + +$(BINARY): $(OBJS) + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +.PHONY: install +install: $(BINARY) + install -d $(DESTDIR)/usr/bin + install -m 0755 $^ $(DESTDIR)/usr/bin/ + +.PHONY: all +all: $(BINARY) + +.PHONY: clean +clean: + -rm -f *.o $(BINARY) diff --git a/cccs-maintenance-status-example/README.md b/cccs-maintenance-status-example/README.md new file mode 100644 index 0000000..a5aad17 --- /dev/null +++ b/cccs-maintenance-status-example/README.md @@ -0,0 +1,79 @@ +Digi ConnectCore Cloud Services Maintenance Status Example Application +====================================================================== + +Example application to set the device maintenance status using ConnectCore Cloud +Services. + +This application alternates 'In maintenance' and 'In service' status keeping +them the provided number of seconds as parameters. + +If no parameters are provided each status is configured for 60 seconds. + +Running the application +----------------------- +This application requires `cccsd` (ConnectCore Cloud Services daemon) running +on the device. + +Once the binary is in the target, launch the application: + +``` +# ./cccs-maintenance-status-example +cccs-maintenance-status-example[1216]: [INFO] MNT: Setting maintenance to 'true' +Device IN MAINTENANCE for 60 seconds +Digi Remote Manager CAN: + * Apply compatible configurations + * Execute existing automations +cccs-maintenance-status-example[1216]: [INFO] MNT: Setting maintenance to 'false' +Device IN SERVICE for 60 seconds +Digi Remote Manager CANNOT: + * Apply configurations (unless 'allow' is set) + * Execute automations (unless 'allow' is set) +cccs-maintenance-status-example[1216]: [INFO] MNT: Setting maintenance to 'true' +Device IN MAINTENANCE for 60 seconds +Digi Remote Manager CAN: + * Apply compatible configurations + * Execute existing automations +cccs-maintenance-status-example[1216]: [INFO] MNT: Setting maintenance to 'false' +Device IN SERVICE for 60 seconds +Digi Remote Manager CANNOT: + * Apply configurations (unless 'allow' is set) + * Execute automations (unless 'allow' is set) + +[...] +``` + +Check the status of your device from Digi Remote Manager: + +1. Go to https://remotemanager.digi.com/. +2. Login with your credentials. +3. Click on the **Device ID** of your device in the **Devices** page. +4. Check the **Service Status** on the **Details** tab. + +Compiling the application +------------------------- +This example can be compiled using a Digi Embedded Yocto based toolchain. Make +sure to source the corresponding toolchain of the platform you are using, +for example, for ConnectCore 6UL: + +``` +~$ . /environment-setup-cortexa7t2hf-neon-dey-linux-gnueabi +~$ make +``` + +For more information, see the [Digi Embedded Yocto online documentation](https://github.com/digi-embedded/meta-digi). + +License +------- +Copyright 2023, Digi International Inc. + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/cccs-maintenance-status-example/main.c b/cccs-maintenance-status-example/main.c new file mode 100644 index 0000000..1243351 --- /dev/null +++ b/cccs-maintenance-status-example/main.c @@ -0,0 +1,221 @@ +/* + * Copyright 2023, Digi International Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MNT_INTERVAL 60 /* seconds */ +#define LOOP_MS 100 + +static bool stop_requested = false; + +/* + * usage_and_exit() - Show usage information and exit with 'val' return value + * + * @name: Application name. + * @val: The exit code. + */ +static void usage_and_exit(char *name, int val) +{ + fprintf(stdout, + "Example application to alternate 'in maintenance' and 'in service' status\n" + "\n" + "Usage: %s\n" + "The application sets the device:\n" + " In maintenance for %d seconds.\n" + " In service for %d seconds.\n" + "\n" + "Usage: %s \n" + " In maintenance for seconds.\n" + " In service for seconds.\n" + "\n", name, MNT_INTERVAL, MNT_INTERVAL, name); + + exit(val); +} + +/* + * sigaction_handler() - Handler to execute after receiving a signal + * + * @signum: Received signal. + */ +static void sigaction_handler(int signum) +{ + log_debug("%s: received signal %d", __func__, signum); + + stop_requested = true; + + exit(0); +} + +/* + * cleanup() - Frees all the allocated memory before exiting + */ +static void cleanup(void) +{ + deinit_logger(); +} + +/* + * register_signals() - Registers program signals + */ +static void register_signals(void) +{ + struct sigaction new_action; + struct sigaction old_action; + + atexit(cleanup); + + new_action.sa_handler = sigaction_handler; + new_action.sa_flags = 0; + sigemptyset(&new_action.sa_mask); + + sigaction(SIGINT, NULL, &old_action); + if (old_action.sa_handler != SIG_IGN) + sigaction(SIGINT, &new_action, NULL); + + sigaction(SIGHUP, &old_action, NULL); + if (old_action.sa_handler != SIG_IGN) + sigaction(SIGHUP, &new_action, NULL); + + sigaction(SIGTERM, &old_action, NULL); + if (old_action.sa_handler != SIG_IGN) + sigaction(SIGTERM, &new_action, NULL); +} + +/* + * wait_loop() - Loop to wait the provided number of seconds + * + * @timeout: Number of seconds to wait. + */ +static void wait_loop(long timeout) +{ + long n_loops, loop; + + n_loops = timeout * 1000 / LOOP_MS; + for (loop = 0; loop < n_loops; loop++) { + struct timespec sleepValue = {0}; + + if (stop_requested) + break; + sleepValue.tv_nsec = LOOP_MS * 1000 * 1000; + nanosleep(&sleepValue, NULL); + } +} + +int main(int argc, char *argv[]) +{ + char *name = basename(argv[0]); + bool status = false; + long mnt_sec = MNT_INTERVAL, srv_sec = MNT_INTERVAL; + + init_logger(LOG_INFO, LOG_CONS | LOG_NDELAY | LOG_PID | LOG_PERROR, name); + + if (argc != 1 && argc != 3) + usage_and_exit(name, EXIT_FAILURE); + + if (argc == 3) { + char *endptr = NULL; + + mnt_sec = strtol(argv[1], &endptr, 10); + //log_info("mnt_sec=%ld, strlen(endptr)=%lu", mnt_sec, strlen(endptr)); + if (errno != 0 || mnt_sec < 0 || strlen(endptr)) + goto invalid_values; + + srv_sec = strtol(argv[2], &endptr, 10); + //log_info("srv_sec=%ld", srv_sec); + if (errno != 0 || srv_sec < 0 || strlen(endptr)) + goto invalid_values; + + if (mnt_sec == 0 && srv_sec == 0) + goto invalid_values; + } + + register_signals(); + + if (!cccs_is_daemon_ready(CCCSD_NO_WAIT)) { + log_error("%s: CCCS daemon not ready... exiting", __func__); + + return EXIT_FAILURE; + } + + while (!stop_requested) { + cccs_comm_error_t ret; + cccs_resp_t resp; + bool success = false; + long timeout; + + status = !status; + timeout = status ? mnt_sec : srv_sec; + + if (timeout == 0) + continue; + + ret = cccs_set_maintenance_status(status, 3, &resp); + if (ret != CCCS_SEND_ERROR_NONE) { + log_error("%s: Unable to set maintenance status", __func__); + } else if (resp.code != 0) { + if (resp.hint) + log_error("%s: Unable to set maintenance status: %s (%d)", + __func__, resp.hint, resp.code); + else + log_error("%s: Unable to set maintenance status: %d", + __func__, resp.code); + } else { + success = true; + } + free(resp.hint); + + if (success) { + if (status) { + if (mnt_sec == 0 || srv_sec == 0) + printf("Device IN MAINTENANCE\n"); + else + printf("Device IN MAINTENANCE for %ld seconds\n", timeout); + printf("Digi Remote Manager CAN:\n"); + printf(" * Apply compatible configurations\n"); + printf(" * Execute existing automations\n"); + } else { + if (mnt_sec == 0 || srv_sec == 0) + printf("Device IN SERVICE\n"); + else + printf("Device IN SERVICE for %ld seconds\n", timeout); + printf("Digi Remote Manager CANNOT:\n"); + printf(" * Apply configurations (unless 'allow' is set)\n"); + printf(" * Execute automations (unless 'allow' is set)\n"); + } + + if (mnt_sec == 0 || srv_sec == 0) + break; + } else { + /* Retry the same status */ + status = !status; + } + + wait_loop(timeout); + } + + return EXIT_SUCCESS; + +invalid_values: + printf("Invalid time values\n"); + usage_and_exit(name, EXIT_FAILURE); +} diff --git a/samples-manifest.xml b/samples-manifest.xml index 385e117..4819f24 100644 --- a/samples-manifest.xml +++ b/samples-manifest.xml @@ -293,4 +293,24 @@ to stream `binary_dp`. ccmp13-dvk + + Digi CCCS set maintenance Example + +Example application to enable/disable maintenance status. + + cccs-maintenance-status-example + + ccimx6sbc + ccimx6qpsbc + ccimx6ulstarter + ccimx6ulsbc + ccimx8x-sbc-express + ccimx8x-sbc-pro + ccimx8mn-dvk + ccimx8mm-dvk + ccimx93-dvk + ccmp15-dvk + ccmp13-dvk + +