cccs: add ConnectCore Cloud Services examples
https://onedigi.atlassian.net/browse/DEL-8628 Signed-off-by: Tatiana Leon <Tatiana.Leon@digi.com>
This commit is contained in:
parent
79aa8410c2
commit
82ee13f97e
|
|
@ -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-data-request-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)
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
Digi ConnectCore Cloud Services Data Request Example Application
|
||||
================================================================
|
||||
|
||||
Example application to listen to data requests from Remote Manager using
|
||||
ConnectCore Cloud Services.
|
||||
|
||||
This application registers a `get_time` data request.
|
||||
When this request arrives the application sends back the current time.
|
||||
|
||||
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-data-request-example
|
||||
cccs-data-request-example[1011]: [DEBUG] CCCSD: Connected to CCCSD (s=4)
|
||||
cccs-data-request-example[1011]: [DEBUG] CCCS daemon ready
|
||||
cccs-data-request-example[1011]: [INFO] DREQ: Registering 'get_time' data request
|
||||
cccs-data-request-example[1011]: [DEBUG] CCCSD: Connected to CCCSD (s=7)
|
||||
cccs-data-request-example[1011]: [DEBUG] CCCSD: Success from CCCSD
|
||||
Waiting for Remote Manager request...
|
||||
Press 'q' and 'Enter' to exit
|
||||
|
||||
```
|
||||
|
||||
Send a `get_time` data request to your device.
|
||||
To do so:
|
||||
|
||||
1. Go to https://remotemanager.digi.com/.
|
||||
2. Login with your credentials.
|
||||
3. Get your device identifier from the **Devices** page:
|
||||
a. Go to the **Management > Devices** tab.
|
||||
b. If you have more than one device, you can filter using the **MAC**
|
||||
address of your device:
|
||||
1. Click on the filter text box and select **MAC**.
|
||||
2. Type the MAC address of your device and press `Enter`.
|
||||
3. Copy the **Device ID** of your device from the table by using the **Copy Device ID** button that appears next to it when you hover over the item.
|
||||
4. Go to the **System > API Explorer** tab. From here you can test the Web
|
||||
Services API.
|
||||
5. Click the **Examples** combo.
|
||||
6. Select **SCI > Data Service > Send Request**.
|
||||
A request appears inside the Body text box.
|
||||
7. Modify the request to stop the sampling process on your device:
|
||||
a. Replace the `device id` value with the copied one.
|
||||
b. Replace the `target_name` value with `get_time`.
|
||||
c. Remove the payload of the request.
|
||||
The request should be similar to the following:
|
||||
|
||||
```xml
|
||||
<sci_request version="1.0">
|
||||
<data_service>
|
||||
<targets>
|
||||
<device id="00000000-00000000-00XXXXXX-XXXXXXXX" />
|
||||
</targets>
|
||||
<requests>
|
||||
<device_request target_name="get_time"></device_request>
|
||||
</requests>
|
||||
</data_service>
|
||||
</sci_request>
|
||||
```
|
||||
Where `00000000-00000000-00XXXXXX-XXXXXXXX` is the Device ID.
|
||||
8. Click **Send** to send the request to your device.
|
||||
In the **Response** text box you can review the answer from the device:
|
||||
|
||||
```xml
|
||||
<sci_reply version="1.0">
|
||||
<data_service>
|
||||
<device id="00000000-00000000-00XXXXXX-XXXXXXXX">
|
||||
<requests>
|
||||
<device_request target_name="get_time" status="0">Time: Fri Sep 1 11:36:33 2023</device_request>
|
||||
</requests>
|
||||
</device>
|
||||
</data_service>
|
||||
</sci_reply>
|
||||
```
|
||||
Where `00000000-00000000-00XXXXXX-XXXXXXXX` is the Device ID.
|
||||
|
||||
The application prints out the received request:
|
||||
|
||||
```
|
||||
[...]
|
||||
Waiting for Remote Manager request...
|
||||
Press 'q' and 'Enter' to exit
|
||||
cccs-data-request-example[1163]: [DEBUG] get_time_cb: target='get_time'
|
||||
cccs-data-request-example[1163]: [DEBUG] get_time_status_cb: target='get_time' - error='0' - error-hint='Success'
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
~$ . <DEY-toolchain-path>/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.
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* 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 <cccs_services.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !(defined UNUSED_ARGUMENT)
|
||||
#define UNUSED_ARGUMENT(a) (void)(a)
|
||||
#endif
|
||||
|
||||
#define TARGET_GET_TIME "get_time"
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup() - Frees all the allocated memory before exiting
|
||||
*/
|
||||
static void cleanup(void)
|
||||
{
|
||||
cccs_resp_t resp;
|
||||
cccs_comm_error_t ret;
|
||||
|
||||
ret = cccs_remove_request_target(TARGET_GET_TIME, &resp);
|
||||
if (ret != CCCS_SEND_ERROR_NONE) {
|
||||
log_error("%s: Cannot unregister target '%s': CCCSD error %d",
|
||||
__func__, TARGET_GET_TIME, ret);
|
||||
} else if (resp.code != 0) {
|
||||
if (resp.hint)
|
||||
log_error("%s: Cannot unregister target '%s': CCCSD error, %s (%d)",
|
||||
__func__, TARGET_GET_TIME, resp.hint, resp.code);
|
||||
else
|
||||
log_error("%s: Cannot unregister target '%s': CCCSD error, %d",
|
||||
__func__, TARGET_GET_TIME, resp.code);
|
||||
}
|
||||
|
||||
free(resp.hint);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_time_cb() - Data callback for 'get_time' data requests
|
||||
*
|
||||
* @target: Target ID of the data request (get_time).
|
||||
* @req_buf_info: Buffer containing the data request.
|
||||
* @resp_buf_info: Buffer to store the answer of the request.
|
||||
*
|
||||
* Logs information about the received request and executes the corresponding
|
||||
* command.
|
||||
*
|
||||
* Return: 'CCCS_RECEIVE_ERROR_NONE' if success, any other value on failure.
|
||||
*/
|
||||
static cccs_receive_error_t get_time_cb(char const *const target,
|
||||
cccs_buffer_info_t const *const req_buf_info,
|
||||
cccs_buffer_info_t *const resp_buf_info)
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
char *time_str = ctime(&t);
|
||||
|
||||
UNUSED_ARGUMENT(req_buf_info);
|
||||
log_debug("%s: target='%s'", __func__, target);
|
||||
|
||||
resp_buf_info->length = snprintf(NULL, 0, "Time: %s", time_str);
|
||||
resp_buf_info->buffer = calloc(resp_buf_info->length + 1, sizeof(char));
|
||||
if (resp_buf_info->buffer == NULL) {
|
||||
log_error("%s: resp_buf_info calloc error", __func__);
|
||||
|
||||
return CCCS_RECEIVE_ERROR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
resp_buf_info->length = sprintf(resp_buf_info->buffer, "Time: %s", time_str);
|
||||
|
||||
return CCCS_RECEIVE_ERROR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_time_status_cb() - Status callback for 'get_time' data requests
|
||||
*
|
||||
* @target: Target ID of the data request (get_time)
|
||||
* @resp_buf_info: Buffer containing the response data.
|
||||
* @receive_error: The error status of the receive process.
|
||||
* @receive_error_hint: The error hint from the connector service.
|
||||
*
|
||||
* This callback is executed when the response process has finished. It doesn't
|
||||
* matter if everything worked or there was an error during the process.
|
||||
*
|
||||
* Cleans and frees the response buffer.
|
||||
*/
|
||||
static void get_time_status_cb(char const *const target,
|
||||
cccs_buffer_info_t *const resp_buf_info,
|
||||
int receive_error,
|
||||
const char *const receive_error_hint)
|
||||
{
|
||||
log_debug("%s: target='%s' - error='%d' - error-hint='%s'",
|
||||
__func__, target, receive_error, receive_error_hint);
|
||||
|
||||
/* Free the response buffer */
|
||||
if (resp_buf_info != NULL)
|
||||
free(resp_buf_info->buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the following SCI request to test this example (insert your Device ID):
|
||||
*
|
||||
* <sci_request version="1.0">
|
||||
* <data_service>
|
||||
* <targets>
|
||||
* <device id="00000000-00000000-XXXXXXXX-XXXXXXXX"/>
|
||||
* </targets>
|
||||
* <requests>
|
||||
* <device_request target_name="get_time"/>
|
||||
* </requests>
|
||||
* </data_service>
|
||||
* </sci_request>
|
||||
*
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
cccs_comm_error_t ret;
|
||||
char *name = basename(argv[0]);
|
||||
cccs_resp_t resp;
|
||||
int read_char;
|
||||
|
||||
init_logger(LOG_DEBUG, LOG_CONS | LOG_NDELAY | LOG_PID | LOG_PERROR, name);
|
||||
|
||||
register_signals();
|
||||
|
||||
if (!cccs_is_daemon_ready(CCCSD_NO_WAIT)) {
|
||||
log_error("%s: CCCS daemon not ready... exiting", __func__);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ret = cccs_add_request_target(TARGET_GET_TIME, get_time_cb,
|
||||
get_time_status_cb, &resp);
|
||||
if (ret != CCCS_SEND_ERROR_NONE) {
|
||||
log_error("%s: Cannot register target '%s': CCCSD error %d",
|
||||
__func__, TARGET_GET_TIME, ret);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
} else if (resp.code != 0) {
|
||||
if (resp.hint)
|
||||
log_error("%s: Cannot register target '%s': CCCSD error, %s (%d)",
|
||||
__func__, TARGET_GET_TIME, resp.hint, resp.code);
|
||||
else
|
||||
log_error("%s: Cannot register target '%s': CCCSD error, %d",
|
||||
__func__, TARGET_GET_TIME, resp.code);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
free(resp.hint);
|
||||
|
||||
printf("Waiting for Remote Manager request...\n");
|
||||
printf("Press 'q' and 'Enter' to exit\n");
|
||||
do {
|
||||
read_char = getchar();
|
||||
} while (read_char != 'q');
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# Copyright (c) 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.
|
||||
#
|
||||
|
||||
SUBDIRS := \
|
||||
cccs-data-request-example \
|
||||
cccs-upload-data-points-example
|
||||
|
||||
all: $(SUBDIRS)
|
||||
|
||||
.PHONY: $(SUBDIRS)
|
||||
$(SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
|
||||
install clean:
|
||||
for a in $(SUBDIRS); do $(MAKE) -C $$a $@; done
|
||||
|
|
@ -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-upload-data-points-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)
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
Digi ConnectCore Cloud Services Upload Data Points Example Application
|
||||
======================================================================
|
||||
|
||||
Example application to upload data points to Remote Manager using ConnectCore
|
||||
Cloud Services.
|
||||
|
||||
This application uploads an integer value with an incremented counter to a data
|
||||
stream called 'incremental'. The counter value is incremented every 5 seconds.
|
||||
The uploads takes place every 10 new samples, that is every 50 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-upload-data-points-example
|
||||
cccs-upload-data-points-example[1010]: [DEBUG] CCCSD: Connected to CCCSD (s=4)
|
||||
cccs-upload-data-points-example[1010]: [DEBUG] CCCS daemon ready
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 0
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 1
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 2
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 3
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 4
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 5
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 6
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 7
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 8
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 9
|
||||
cccs-upload-data-points-example[1090]: [INFO] Sending data sream with new incremental value
|
||||
cccs-upload-data-points-example[1090]: [INFO] DP: Sending data points to CCCSD
|
||||
cccs-upload-data-points-example[1090]: [DEBUG] CCCSD: Connected to CCCSD (s=4)
|
||||
cccs-upload-data-points-example[1090]: [DEBUG] CCCSD: Success from CCCSD
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 10
|
||||
cccs-upload-data-points-example[1090]: [INFO] Counter = 11
|
||||
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
~$ . <DEY-toolchain-path>/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.
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* 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 <cccs_services.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define STREAM_NAME "incremental"
|
||||
|
||||
#define DP_SLEEP_TIME 5
|
||||
#define DP_NUMBER 10
|
||||
|
||||
static int stop_requested = 0;
|
||||
static cccs_dp_collection_handle_t dp_collection;
|
||||
|
||||
/*
|
||||
* destroy_data_stream() - Destroy the data collection with the included data streams
|
||||
*
|
||||
* @collection: Data point collection to destroy.
|
||||
*
|
||||
* Return: 'CCCS_DP_ERROR_NONE' if success, any other value on failure.
|
||||
*/
|
||||
static cccs_dp_error_t destroy_data_stream(cccs_dp_collection_handle_t collection)
|
||||
{
|
||||
log_debug("%s", "Destroying data collection");
|
||||
|
||||
return cccs_dp_destroy_collection(collection);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = 1;
|
||||
/* 'atexit' executes the cleanup function */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup() - Frees all the allocated memory before exiting
|
||||
*/
|
||||
static void cleanup(void)
|
||||
{
|
||||
if (stop_requested)
|
||||
destroy_data_stream(dp_collection);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_incremental_value() - Retrieves an incremental value each time
|
||||
*
|
||||
* Return: The new counter value.
|
||||
*/
|
||||
static int get_incremental_value(void)
|
||||
{
|
||||
static int counter = -1;
|
||||
|
||||
if (counter == INT_MAX)
|
||||
counter = 0;
|
||||
else
|
||||
counter++;
|
||||
|
||||
log_info("Counter = %d", counter);
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
/*
|
||||
* init_data_stream() - Initialize a data point collection
|
||||
*
|
||||
* @collection: Data point collection to initialize
|
||||
*
|
||||
* This function creates a data point collection and adds the 'incremental'
|
||||
* data stream to it.
|
||||
*
|
||||
* Return: 'CCCS_DP_ERROR_NONE' if success, any other value on failure.
|
||||
*/
|
||||
static cccs_dp_error_t init_data_stream(cccs_dp_collection_handle_t *collection)
|
||||
{
|
||||
cccs_dp_collection_handle_t c;
|
||||
cccs_dp_error_t dp_error;
|
||||
|
||||
dp_error = cccs_dp_create_collection(&c);
|
||||
if (dp_error != CCCS_DP_ERROR_NONE) {
|
||||
log_error("%s: error %d", __func__, dp_error);
|
||||
|
||||
return dp_error;
|
||||
}
|
||||
|
||||
*collection = c;
|
||||
|
||||
dp_error = cccs_dp_add_data_stream_to_collection_extra(c,
|
||||
STREAM_NAME, CCCS_DP_KEY_DATA_INT32, true, "counts", NULL);
|
||||
if (dp_error != CCCS_DP_ERROR_NONE) {
|
||||
log_error("%s: error %d", __func__, dp_error);
|
||||
cccs_dp_destroy_collection(c);
|
||||
*collection = NULL;
|
||||
}
|
||||
|
||||
return dp_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* add_incremental_data_point() - Add a new incremental data point to the collection
|
||||
*
|
||||
* @collection: Data point collection to add the new data point.
|
||||
*
|
||||
* Return: 'CCCS_DP_ERROR_NONE' if success, any other value on failure.
|
||||
*/
|
||||
static cccs_dp_error_t add_incremental_data_point(cccs_dp_collection_handle_t collection)
|
||||
{
|
||||
cccs_dp_error_t dp_error;
|
||||
|
||||
dp_error = cccs_dp_add(collection, STREAM_NAME, get_incremental_value());
|
||||
if (dp_error != CCCS_DP_ERROR_NONE)
|
||||
log_error("%s: failed with error: %d", __func__, dp_error);
|
||||
|
||||
return dp_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* send_data() - Send collected data to ConnectCore Cloud Services daemon
|
||||
*
|
||||
* @collection: Data point collection to with the data to send.
|
||||
*
|
||||
* Return: 0 if success, any other value on failure.
|
||||
*/
|
||||
static int send_data(cccs_dp_collection_handle_t collection)
|
||||
{
|
||||
cccs_comm_error_t ret;
|
||||
cccs_resp_t resp;
|
||||
|
||||
log_info("%s", "Sending data sream with new incremental value");
|
||||
|
||||
ret = cccs_send_dp_collection_tout(collection, 5, &resp);
|
||||
if (ret != CCCS_SEND_ERROR_NONE) {
|
||||
log_error("%s: error sending data points: CCCSD error %d", __func__, ret);
|
||||
} else if (resp.code != 0) {
|
||||
if (resp.hint)
|
||||
log_error("%s: error sending data points: CCCSD error %s (%d)", __func__, resp.hint, resp.code);
|
||||
else
|
||||
log_error("%s: error sending data points: CCCSD error %d", __func__, resp.code);
|
||||
}
|
||||
|
||||
free(resp.hint);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *name = basename(argv[0]);
|
||||
cccs_dp_error_t dp_error;
|
||||
int i;
|
||||
|
||||
init_logger(LOG_DEBUG, LOG_CONS | LOG_NDELAY | LOG_PID | LOG_PERROR, name);
|
||||
|
||||
register_signals();
|
||||
|
||||
if (!cccs_is_daemon_ready(CCCSD_NO_WAIT)) {
|
||||
log_error("%s: CCCS daemon not ready... exiting", __func__);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dp_error = init_data_stream(&dp_collection);
|
||||
if (dp_error != CCCS_DP_ERROR_NONE) {
|
||||
log_error("%s: Cannot initialize data stream, error %d",
|
||||
__func__, dp_error);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
stop_requested = 0;
|
||||
while (!stop_requested) {
|
||||
/* Collect DP_NUMBER data points sampled each DP_SLEEP_TIME seconds */
|
||||
for (i = 0; i < DP_NUMBER; i++) {
|
||||
dp_error = add_incremental_data_point(dp_collection);
|
||||
|
||||
if (dp_error != CCCS_DP_ERROR_NONE) {
|
||||
log_error("%s: Cannot add data point, error %d",
|
||||
__func__, dp_error);
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i + 1 < DP_NUMBER)
|
||||
sleep(DP_SLEEP_TIME);
|
||||
}
|
||||
|
||||
/* Send the block of collected data points */
|
||||
send_data(dp_collection);
|
||||
|
||||
if (i == DP_NUMBER)
|
||||
sleep(DP_SLEEP_TIME);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -223,4 +223,51 @@ A key modifier may be used to further differentiate the key used in a particular
|
|||
<platform>ccimx8mm-dvk</platform>
|
||||
</platforms>
|
||||
</sample>
|
||||
<sample id="cccs-data-request-example">
|
||||
<name>Digi CCCS data request Example</name>
|
||||
<description>
|
||||
Example application to listen to data requests from Remote Manager using
|
||||
ConnectCore Cloud Services.
|
||||
This application registers a `get_time` data request.
|
||||
When this request arrives the application sends back the current time.
|
||||
</description>
|
||||
<path>cccs-data-request-example</path>
|
||||
<platforms>
|
||||
<platform>ccimx6sbc</platform>
|
||||
<platform>ccimx6qpsbc</platform>
|
||||
<platform>ccimx6ulstarter</platform>
|
||||
<platform>ccimx6ulsbc</platform>
|
||||
<platform>ccimx8x-sbc-express</platform>
|
||||
<platform>ccimx8x-sbc-pro</platform>
|
||||
<platform>ccimx8mn-dvk</platform>
|
||||
<platform>ccimx8mm-dvk</platform>
|
||||
<platform>ccmp15-dvk</platform>
|
||||
<platform>ccmp13-dvk</platform>
|
||||
<platform>ccimx93-dvk</platform>
|
||||
</platforms>
|
||||
</sample>
|
||||
<sample id="cccs-upload-data-points-example">
|
||||
<name>Digi CCCS upload data points Example</name>
|
||||
<description>
|
||||
Example application to upload data points to Remote Manager using ConnectCore
|
||||
Cloud Services.
|
||||
This application uploads an integer value with an incremented counter to a data
|
||||
stream called 'incremental'. The counter value is incremented every 5 seconds.
|
||||
The uploads takes place every 10 new samples, that is every 50 seconds.
|
||||
</description>
|
||||
<path>cccs-upload-data-points-example</path>
|
||||
<platforms>
|
||||
<platform>ccimx6sbc</platform>
|
||||
<platform>ccimx6qpsbc</platform>
|
||||
<platform>ccimx6ulstarter</platform>
|
||||
<platform>ccimx6ulsbc</platform>
|
||||
<platform>ccimx8x-sbc-express</platform>
|
||||
<platform>ccimx8x-sbc-pro</platform>
|
||||
<platform>ccimx8mn-dvk</platform>
|
||||
<platform>ccimx8mm-dvk</platform>
|
||||
<platform>ccmp15-dvk</platform>
|
||||
<platform>ccmp13-dvk</platform>
|
||||
<platform>ccimx93-dvk</platform>
|
||||
</platforms>
|
||||
</sample>
|
||||
</samples>
|
||||
|
|
|
|||
Loading…
Reference in New Issue