diff --git a/demos/high_res/adc.c b/demos/high_res/adc.c new file mode 100644 index 000000000000..8cbd9ad87e3e --- /dev/null +++ b/demos/high_res/adc.c @@ -0,0 +1,850 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Industrialio buffer test code. + * + * Copyright (c) 2008 Jonathan Cameron + * + * This program is primarily intended as an example application. + * Reads the current buffer setup from sysfs and starts a short capture + * from the specified device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" +#include "lv_demo_high_res_private.h" + +static lv_demo_high_res_api_t * api_hmi; +static struct mosquitto *mosq; +extern int back_pressed_adc; +int flag_is_connected = 0; +void publish_sensor_data(float); + +/** + * enum autochan - state for the automatic channel enabling mechanism + */ +enum autochan { + AUTOCHANNELS_DISABLED, + AUTOCHANNELS_ENABLED, + AUTOCHANNELS_ACTIVE, +}; + +/* Callback called when the client receives a CONNACK message from the broker. */ +void on_connect_temp_pub(struct mosquitto *mosq, void *obj, int reason_code) +{ + /* Print out the connection result. mosquitto_connack_string() produces an + * appropriate string for MQTT v3.x clients, the equivalent for MQTT v5.0 + * clients is mosquitto_reason_string(). + */ + printf("on_connect: %s\n", mosquitto_connack_string(reason_code)); + if(reason_code != 0){ + /* If the connection fails for any reason, we don't want to keep on + * retrying in this example, so disconnect. Without this, the client + * will attempt to reconnect. */ + mosquitto_disconnect(mosq); + } + + /* You may wish to set a flag here to indicate to your application that the + * client is now connected. */ +} + +/* Callback called when the client knows to the best of its abilities that a + * PUBLISH has been successfully sent. For QoS 0 this means the message has + * been completely written to the operating system. For QoS 1 this means we + * have received a PUBACK from the broker. For QoS 2 this means we have + * received a PUBCOMP from the broker. */ +void on_publish_temp_pub(struct mosquitto *mosq, void *obj, int mid) +{ + // printf("Message with mid %d has been published.\n", mid); +} + +/* This function pretends to read some data from a sensor and publish it.*/ +void publish_sensor_data(float temp) +{ + if(!flag_is_connected){ + return; + } + char payload[20]; + int rc; + + /* Print it to a string for easy human reading - payload format is highly + * application dependent. */ + snprintf(payload, sizeof(payload), "%1f", temp); + + /* Publish the message + * mosq - our client instance + * *mid = NULL - we don't want to know what the message id for this message is + * topic = "example/temperature" - the topic on which this message will be published + * payloadlen = strlen(payload) - the length of our payload in bytes + * payload - the actual payload + * qos = 1 - publish with QoS 1 for this example + * retain = false - do not use the retained message feature for this message + */ + rc = mosquitto_publish(mosq, NULL, "SmartHome/temp", strlen(payload), payload, 1, false); + if(rc != MOSQ_ERR_SUCCESS){ + fprintf(stderr, "Error publishing: %s\n", mosquitto_strerror(rc)); + } +} + +void publish_evCharge_data(int ev_charge) +{ + if(!flag_is_connected){ + return; + } + char payload[20]; + int rc; + + /* Print it to a string for easy human reading - payload format is highly + * application dependent. */ + snprintf(payload, sizeof(payload), "%d", ev_charge); + + /* Publish the message + * mosq - our client instance + * *mid = NULL - we don't want to know what the message id for this message is + * topic = "example/temperature" - the topic on which this message will be published + * payloadlen = strlen(payload) - the length of our payload in bytes + * payload - the actual payload + * qos = 1 - publish with QoS 1 for this example + * retain = false - do not use the retained message feature for this message + */ + rc = mosquitto_publish(mosq, NULL, "SmartHome/evCharge", strlen(payload), payload, 1, false); + if(rc != MOSQ_ERR_SUCCESS){ + fprintf(stderr, "Error publishing: %s\n", mosquitto_strerror(rc)); + } +} + +int mqtt_temp_pub_init(){ + + int rc; + + /* Required before calling other mosquitto functions */ + mosquitto_lib_init(); + + /* Create a new client instance. + * id = NULL -> ask the broker to generate a client id for us + * clean session = true -> the broker should remove old sessions when we connect + * obj = NULL -> we aren't passing any of our private data for callbacks + */ + mosq = mosquitto_new(NULL, true, NULL); + if(mosq == NULL){ + fprintf(stderr, "Error: Out of memory.\n"); + return 1; + } + + /* Configure callbacks. This should be done before connecting ideally. */ + mosquitto_connect_callback_set(mosq, on_connect_temp_pub); + mosquitto_publish_callback_set(mosq, on_publish_temp_pub); + + /* Connect to test.mosquitto.org on port 1883, with a keepalive of 60 seconds. + * This call makes the socket connection only, it does not complete the MQTT + * CONNECT/CONNACK flow, you should use mosquitto_loop_start() or + * mosquitto_loop_forever() for processing net traffic. */ + //rc = mosquitto_connect(mosq, "test.mosquitto.org", 1883, 60); + + int err = mosquitto_tls_set(mosq, "/usr/share/ti-lvgl-demo/cert/AmazonRootCA1.pem", NULL, NULL, NULL, NULL); + if (err != MOSQ_ERR_SUCCESS){ + printf("TLS not set\n"); + } + + rc = mosquitto_connect(mosq, "broker.hivemq.com", 8883, 60); + if(rc != MOSQ_ERR_SUCCESS){ + flag_is_connected = 0; + mosquitto_destroy(mosq); + fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); + return 1; + } + else{ + flag_is_connected = 1; + } + + /* Run the network loop in a background thread, this call returns quickly. */ + rc = mosquitto_loop_start(mosq); + if(rc != MOSQ_ERR_SUCCESS){ + flag_is_connected = 0; + mosquitto_destroy(mosq); + fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); + return 1; + } + else{ + flag_is_connected = 1; + } + + return 0; +} + +/** + * size_from_channelarray() - calculate the storage size of a scan + * @channels: the channel info array + * @num_channels: number of channels + * + * Has the side effect of filling the channels[i].location values used + * in processing the buffer output. + **/ +static unsigned int size_from_channelarray(struct iio_channel_info *channels, int num_channels) +{ + unsigned int bytes = 0; + int i = 0, max = 0; + unsigned int misalignment; + + while (i < num_channels) { + if (channels[i].bytes > max) + max = channels[i].bytes; + if (bytes % channels[i].bytes == 0) + channels[i].location = bytes; + else + channels[i].location = bytes - bytes % channels[i].bytes + + channels[i].bytes; + + bytes = channels[i].location + channels[i].bytes; + i++; + } + /* + * We want the data in next sample to also be properly aligned so + * we'll add padding at the end if needed. Adding padding only + * works for channel data which size is 2^n bytes. + */ + misalignment = bytes % max; + if (misalignment) + bytes += max - misalignment; + + return bytes; +} + +static void print1byte(uint8_t input, struct iio_channel_info *info) +{ + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + if (info->is_signed) { + int8_t val = (int8_t)(input << (8 - info->bits_used)) >> + (8 - info->bits_used); + printf("1ubyte:%d ", val); + printf("%05f ", ((float)val + info->offset) * info->scale); + } else { + printf("%05f ", ((float)input + info->offset) * info->scale); + printf("1sbyte:%d ", input); + } +} + +static void print2byte(uint16_t input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be16toh(input); + else + input = le16toh(input); + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + + lv_lock(); + lv_subject_set_int(&api_hmi->subjects.temperature_indoor, input); + lv_subject_set_int(&api_hmi->subjects.temperature_outdoor, input-65); + lv_unlock(); + publish_sensor_data(input/10.0); +} + +static void print4byte(uint32_t input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be32toh(input); + else + input = le32toh(input); + + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + if (info->is_signed) { + int32_t val = (int32_t)(input << (32 - info->bits_used)) >> + (32 - info->bits_used); + printf("4ubyte:%d ", val); + printf("%05f ", ((float)val + info->offset) * info->scale); + } else { + printf("%05f ", ((float)input + info->offset) * info->scale); + printf("4sbyte:%d ", input); + } +} + +static void print8byte(uint64_t input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be64toh(input); + else + input = le64toh(input); + + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + if (info->is_signed) { + int64_t val = (int64_t)(input << (64 - info->bits_used)) >> + (64 - info->bits_used); + /* special case for timestamp */ + if (info->scale == 1.0f && info->offset == 0.0f) + printf("%" PRId64 " ", val); + else + printf("%05f ", + ((float)val + info->offset) * info->scale); + } else { + printf("%05f ", ((float)input + info->offset) * info->scale); + printf("8sbyte:%d ", input); + } +} + +/** + * process_scan() - print out the values in SI units + * @data: pointer to the start of the scan + * @channels: information about the channels. + * Note: size_from_channelarray must have been called first + * to fill the location offsets. + * @num_channels: number of channels + **/ +static void process_scan(char *data, struct iio_channel_info *channels, + int num_channels) +{ + int k=0; + switch (channels[k].bytes) { + /* only a few cases implemented so far */ + case 1: + print1byte(*(uint8_t *)(data + channels[k].location), + &channels[k]); + break; + case 2: + print2byte(*(uint16_t *)(data + channels[k].location), + &channels[k]); + break; + case 4: + print4byte(*(uint32_t *)(data + channels[k].location), + &channels[k]); + break; + case 8: + print8byte(*(uint64_t *)(data + channels[k].location), + &channels[k]); + break; + default: + break; + } +} + +static int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable) +{ + const struct dirent *ent; + char scanelemdir[256]; + DIR *dp; + int ret; + + snprintf(scanelemdir, sizeof(scanelemdir), + FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx); + scanelemdir[sizeof(scanelemdir)-1] = '\0'; + + dp = opendir(scanelemdir); + if (!dp) { + fprintf(stderr, "Enabling/disabling channels: can't open %s\n", + scanelemdir); + return -EIO; + } + + ret = -ENOENT; + while (ent = readdir(dp), ent) { + if (iioutils_check_suffix(ent->d_name, "_en")) { + printf("%sabling: %s\n", + enable ? "En" : "Dis", + ent->d_name); + ret = write_sysfs_int(ent->d_name, scanelemdir, + enable); + if (ret < 0) + fprintf(stderr, "Failed to enable/disable %s\n", + ent->d_name); + } + } + + if (closedir(dp) == -1) { + perror("Enabling/disabling channels: " + "Failed to close directory"); + return -errno; + } + return 0; +} + +static void print_usage(void) +{ + fprintf(stderr, "Usage: generic_buffer [options]...\n" + "Capture, convert and output data from IIO device buffer\n" + " -a Auto-activate all available channels\n" + " -A Force-activate ALL channels\n" + " -b The buffer which to open (by index), default 0\n" + " -c Do n conversions, or loop forever if n < 0\n" + " -e Disable wait for event (new data)\n" + " -g Use trigger-less mode\n" + " -l Set buffer length to n samples\n" + " --device-name -n \n" + " --device-num -N \n" + " Set device by name or number (mandatory)\n" + " --trigger-name -t \n" + " --trigger-num -T \n" + " Set trigger by name or number\n" + " -w Set delay between reads in us (event-less mode)\n"); +} + +static enum autochan autochannels = AUTOCHANNELS_ENABLED; +static char *dev_dir_name = NULL; +static char *buf_dir_name = NULL; +static int buffer_idx = 0; +static bool current_trigger_set = false; + +static void cleanup(void) +{ + int ret; + + /* Disable trigger */ + if (dev_dir_name && current_trigger_set) { + /* Disconnect the trigger - just write a dummy name. */ + ret = write_sysfs_string("trigger/current_trigger", + dev_dir_name, "NULL"); + if (ret < 0) + fprintf(stderr, "Failed to disable trigger: %s\n", + strerror(-ret)); + current_trigger_set = false; + } + + /* Disable buffer */ + if (buf_dir_name) { + ret = write_sysfs_int("enable", buf_dir_name, 0); + if (ret < 0) + fprintf(stderr, "Failed to disable buffer: %s\n", + strerror(-ret)); + } + + /* Disable channels if auto-enabled */ + if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 0); + if (ret) + fprintf(stderr, "Failed to disable all channels\n"); + autochannels = AUTOCHANNELS_DISABLED; + } +} + +static void sig_handler(int signum) +{ + fprintf(stderr, "Caught signal %d\n", signum); + cleanup(); + exit(-signum); +} + +static void register_cleanup(void) +{ + struct sigaction sa = { .sa_handler = sig_handler }; + const int signums[] = { SIGINT, SIGTERM, SIGABRT }; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(signums); ++i) { + ret = sigaction(signums[i], &sa, NULL); + if (ret) { + perror("Failed to register signal handler"); + exit(-1); + } + } +} + +static const struct option longopts[] = { + { "device-name", 1, 0, 'n' }, + { "device-num", 1, 0, 'N' }, + { "trigger-name", 1, 0, 't' }, + { "trigger-num", 1, 0, 'T' }, + { }, +}; + +int *adc_init(lv_demo_high_res_api_t * api) +{ + api_hmi = api; + mqtt_temp_pub_init(); + long long num_loops = 2; + unsigned long timedelay = 1000000; + unsigned long buf_len = 128; + + ssize_t i; + unsigned long long j; + unsigned long toread; + int ret; + struct stat st; + int fd = -1; + int buf_fd = -1; + + int num_channels = 0; + char *trigger_name = NULL, *device_name = NULL; + + char *data = NULL; + ssize_t read_size; + int dev_num = 0, trig_num = -1; + char *buffer_access = NULL; + unsigned int scan_size; + int noevents = 0; + int notrigger = 1; + char *dummy; + bool force_autochannels = false; + + struct iio_channel_info *channels = NULL; + + register_cleanup(); + + /* Find the device requested */ + if (dev_num < 0 && !device_name) { + fprintf(stderr, "Device not set\n"); + print_usage(); + ret = -1; + goto error; + } else if (dev_num >= 0 && device_name) { + fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); + print_usage(); + ret = -1; + goto error; + } else if (dev_num < 0) { + dev_num = find_type_by_name(device_name, "iio:device"); + if (dev_num < 0) { + fprintf(stderr, "Failed to find the %s\n", device_name); + ret = dev_num; + goto error; + } + } + printf("iio device number being used is %d\n", dev_num); + + ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); + if (ret < 0) + return -ENOMEM; + /* Fetch device_name if specified by number */ + if (!device_name) { + device_name = malloc(IIO_MAX_NAME_LENGTH); + if (!device_name) { + ret = -ENOMEM; + goto error; + } + ret = read_sysfs_string("name", dev_dir_name, device_name); + if (ret < 0) { + fprintf(stderr, "Failed to read name of device %d\n", dev_num); + goto error; + } + } + + if (notrigger) { + printf("trigger-less mode selected\n"); + } else if (trig_num >= 0) { + char *trig_dev_name; + ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); + if (ret < 0) { + return -ENOMEM; + } + trigger_name = malloc(IIO_MAX_NAME_LENGTH); + if (!trigger_name) { + ret = -ENOMEM; + goto error; + } + ret = read_sysfs_string("name", trig_dev_name, trigger_name); + free(trig_dev_name); + if (ret < 0) { + fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); + return ret; + } + printf("iio trigger number being used is %d\n", trig_num); + } else { + if (!trigger_name) { + /* + * Build the trigger name. If it is device associated + * its name is _dev[n] where n matches + * the device number found above. + */ + ret = asprintf(&trigger_name, + "%s-dev%d", device_name, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error; + } + } + + /* Look for this "-devN" trigger */ + trig_num = find_type_by_name(trigger_name, "trigger"); + if (trig_num < 0) { + /* OK try the simpler "-trigger" suffix instead */ + free(trigger_name); + ret = asprintf(&trigger_name, + "%s-trigger", device_name); + if (ret < 0) { + ret = -ENOMEM; + goto error; + } + } + + trig_num = find_type_by_name(trigger_name, "trigger"); + if (trig_num < 0) { + fprintf(stderr, "Failed to find the trigger %s\n", + trigger_name); + ret = trig_num; + goto error; + } + + printf("iio trigger number being used is %d\n", trig_num); + } + + /* + * Parse the files in scan_elements to identify what channels are + * present + */ + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels); + if (ret) { + fprintf(stderr, "Problem reading scan element information\n" + "diag %s\n", dev_dir_name); + goto error; + } + if (num_channels && autochannels == AUTOCHANNELS_ENABLED && + !force_autochannels) { + fprintf(stderr, "Auto-channels selected but some channels " + "are already activated in sysfs\n"); + fprintf(stderr, "Proceeding without activating any channels\n"); + } + + if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || + (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { + fprintf(stderr, "Enabling all channels\n"); + + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 1); + if (ret) { + fprintf(stderr, "Failed to enable all channels\n"); + goto error; + } + + /* This flags that we need to disable the channels again */ + autochannels = AUTOCHANNELS_ACTIVE; + + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, + &num_channels); + if (ret) { + fprintf(stderr, "Problem reading scan element " + "information\n" + "diag %s\n", dev_dir_name); + goto error; + } + if (!num_channels) { + fprintf(stderr, "Still no channels after " + "auto-enabling, giving up\n"); + goto error; + } + } + + if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { + fprintf(stderr, + "No channels are enabled, we have nothing to scan.\n"); + fprintf(stderr, "Enable channels manually in " + FORMAT_SCAN_ELEMENTS_DIR + "/*_en or pass -a to autoenable channels and " + "try again.\n", dev_dir_name, buffer_idx); + ret = -ENOENT; + goto error; + } + + /* + * Construct the directory name for the associated buffer. + * As we know that the lis3l02dq has only one buffer this may + * be built rather than found. + */ + ret = asprintf(&buf_dir_name, + "%siio:device%d/buffer%d", iio_dir, dev_num, buffer_idx); + if (ret < 0) { + ret = -ENOMEM; + goto error; + } + + if (stat(buf_dir_name, &st)) { + fprintf(stderr, "Could not stat() '%s', got error %d: %s\n", + buf_dir_name, errno, strerror(errno)); + ret = -errno; + goto error; + } + + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "File '%s' is not a directory\n", buf_dir_name); + ret = -EFAULT; + goto error; + } + + if (!notrigger) { + printf("%s %s\n", dev_dir_name, trigger_name); + /* + * Set the device trigger to be the data ready trigger found + * above + */ + ret = write_sysfs_string_and_verify("trigger/current_trigger", + dev_dir_name, + trigger_name); + if (ret < 0) { + fprintf(stderr, + "Failed to write current_trigger file\n"); + goto error; + } + } + + ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error; + } + + /* Attempt to open non blocking the access dev */ + fd = open(buffer_access, O_RDONLY | O_NONBLOCK); + if (fd == -1) { /* TODO: If it isn't there make the node */ + ret = -errno; + fprintf(stderr, "Failed to open %s\n", buffer_access); + goto error; + } + + /* specify for which buffer index we want an FD */ + buf_fd = buffer_idx; + + ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &buf_fd); + if (ret == -1 || buf_fd == -1) { + ret = -errno; + if (ret == -ENODEV || ret == -EINVAL) + fprintf(stderr, + "Device does not have this many buffers\n"); + else + fprintf(stderr, "Failed to retrieve buffer fd\n"); + + goto error; + } + + /* Setup ring buffer parameters */ + ret = write_sysfs_int("length", buf_dir_name, buf_len); + if (ret < 0) + goto error; + + /* Enable the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 1); + if (ret < 0) { + fprintf(stderr, + "Failed to enable buffer '%s': %s\n", + buf_dir_name, strerror(-ret)); + goto error; + } + + scan_size = size_from_channelarray(channels, num_channels); + + size_t total_buf_len = scan_size * buf_len; + + if (scan_size > 0 && total_buf_len / scan_size != buf_len) { + ret = -EFAULT; + perror("Integer overflow happened when calculate scan_size * buf_len"); + goto error; + } + + data = malloc(total_buf_len); + if (!data) { + ret = -ENOMEM; + goto error; + } + + /** + * This check is being done here for sanity reasons, however it + * should be omitted under normal operation. + * If this is buffer0, we check that we get EBUSY after this point. + */ + if (buffer_idx == 0) { + errno = 0; + read_size = read(fd, data, 1); + if (read_size > -1 || errno != EBUSY) { + ret = -EFAULT; + perror("Reading from '%s' should not be possible after ioctl()"); + goto error; + } + } + + /* close now the main chardev FD and let the buffer FD work */ + if (close(fd) == -1) + perror("Failed to close character device file"); + fd = -1; + + while(1) { + if (!noevents) { + struct pollfd pfd = { + .fd = buf_fd, + .events = POLLIN, + }; + + ret = poll(&pfd, 1, -1); + if (ret < 0) { + ret = -errno; + goto error; + } else if (ret == 0) { + continue; + } + + } else { + usleep(timedelay); + } + + toread = buf_len; + + read_size = read(buf_fd, data, toread * scan_size); + if (read_size < 0) { + if (errno == EAGAIN) { + fprintf(stderr, "nothing available\n"); + continue; + } else { + break; + } + } + process_scan(data + scan_size * i, channels, + num_channels); + usleep(500000); + } + mosquitto_lib_cleanup(); + +error: + cleanup(); + mosquitto_lib_cleanup(); + + if (fd >= 0 && close(fd) == -1) + perror("Failed to close character device"); + if (buf_fd >= 0 && close(buf_fd) == -1) + perror("Failed to close buffer"); + free(buffer_access); + free(data); + free(buf_dir_name); + for (i = num_channels - 1; i >= 0; i--) { + free(channels[i].name); + free(channels[i].generic_name); + } + free(channels); + free(trigger_name); + free(device_name); + free(dev_dir_name); + + return ret; +} \ No newline at end of file diff --git a/demos/high_res/assets/ti-logo.png b/demos/high_res/assets/ti-logo.png new file mode 100644 index 000000000000..cc81cf9c08ef Binary files /dev/null and b/demos/high_res/assets/ti-logo.png differ diff --git a/demos/high_res/audio.c b/demos/high_res/audio.c new file mode 100644 index 000000000000..c7e919870340 --- /dev/null +++ b/demos/high_res/audio.c @@ -0,0 +1,136 @@ +/* + * Simple sound playback using ALSA API and libasound. + * + * Compile: + * $ cc -o play sound_playback.c -lasound + * + * Copyright (C) 2009 Alessandro Ghedini + * -------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * Alessandro Ghedini wrote this file. As long as you retain this + * notice you can do whatever you want with this stuff. If we + * meet some day, and you think this stuff is worth it, you can + * buy me a beer in return. + * -------------------------------------------------------------- + */ + +#include +#include +#include + +#define PCM_DEVICE "default" +extern pthread_mutex_t playing_now_lock; +extern int playing_now; + +void *audio_play() { + unsigned int pcm, tmp, dir; + int rate, channels, seconds; + snd_pcm_t *pcm_handle; + snd_pcm_hw_params_t *params; + snd_pcm_uframes_t frames; + char *buff; + int buff_size, loops; + + rate = 44100; + channels = 2; + seconds = 30; + + /* Open the PCM device in playback mode */ + if (pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0){ + printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(pcm)); + return; + } + + /* Allocate parameters object and fill it with default values*/ + snd_pcm_hw_params_alloca(¶ms); + + snd_pcm_hw_params_any(pcm_handle, params); + + /* Set parameters */ + if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0){ + printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm)); + return; + } + + if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE) < 0){ + printf("ERROR: Can't set format. %s\n", snd_strerror(pcm)); + return; + } + + if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels) < 0){ + printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm)); + return; + } + + if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0){ + printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm)); + return; + } + + /* Write parameters */ + if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0){ + printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm)); + return; + } + + /* Resume information */ + printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle)); + + printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle))); + + snd_pcm_hw_params_get_channels(params, &tmp); + printf("channels: %i ", tmp); + + if (tmp == 1) + printf("(mono)\n"); + else if (tmp == 2) + printf("(stereo)\n"); + + snd_pcm_hw_params_get_rate(params, &tmp, 0); + printf("rate: %d bps\n", tmp); + + printf("seconds: %d\n", seconds); + + /* Allocate buffer to hold single period */ + snd_pcm_hw_params_get_period_size(params, &frames, 0); + + buff_size = frames * channels * 2 /* 2 -> sample size */; + buff = (char *) malloc(buff_size); + + snd_pcm_hw_params_get_period_time(params, &tmp, NULL); + + while(1){ + int fd = open("/usr/share/ti-lvgl-demo/audio/mixkit-game-show-suspense-waiting-667.wav", O_RDONLY); + if (fd == -1) { + perror("Error opening audio file"); + return; + } + for (loops = (seconds * 1000000) / tmp; loops > 0; loops--) { + while(1){ + pthread_mutex_lock(&playing_now_lock); + if(playing_now){ + pcm = snd_pcm_pause(pcm_handle, 0); + pthread_mutex_unlock(&playing_now_lock); + break; + }else{ + pcm = snd_pcm_pause(pcm_handle, 1); + } + pthread_mutex_unlock(&playing_now_lock); + usleep(250000); + } + + if (pcm = read(fd, buff, buff_size) == 0) { + printf("Early end of file.\n"); + return 0; + } + + if (pcm = snd_pcm_writei(pcm_handle, buff, frames) == -EPIPE) { + printf("XRUN.\n"); + snd_pcm_prepare(pcm_handle); + } else if (pcm < 0) { + printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm)); + } + } + close(fd); + } +} \ No newline at end of file diff --git a/demos/high_res/button.c b/demos/high_res/button.c new file mode 100644 index 000000000000..b6737d9d4c7e --- /dev/null +++ b/demos/high_res/button.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include "lv_demo_high_res_private.h" + +int button_configured = 0; + +const char *ev_type[EV_CNT] = { + [EV_SYN] = "EV_SYN", + [EV_KEY] = "EV_KEY", + [EV_REL] = "EV_REL", + [EV_ABS] = "EV_ABS", + [EV_MSC] = "EV_MSC", + [EV_SW] = "EV_SW", + [EV_LED] = "EV_LED", + [EV_SND] = "EV_SND", + [EV_REP] = "EV_REP", + [EV_FF] = "EV_FF", + [EV_PWR] = "EV_PWR", + [EV_FF_STATUS] = "EV_FF_STATUS", + [EV_MAX] = "EV_MAX", +}; + +const char *ev_code_syn[SYN_CNT] = { + [SYN_REPORT] = "SYN_REPORT", + [SYN_CONFIG] = "SYN_CONFIG", + [SYN_MT_REPORT] = "SYN_MT_REPORT", + [SYN_DROPPED] = "SYN_DROPPED", + [SYN_MAX] = "SYN_MAX", +}; + +void *button_init(lv_demo_high_res_api_t * api) +{ + int fd; + char dev[] = "/dev/input/eventX"; + struct input_event ie; + + char buffer[128]; + FILE *fp = popen("cat /proc/bus/input/devices | grep Phys=gpio-keys/input", "r"); + + if (fp == NULL) { + perror("popen failed"); + return 1; + } + + if (fgets(buffer, sizeof(buffer), fp) != NULL) { + int len_dev = strlen(dev); + int len_buffer = strlen(buffer); + dev[len_dev - 1] = buffer[len_buffer - 2]; + button_configured = 1; + } + else{ + printf("Button not Configured\n"); + return 0; + } + + if ((fd = open(dev, O_RDONLY)) == -1) { + perror("opening device"); + exit(EXIT_FAILURE); + } + + int last_val=-1; + int curr_val=-1; + while (read(fd, &ie, sizeof(struct input_event))) { + if(ie.type != 1) + continue; + curr_val = ie.value; + if(curr_val==0 && last_val > 0){ + fprintf(stderr, "Button Released!!\n"); + lv_lock(); + int lock_status = lv_subject_get_int(&api->subjects.locked); + lv_subject_set_int(&api->subjects.locked, !lock_status); + lv_unlock(); + } + last_val = curr_val; + } + + close(fd); + + return EXIT_SUCCESS; +} diff --git a/demos/high_res/clock.c b/demos/high_res/clock.c new file mode 100644 index 000000000000..e20958415840 --- /dev/null +++ b/demos/high_res/clock.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include "lv_demo_high_res_private.h" + + +static void slice(const char* str, char* result, size_t start, size_t end) { + strncpy(result, str + start, end - start); +} + +void *clock_init(lv_demo_high_res_api_t * api) { + int last_minute = -1; + while(1){ + char buffer[128]; + FILE *fp = popen("date", "r"); + + if (fp == NULL) { + perror("popen failed"); + return 1; + } + + if (fgets(buffer, sizeof(buffer), fp) == NULL) { + continue; + } + + char day[10]; + char sliced_day[5]; + slice(buffer, sliced_day, 0, 0 + 3); + if(strcmp(sliced_day, "Mon")==0){ + strcpy(day, "Monday"); + } + else if(strcmp(sliced_day, "Tue")==0){ + strcpy(day, "Tuesday"); + } + else if(strcmp(sliced_day, "Wed")==0){ + strcpy(day, "Wednesday"); + } + else if(strcmp(sliced_day, "Thu")==0){ + strcpy(day, "Thursday"); + } + else if(strcmp(sliced_day, "Fri")==0){ + strcpy(day, "Friday"); + } + else if(strcmp(sliced_day, "Sat")==0){ + strcpy(day, "Saturday"); + } + else if(strcmp(sliced_day, "Sun")==0){ + strcpy(day, "Sunday"); + } + + char month[10]; + char sliced_month[5]; + slice(buffer, sliced_month, 4, 4 + 3); + if(strcmp(sliced_month, "Jan")==0){ + strcpy(month, "January"); + } + else if(strcmp(sliced_month, "Feb")==0){ + strcpy(month, "February"); + } + else if(strcmp(sliced_month, "Mar")==0){ + strcpy(month, "March"); + } + else if(strcmp(sliced_month, "Apr")==0){ + strcpy(month, "April"); + } + else if(strcmp(sliced_month, "May")==0){ + strcpy(month, "May"); + } + else if(strcmp(sliced_month, "Jun")==0){ + strcpy(month, "June"); + } + else if(strcmp(sliced_month, "Jul")==0){ + strcpy(month, "July"); + } + else if(strcmp(sliced_month, "Aug")==0){ + strcpy(month, "August"); + } + else if(strcmp(sliced_month, "Sep")==0){ + strcpy(month, "September"); + } + else if(strcmp(sliced_month, "Oct")==0){ + strcpy(month, "October"); + } + else if(strcmp(sliced_month, "Nov")==0){ + strcpy(month, "November"); + } + else if(strcmp(sliced_month, "Dec")==0){ + strcpy(month, "December"); + } + + char sliced_date[4]; + slice(buffer, sliced_date, 8, 8 + 2); + int date = atoi(sliced_date); + + char sliced_hour[4]; + slice(buffer, sliced_hour, 11, 11 + 2); + int hour = atoi(sliced_hour); + + char sliced_minute[4]; + slice(buffer, sliced_minute, 14, 14 + 2); + int minute = atoi(sliced_minute); + if(last_minute==-1){ + lv_lock(); + lv_subject_set_pointer(&api->subjects.month_name, month); + lv_subject_set_int(&api->subjects.month_day, date); + lv_subject_set_pointer(&api->subjects.week_day_name, day); + lv_subject_set_int(&api->subjects.hour, hour); + lv_subject_set_int(&api->subjects.minute, minute); + lv_unlock(); + last_minute = minute; + } + + char sliced_year[4]; + slice(buffer, sliced_year, 24, 24 + 4); + int year = atoi(sliced_year); + + pclose(fp); + + if(last_minute != minute){ + lv_lock(); + lv_subject_set_pointer(&api->subjects.month_name, month); + lv_subject_set_int(&api->subjects.month_day, date); + lv_subject_set_pointer(&api->subjects.week_day_name, day); + lv_subject_set_int(&api->subjects.hour, hour); + lv_subject_set_int(&api->subjects.minute, minute); + lv_unlock(); + } + last_minute = minute; + usleep(1000000); + } +} \ No newline at end of file diff --git a/demos/high_res/iio_utils.c b/demos/high_res/iio_utils.c new file mode 100644 index 000000000000..c5c5082cb24e --- /dev/null +++ b/demos/high_res/iio_utils.c @@ -0,0 +1,988 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* IIO - useful set of util functionality + * + * Copyright (c) 2008 Jonathan Cameron + */ +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + +const char *iio_dir = "/sys/bus/iio/devices/"; + +static char * const iio_direction[] = { + "in", + "out", +}; + +/** + * iioutils_break_up_name() - extract generic name from full channel name + * @full_name: the full channel name + * @generic_name: the output generic channel name + * + * Returns 0 on success, or a negative error code if string extraction failed. + **/ +int iioutils_break_up_name(const char *full_name, char **generic_name) +{ + char *current; + char *w, *r; + char *working, *prefix = ""; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(iio_direction); i++) + if (!strncmp(full_name, iio_direction[i], + strlen(iio_direction[i]))) { + prefix = iio_direction[i]; + break; + } + + current = strdup(full_name + strlen(prefix) + 1); + if (!current) + return -ENOMEM; + + working = strtok(current, "_\0"); + if (!working) { + free(current); + return -EINVAL; + } + + w = working; + r = working; + + while (*r != '\0') { + if (!isdigit(*r)) { + *w = *r; + w++; + } + + r++; + } + *w = '\0'; + ret = asprintf(generic_name, "%s_%s", prefix, working); + free(current); + + return (ret == -1) ? -ENOMEM : 0; +} + +/** + * iioutils_get_type() - find and process _type attribute data + * @is_signed: output whether channel is signed + * @bytes: output how many bytes the channel storage occupies + * @bits_used: output number of valid bits of data + * @shift: output amount of bits to shift right data before applying bit mask + * @mask: output a bit mask for the raw data + * @be: output if data in big endian + * @device_dir: the IIO device directory + * @buffer_idx: the IIO buffer index + * @name: the channel name + * @generic_name: the channel type name + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, + unsigned int *bits_used, unsigned int *shift, + uint64_t *mask, unsigned int *be, + const char *device_dir, int buffer_idx, + const char *name, const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; + char signchar, endianchar; + unsigned padint; + const struct dirent *ent; + + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); + if (ret < 0) + return -ENOMEM; + + ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_scan_el_dir; + } + ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + + dp = opendir(scan_el_dir); + if (!dp) { + ret = -errno; + goto error_free_builtname_generic; + } + + ret = -ENOENT; + while (ent = readdir(dp), ent) + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + + sysfsfp = fopen(filename, "r"); + if (!sysfsfp) { + ret = -errno; + fprintf(stderr, "failed to open %s\n", + filename); + goto error_free_filename; + } + + ret = fscanf(sysfsfp, + "%ce:%c%u/%u>>%u", + &endianchar, + &signchar, + bits_used, + &padint, shift); + if (ret < 0) { + ret = -errno; + fprintf(stderr, + "failed to pass scan type description\n"); + goto error_close_sysfsfp; + } else if (ret != 5) { + ret = -EIO; + fprintf(stderr, + "scan type description didn't match\n"); + goto error_close_sysfsfp; + } + + *be = (endianchar == 'b'); + *bytes = padint / 8; + if (*bits_used == 64) + *mask = ~(0ULL); + else + *mask = (1ULL << *bits_used) - 1ULL; + + *is_signed = (signchar == 's'); + if (fclose(sysfsfp)) { + ret = -errno; + fprintf(stderr, "Failed to close %s\n", + filename); + goto error_free_filename; + } + + sysfsfp = 0; + free(filename); + filename = 0; + + /* + * Avoid having a more generic entry overwriting + * the settings. + */ + if (strcmp(builtname, ent->d_name) == 0) + break; + } + +error_close_sysfsfp: + if (sysfsfp) + if (fclose(sysfsfp)) + perror("iioutils_get_type(): Failed to close file"); + +error_free_filename: + if (filename) + free(filename); + +error_closedir: + if (closedir(dp) == -1) + perror("iioutils_get_type(): Failed to close directory"); + +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_free_scan_el_dir: + free(scan_el_dir); + + return ret; +} + +/** + * iioutils_get_param_float() - read a float value from a channel parameter + * @output: output the float value + * @param_name: the parameter name to read + * @device_dir: the IIO device directory in sysfs + * @name: the channel name + * @generic_name: the channel type name + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int iioutils_get_param_float(float *output, const char *param_name, + const char *device_dir, const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *builtname, *builtname_generic; + char *filename = NULL; + const struct dirent *ent; + + ret = asprintf(&builtname, "%s_%s", name, param_name); + if (ret < 0) + return -ENOMEM; + + ret = asprintf(&builtname_generic, + "%s_%s", generic_name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + + dp = opendir(device_dir); + if (!dp) { + ret = -errno; + goto error_free_builtname_generic; + } + + ret = -ENOENT; + while (ent = readdir(dp), ent) + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", device_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + + sysfsfp = fopen(filename, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free_filename; + } + + errno = 0; + if (fscanf(sysfsfp, "%f", output) != 1) + ret = errno ? -errno : -ENODATA; + + fclose(sysfsfp); + break; + } +error_free_filename: + if (filename) + free(filename); + +error_closedir: + if (closedir(dp) == -1) + perror("iioutils_get_param_float(): Failed to close directory"); + +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); + + return ret; +} + +/** + * bsort_channel_array_by_index() - sort the array in index order + * @ci_array: the iio_channel_info array to be sorted + * @cnt: the amount of array elements + **/ + +void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) +{ + struct iio_channel_info temp; + int x, y; + + for (x = 0; x < cnt; x++) + for (y = 0; y < (cnt - 1); y++) + if (ci_array[y].index > ci_array[y + 1].index) { + temp = ci_array[y + 1]; + ci_array[y + 1] = ci_array[y]; + ci_array[y] = temp; + } +} + +/** + * build_channel_array() - function to figure out what channels are present + * @device_dir: the IIO device directory in sysfs + * @buffer_idx: the IIO buffer for this channel array + * @ci_array: output the resulting array of iio_channel_info + * @counter: output the amount of array elements + * + * Returns 0 on success, otherwise a negative error code. + **/ +int build_channel_array(const char *device_dir, int buffer_idx, + struct iio_channel_info **ci_array, int *counter) +{ + DIR *dp; + FILE *sysfsfp; + int count = 0, i; + struct iio_channel_info *current; + int ret; + const struct dirent *ent; + char *scan_el_dir; + char *filename; + + *counter = 0; + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); + if (ret < 0) + return -ENOMEM; + + dp = opendir(scan_el_dir); + if (!dp) { + ret = -errno; + goto error_free_name; + } + + while (ent = readdir(dp), ent) + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_close_dir; + } + + sysfsfp = fopen(filename, "r"); + free(filename); + if (!sysfsfp) { + ret = -errno; + goto error_close_dir; + } + + errno = 0; + if (fscanf(sysfsfp, "%i", &ret) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("build_channel_array(): Failed to close file"); + + goto error_close_dir; + } + if (ret == 1) + (*counter)++; + + if (fclose(sysfsfp)) { + ret = -errno; + goto error_close_dir; + } + + } + + *ci_array = malloc(sizeof(**ci_array) * (*counter)); + if (!*ci_array) { + ret = -ENOMEM; + goto error_close_dir; + } + + rewinddir(dp); + while (ent = readdir(dp), ent) { + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + int current_enabled = 0; + + current = &(*ci_array)[count++]; + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + /* decrement count to avoid freeing name */ + count--; + goto error_cleanup_array; + } + + sysfsfp = fopen(filename, "r"); + free(filename); + if (!sysfsfp) { + ret = -errno; + count--; + goto error_cleanup_array; + } + + errno = 0; + if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { + ret = errno ? -errno : -ENODATA; + count--; + goto error_cleanup_array; + } + + if (fclose(sysfsfp)) { + ret = -errno; + count--; + goto error_cleanup_array; + } + + if (!current_enabled) { + count--; + continue; + } + + current->scale = 1.0; + current->offset = 0; + current->name = strndup(ent->d_name, + strlen(ent->d_name) - + strlen("_en")); + if (!current->name) { + ret = -ENOMEM; + count--; + goto error_cleanup_array; + } + + /* Get the generic and specific name elements */ + ret = iioutils_break_up_name(current->name, + ¤t->generic_name); + if (ret) { + free(current->name); + count--; + goto error_cleanup_array; + } + + ret = asprintf(&filename, + "%s/%s_index", + scan_el_dir, + current->name); + if (ret < 0) { + ret = -ENOMEM; + goto error_cleanup_array; + } + + sysfsfp = fopen(filename, "r"); + free(filename); + if (!sysfsfp) { + ret = -errno; + fprintf(stderr, "failed to open %s/%s_index\n", + scan_el_dir, current->name); + goto error_cleanup_array; + } + + errno = 0; + if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("build_channel_array(): Failed to close file"); + + goto error_cleanup_array; + } + + if (fclose(sysfsfp)) { + ret = -errno; + goto error_cleanup_array; + } + + /* Find the scale */ + ret = iioutils_get_param_float(¤t->scale, + "scale", + device_dir, + current->name, + current->generic_name); + if ((ret < 0) && (ret != -ENOENT)) + goto error_cleanup_array; + + ret = iioutils_get_param_float(¤t->offset, + "offset", + device_dir, + current->name, + current->generic_name); + if ((ret < 0) && (ret != -ENOENT)) + goto error_cleanup_array; + + ret = iioutils_get_type(¤t->is_signed, + ¤t->bytes, + ¤t->bits_used, + ¤t->shift, + ¤t->mask, + ¤t->be, + device_dir, + buffer_idx, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + } + } + + if (closedir(dp) == -1) { + ret = -errno; + goto error_cleanup_array; + } + + free(scan_el_dir); + /* reorder so that the array is in index order */ + bsort_channel_array_by_index(*ci_array, *counter); + + return 0; + +error_cleanup_array: + for (i = count - 1; i >= 0; i--) { + free((*ci_array)[i].name); + free((*ci_array)[i].generic_name); + } + free(*ci_array); + *ci_array = NULL; + *counter = 0; +error_close_dir: + if (dp) + if (closedir(dp) == -1) + perror("build_channel_array(): Failed to close dir"); + +error_free_name: + free(scan_el_dir); + + return ret; +} + +static int calc_digits(int num) +{ + int count = 0; + + /* It takes a digit to represent zero */ + if (!num) + return 1; + + while (num != 0) { + num /= 10; + count++; + } + + return count; +} + +/** + * find_type_by_name() - function to match top level types by name + * @name: top level type instance name + * @type: the type of top level instance being searched + * + * Returns the device number of a matched IIO device on success, otherwise a + * negative error code. + * Typical types this is used for are device and trigger. + **/ +int find_type_by_name(const char *name, const char *type) +{ + const struct dirent *ent; + int number, numstrlen, ret; + + FILE *namefp; + DIR *dp; + char thisname[IIO_MAX_NAME_LENGTH]; + char *filename; + + dp = opendir(iio_dir); + if (!dp) { + fprintf(stderr, "No industrialio devices available\n"); + return -ENODEV; + } + + while (ent = readdir(dp), ent) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0 && + strlen(ent->d_name) > strlen(type) && + strncmp(ent->d_name, type, strlen(type)) == 0) { + errno = 0; + ret = sscanf(ent->d_name + strlen(type), "%d", &number); + if (ret < 0) { + ret = -errno; + fprintf(stderr, + "failed to read element number\n"); + goto error_close_dir; + } else if (ret != 1) { + ret = -EIO; + fprintf(stderr, + "failed to match element number\n"); + goto error_close_dir; + } + + numstrlen = calc_digits(number); + /* verify the next character is not a colon */ + if (strncmp(ent->d_name + strlen(type) + numstrlen, + ":", 1) != 0) { + filename = malloc(strlen(iio_dir) + strlen(type) + + numstrlen + 6); + if (!filename) { + ret = -ENOMEM; + goto error_close_dir; + } + + ret = sprintf(filename, "%s%s%d/name", iio_dir, + type, number); + if (ret < 0) { + free(filename); + goto error_close_dir; + } + + namefp = fopen(filename, "r"); + if (!namefp) { + free(filename); + continue; + } + + free(filename); + errno = 0; + if (fscanf(namefp, "%s", thisname) != 1) { + ret = errno ? -errno : -ENODATA; + goto error_close_dir; + } + + if (fclose(namefp)) { + ret = -errno; + goto error_close_dir; + } + + if (strcmp(name, thisname) == 0) { + if (closedir(dp) == -1) + return -errno; + + return number; + } + } + } + } + if (closedir(dp) == -1) + return -errno; + + return -ENODEV; + +error_close_dir: + if (closedir(dp) == -1) + perror("find_type_by_name(): Failed to close directory"); + + return ret; +} + +static int _write_sysfs_int(const char *filename, const char *basedir, int val, + int verify) +{ + int ret = 0; + FILE *sysfsfp; + int test; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (!temp) + return -ENOMEM; + + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + + sysfsfp = fopen(temp, "w"); + if (!sysfsfp) { + ret = -errno; + fprintf(stderr, "failed to open %s\n", temp); + goto error_free; + } + + ret = fprintf(sysfsfp, "%d", val); + if (ret < 0) { + if (fclose(sysfsfp)) + perror("_write_sysfs_int(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { + ret = -errno; + goto error_free; + } + + if (verify) { + sysfsfp = fopen(temp, "r"); + if (!sysfsfp) { + ret = -errno; + fprintf(stderr, "failed to open %s\n", temp); + goto error_free; + } + + if (fscanf(sysfsfp, "%d", &test) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("_write_sysfs_int(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { + ret = -errno; + goto error_free; + } + + if (test != val) { + fprintf(stderr, + "Possible failure in int write %d to %s/%s\n", + val, basedir, filename); + ret = -1; + } + } + +error_free: + free(temp); + return ret; +} + +/** + * write_sysfs_int() - write an integer value to a sysfs file + * @filename: name of the file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: integer value to write to file + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int write_sysfs_int(const char *filename, const char *basedir, int val) +{ + return _write_sysfs_int(filename, basedir, val, 0); +} + +/** + * write_sysfs_int_and_verify() - write an integer value to a sysfs file + * and verify + * @filename: name of the file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: integer value to write to file + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int write_sysfs_int_and_verify(const char *filename, const char *basedir, + int val) +{ + return _write_sysfs_int(filename, basedir, val, 1); +} + +static int _write_sysfs_string(const char *filename, const char *basedir, + const char *val, int verify) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (!temp) { + fprintf(stderr, "Memory allocation failed\n"); + return -ENOMEM; + } + + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + + sysfsfp = fopen(temp, "w"); + if (!sysfsfp) { + ret = -errno; + fprintf(stderr, "Could not open %s\n", temp); + goto error_free; + } + + ret = fprintf(sysfsfp, "%s", val); + if (ret < 0) { + if (fclose(sysfsfp)) + perror("_write_sysfs_string(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { + ret = -errno; + goto error_free; + } + + if (verify) { + sysfsfp = fopen(temp, "r"); + if (!sysfsfp) { + ret = -errno; + fprintf(stderr, "Could not open file to verify\n"); + goto error_free; + } + + if (fscanf(sysfsfp, "%s", temp) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("_write_sysfs_string(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { + ret = -errno; + goto error_free; + } + + if (strcmp(temp, val) != 0) { + fprintf(stderr, + "Possible failure in string write of %s " + "Should be %s written to %s/%s\n", temp, val, + basedir, filename); + ret = -1; + } + } + +error_free: + free(temp); + + return ret; +} + +/** + * write_sysfs_string_and_verify() - string write, readback and verify + * @filename: name of file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: the string to write + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int write_sysfs_string_and_verify(const char *filename, const char *basedir, + const char *val) +{ + return _write_sysfs_string(filename, basedir, val, 1); +} + +/** + * write_sysfs_string() - write string to a sysfs file + * @filename: name of file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: the string to write + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int write_sysfs_string(const char *filename, const char *basedir, + const char *val) +{ + return _write_sysfs_string(filename, basedir, val, 0); +} + +/** + * read_sysfs_posint() - read an integer value from file + * @filename: name of file to read from + * @basedir: the sysfs directory in which the file is to be found + * + * Returns the read integer value >= 0 on success, otherwise a negative error + * code. + **/ +int read_sysfs_posint(const char *filename, const char *basedir) +{ + int ret; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (!temp) { + fprintf(stderr, "Memory allocation failed"); + return -ENOMEM; + } + + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + + sysfsfp = fopen(temp, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free; + } + + errno = 0; + if (fscanf(sysfsfp, "%d\n", &ret) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("read_sysfs_posint(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) + ret = -errno; + +error_free: + free(temp); + + return ret; +} + +/** + * read_sysfs_float() - read a float value from file + * @filename: name of file to read from + * @basedir: the sysfs directory in which the file is to be found + * @val: output the read float value + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int read_sysfs_float(const char *filename, const char *basedir, float *val) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (!temp) { + fprintf(stderr, "Memory allocation failed"); + return -ENOMEM; + } + + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + + sysfsfp = fopen(temp, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free; + } + + errno = 0; + if (fscanf(sysfsfp, "%f\n", val) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("read_sysfs_float(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) + ret = -errno; + +error_free: + free(temp); + + return ret; +} + +/** + * read_sysfs_string() - read a string from file + * @filename: name of file to read from + * @basedir: the sysfs directory in which the file is to be found + * @str: output the read string + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int read_sysfs_string(const char *filename, const char *basedir, char *str) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (!temp) { + fprintf(stderr, "Memory allocation failed"); + return -ENOMEM; + } + + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + + sysfsfp = fopen(temp, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free; + } + + errno = 0; + if (fscanf(sysfsfp, "%s\n", str) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("read_sysfs_string(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) + ret = -errno; + +error_free: + free(temp); + + return ret; +} diff --git a/demos/high_res/iio_utils.h b/demos/high_res/iio_utils.h new file mode 100644 index 000000000000..663c94a6c705 --- /dev/null +++ b/demos/high_res/iio_utils.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _IIO_UTILS_H_ +#define _IIO_UTILS_H_ + +/* IIO - useful set of util functionality + * + * Copyright (c) 2008 Jonathan Cameron + */ + +#include + +/* Made up value to limit allocation sizes */ +#define IIO_MAX_NAME_LENGTH 64 + +#define FORMAT_SCAN_ELEMENTS_DIR "%s/buffer%d" +#define FORMAT_EVENTS_DIR "%s/events" +#define FORMAT_TYPE_FILE "%s_type" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +extern const char *iio_dir; + +/** + * struct iio_channel_info - information about a given channel + * @name: channel name + * @generic_name: general name for channel type + * @scale: scale factor to be applied for conversion to si units + * @offset: offset to be applied for conversion to si units + * @index: the channel index in the buffer output + * @bytes: number of bytes occupied in buffer output + * @bits_used: number of valid bits of data + * @shift: amount of bits to shift right data before applying bit mask + * @mask: a bit mask for the raw output + * @be: flag if data is big endian + * @is_signed: is the raw value stored signed + * @location: data offset for this channel inside the buffer (in bytes) + **/ +struct iio_channel_info { + char *name; + char *generic_name; + float scale; + float offset; + unsigned index; + unsigned bytes; + unsigned bits_used; + unsigned shift; + uint64_t mask; + unsigned be; + unsigned is_signed; + unsigned location; +}; + +static inline int iioutils_check_suffix(const char *str, const char *suffix) +{ + return strlen(str) >= strlen(suffix) && + strncmp(str+strlen(str)-strlen(suffix), + suffix, strlen(suffix)) == 0; +} + +int iioutils_break_up_name(const char *full_name, char **generic_name); +int iioutils_get_param_float(float *output, const char *param_name, + const char *device_dir, const char *name, + const char *generic_name); +void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); +int build_channel_array(const char *device_dir, int buffer_idx, + struct iio_channel_info **ci_array, int *counter); +int find_type_by_name(const char *name, const char *type); +int write_sysfs_int(const char *filename, const char *basedir, int val); +int write_sysfs_int_and_verify(const char *filename, const char *basedir, + int val); +int write_sysfs_string_and_verify(const char *filename, const char *basedir, + const char *val); +int write_sysfs_string(const char *filename, const char *basedir, + const char *val); +int read_sysfs_posint(const char *filename, const char *basedir); +int read_sysfs_float(const char *filename, const char *basedir, float *val); +int read_sysfs_string(const char *filename, const char *basedir, char *str); + +#endif /* _IIO_UTILS_H_ */ diff --git a/demos/high_res/led_blink.c b/demos/high_res/led_blink.c new file mode 100644 index 000000000000..ce961a04cf66 --- /dev/null +++ b/demos/high_res/led_blink.c @@ -0,0 +1,28 @@ +#include +#include +#include + +extern int delay_millis; +extern pthread_mutex_t delay_lock; + +void *led_blink() { + char on = '1'; + char off = '0'; + int fd = open("/sys/devices/platform/leds/leds/am62-sk\:green\:heartbeat/brightness", O_WRONLY); + if (fd == -1) { + perror("Error opening LED sysfs"); + return; + } + write (fd, &off, 1); + int delay_local; + while(1){ + pthread_mutex_lock(&delay_lock); + delay_local = delay_millis; + pthread_mutex_unlock(&delay_lock); + write (fd, &on, 1); + usleep(delay_local*1000); + write (fd, &off, 1); + usleep(delay_local*1000); + } + close(fd); +} \ No newline at end of file diff --git a/demos/high_res/lv_demo_high_res_api_example.c b/demos/high_res/lv_demo_high_res_api_example.c index 9c553382ef94..fe98a694df59 100644 --- a/demos/high_res/lv_demo_high_res_api_example.c +++ b/demos/high_res/lv_demo_high_res_api_example.c @@ -8,6 +8,8 @@ *********************/ #include "lv_demo_high_res.h" +#include +#include #if LV_USE_DEMO_HIGH_RES /********************* @@ -22,12 +24,14 @@ * STATIC PROTOTYPES **********************/ +static pthread_t audio_thread; +static pthread_t mqtt_sub_thread; +static pthread_t clock_thread; +static pthread_t button_thread; +static pthread_t led_thread; +static pthread_t adc_thread; static void exit_cb(lv_demo_high_res_api_t * api); static void output_subject_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -static void locked_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -static void locked_timer_cb(lv_timer_t * t); -static void delete_timer_cb(lv_event_t * e); -static void clock_timer_cb(lv_timer_t * t); /********************** * STATIC VARIABLES @@ -37,9 +41,25 @@ static void clock_timer_cb(lv_timer_t * t); * MACROS **********************/ +/********************** + * GLOBAL VARIABLES + **********************/ +int delay_millis = 1000; +pthread_mutex_t delay_lock; +pthread_mutex_t playing_now_lock; +int playing_now=0; +extern int button_configured; + /********************** * GLOBAL FUNCTIONS **********************/ +extern void *audio_play(void); +extern void *mqtt_sub_init(void); +extern void *clock_init(void); +extern void *button_init(void); +extern void *led_blink(void); +extern void *adc_init(void); + void lv_demo_high_res_api_example(const char * assets_path, const char * logo_path, const char * slides_path) { @@ -47,6 +67,11 @@ void lv_demo_high_res_api_example(const char * assets_path, const char * logo_pa /* see lv_demo_high_res.h for documentation of the available subjects */ lv_subject_set_int(&api->subjects.volume, 50); + int error=0; + char command[50]; + sprintf(command, "amixer set PCM %d\%\t", 50); + error = system(command); + lv_subject_set_int(&api->subjects.volume, 50); lv_subject_set_pointer(&api->subjects.month_name, "August"); lv_subject_set_int(&api->subjects.month_day, 1); lv_subject_set_pointer(&api->subjects.week_day_name, "Wednesday"); @@ -68,14 +93,20 @@ void lv_demo_high_res_api_example(const char * assets_path, const char * logo_pa lv_subject_add_observer(&api->subjects.thermostat_target_temperature, output_subject_observer_cb, (void *)"thermostat_target_temperature"); - /* unlock after being locked for 3 seconds */ - lv_timer_t * locked_timer = lv_timer_create_basic(); - lv_obj_add_event_cb(api->base_obj, delete_timer_cb, LV_EVENT_DELETE, locked_timer); - lv_subject_add_observer(&api->subjects.locked, locked_observer_cb, locked_timer); - - /* slowly increment the time */ - lv_timer_t * clock_timer = lv_timer_create(clock_timer_cb, 10000, api); - lv_obj_add_event_cb(api->base_obj, delete_timer_cb, LV_EVENT_DELETE, clock_timer); + if (pthread_mutex_init(&delay_lock, NULL) != 0) { + printf("\n mutex init has failed\n"); + return 1; + } + if (pthread_mutex_init(&playing_now_lock, NULL) != 0) { + printf("\n mutex init has failed\n"); + return 1; + } + pthread_create(&audio_thread, NULL, audio_play, NULL); + pthread_create(&mqtt_sub_thread, NULL, mqtt_sub_init, api); + pthread_create(&clock_thread, NULL, clock_init, api); + pthread_create(&button_thread, NULL, button_init, api); + pthread_create(&led_thread, NULL, led_blink, NULL); + pthread_create(&adc_thread, NULL, adc_init, api); } /********************** @@ -91,50 +122,26 @@ static void output_subject_observer_cb(lv_observer_t * observer, lv_subject_t * { const char * subject_name = lv_observer_get_user_data(observer); LV_LOG_USER("%s output subject value: %"PRId32, subject_name, lv_subject_get_int(subject)); -} - -static void locked_observer_cb(lv_observer_t * observer, lv_subject_t * subject) -{ - if(lv_subject_get_int(subject)) { - /* unlock after being locked for 3 seconds */ - lv_timer_t * timer = lv_observer_get_user_data(observer); - lv_timer_set_cb(timer, locked_timer_cb); - lv_timer_set_period(timer, 3000); - lv_timer_set_user_data(timer, subject); - lv_timer_set_repeat_count(timer, 1); - lv_timer_set_auto_delete(timer, false); - lv_timer_resume(timer); + if(strcmp(subject_name, "volume") == 0){ + char command[50]; + int error=0; + sprintf(command, "amixer set PCM %d\%\t", lv_subject_get_int(subject)); + printf("%s\n", command); + error = system(command); } -} - -static void locked_timer_cb(lv_timer_t * t) -{ - lv_subject_t * locked_subject = lv_timer_get_user_data(t); - lv_subject_set_int(locked_subject, 0); -} - -static void delete_timer_cb(lv_event_t * e) -{ - lv_timer_t * timer = lv_event_get_user_data(e); - lv_timer_delete(timer); -} - -static void clock_timer_cb(lv_timer_t * t) -{ - /* slowly increment the time */ - lv_demo_high_res_api_t * api = lv_timer_get_user_data(t); - int32_t minutes = lv_subject_get_int(&api->subjects.minute); - minutes += 1; - if(minutes > 59) { - minutes = 0; - int32_t hour = lv_subject_get_int(&api->subjects.hour); - hour += 1; - if(hour > 12) { - hour = 1; - } - lv_subject_set_int(&api->subjects.hour, hour); + else if(strcmp(subject_name, "main_light_temperature") == 0){ + int main_light_temp = lv_subject_get_int(subject); + float fraction_delay = main_light_temp/20000.0; + pthread_mutex_lock(&delay_lock); + delay_millis = (int)(20.0+(1-fraction_delay)*230.0); + pthread_mutex_unlock(&delay_lock); + } + else if(button_configured && strcmp(subject_name, "locked") == 0){ + lv_lock(); + int lock_status = lv_subject_get_int(subject); + lv_indev_enable(NULL, !lock_status); + lv_unlock(); } - lv_subject_set_int(&api->subjects.minute, minutes); } #endif /*LV_USE_DEMO_HIGH_RES*/ diff --git a/demos/high_res/lv_demo_high_res_app_ev_charging.c b/demos/high_res/lv_demo_high_res_app_ev_charging.c index 70548d95ec8e..d8ea999b9ede 100644 --- a/demos/high_res/lv_demo_high_res_app_ev_charging.c +++ b/demos/high_res/lv_demo_high_res_app_ev_charging.c @@ -20,6 +20,11 @@ * DEFINES *********************/ +/********************* + * GLOBAL VARIABLE + *********************/ +extern void publish_evCharge_data(int); + /********************** * TYPEDEFS **********************/ @@ -210,6 +215,7 @@ static void anim_exec_cb(void * var, int32_t v) lv_demo_high_res_ctx_t * c = lv_obj_get_user_data(base_obj); lv_subject_set_int(&c->ev_charging_progress, v); + publish_evCharge_data(lv_map(lv_subject_get_int(&c->ev_charging_progress), 0, EV_CHARGING_RANGE_END, 0, 100)); if(c->ev_charging_bg_cont) { anim_state_t * anim_state = lv_obj_get_user_data(c->ev_charging_bg_cont); diff --git a/demos/high_res/lv_demo_high_res_app_smart_home.c b/demos/high_res/lv_demo_high_res_app_smart_home.c index 65500ffecefc..030308ec3e01 100644 --- a/demos/high_res/lv_demo_high_res_app_smart_home.c +++ b/demos/high_res/lv_demo_high_res_app_smart_home.c @@ -8,6 +8,7 @@ *********************/ #include "lv_demo_high_res_private.h" +#include #if LV_USE_DEMO_HIGH_RES #include "../../src/widgets/image/lv_image.h" @@ -16,8 +17,10 @@ #include "../../src/widgets/arc/lv_arc.h" /********************* - * DEFINES + * Global variables *********************/ +extern pthread_mutex_t playing_now_lock; +extern int playing_now; /********************** * TYPEDEFS @@ -325,9 +328,11 @@ static void widget3_play_pause_clicked_cb(lv_event_t * e) lv_obj_t * play_pause_img = lv_event_get_target_obj(e); lv_demo_high_res_ctx_t * c = lv_event_get_user_data(e); - bool was_playing = lv_image_get_src(play_pause_img) == c->imgs[IMG_PLAY_ICON]; - lv_image_set_src(play_pause_img, c->imgs[was_playing ? IMG_PLAY_ICON_1 : IMG_PLAY_ICON]); - lv_subject_set_int(&c->api.subjects.music_play, !was_playing); + pthread_mutex_lock(&playing_now_lock); + playing_now = lv_image_get_src(play_pause_img) == c->imgs[IMG_PLAY_ICON]; + lv_image_set_src(play_pause_img, c->imgs[playing_now ? IMG_PLAY_ICON_1 : IMG_PLAY_ICON]); + lv_subject_set_int(&c->api.subjects.music_play, !playing_now); + pthread_mutex_unlock(&playing_now_lock); } static void create_widget3(lv_demo_high_res_ctx_t * c, lv_obj_t * widgets) diff --git a/demos/high_res/mqtt_sub.c b/demos/high_res/mqtt_sub.c new file mode 100644 index 000000000000..9dc8d97892e8 --- /dev/null +++ b/demos/high_res/mqtt_sub.c @@ -0,0 +1,157 @@ +/* + * This example shows how to write a client that subscribes to a topic and does + * not do anything other than handle the messages that are received. + */ + +#include +#include +#include +#include +#include +#include "lv_demo_high_res_private.h" + +static lv_demo_high_res_api_t * api_hmi; + +/* Callback called when the client receives a CONNACK message from the broker. */ +void on_connect_vol_sub(struct mosquitto *mosq, void *obj, int reason_code) +{ + int rc; + /* Print out the connection result. mosquitto_connack_string() produces an + * appropriate string for MQTT v3.x clients, the equivalent for MQTT v5.0 + * clients is mosquitto_reason_string(). + */ + printf("on_connect: %s\n", mosquitto_connack_string(reason_code)); + if(reason_code != 0){ + /* If the connection fails for any reason, we don't want to keep on + * retrying in this example, so disconnect. Without this, the client + * will attempt to reconnect. */ + mosquitto_disconnect(mosq); + } + + /* Making subscriptions in the on_connect() callback means that if the + * connection drops and is automatically resumed by the client, then the + * subscriptions will be recreated when the client reconnects. */ + rc = mosquitto_subscribe(mosq, NULL, "SmartHome/volume", 1); + if(rc != MOSQ_ERR_SUCCESS){ + fprintf(stderr, "Error subscribing: %s\n", mosquitto_strerror(rc)); + /* We might as well disconnect if we were unable to subscribe */ + mosquitto_disconnect(mosq); + } + rc = mosquitto_subscribe(mosq, NULL, "SmartHome/led", 1); + if(rc != MOSQ_ERR_SUCCESS){ + fprintf(stderr, "Error subscribing: %s\n", mosquitto_strerror(rc)); + /* We might as well disconnect if we were unable to subscribe */ + mosquitto_disconnect(mosq); + } +} + + +/* Callback called when the broker sends a SUBACK in response to a SUBSCRIBE. */ +void on_subscribe_vol_sub(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) +{ + int i; + bool have_subscription = false; + + /* In this example we only subscribe to a single topic at once, but a + * SUBSCRIBE can contain many topics at once, so this is one way to check + * them all. */ + for(i=0; itopic, "SmartHome/volume")==0){ + int vol = atoi((char *)msg->payload); + if(vol<=0){ + vol=0; + } + else if(vol >=100){ + vol=100; + } + lv_lock(); + lv_subject_set_int(&api_hmi->subjects.volume, vol); + lv_unlock(); + char command[50]; + int error=0; + sprintf(command, "amixer set PCM %d\%\t", vol); + printf("%s\n", command); + error = system(command); + printf("%s %d %s\n", msg->topic, msg->qos, (char *)msg->payload); + } + else if(strcmp((char*)msg->topic, "SmartHome/led")==0){ + int led = atoi((char *)msg->payload); + if(led<=0){ + led=0; + } + else if(led >=20000){ + led=20000; + } + lv_lock(); + lv_subject_set_int(&api_hmi->subjects.main_light_temperature, led); + lv_unlock(); + } +} + + +void *mqtt_sub_init(lv_demo_high_res_api_t * api){ + struct mosquitto *mosq; + int rc; + api_hmi = api; + + /* Required before calling other mosquitto functions */ + mosquitto_lib_init(); + + /* Create a new client instance. + * id = NULL -> ask the broker to generate a client id for us + * clean session = true -> the broker should remove old sessions when we connect + * obj = NULL -> we aren't passing any of our private data for callbacks + */ + mosq = mosquitto_new(NULL, true, NULL); + if(mosq == NULL){ + fprintf(stderr, "Error: Out of memory.\n"); + return; + } + + /* Configure callbacks. This should be done before connecting ideally. */ + mosquitto_connect_callback_set(mosq, on_connect_vol_sub); + mosquitto_subscribe_callback_set(mosq, on_subscribe_vol_sub); + mosquitto_message_callback_set(mosq, on_message_vol_sub); + + mosquitto_tls_set(mosq, "/usr/share/ti-lvgl-demo/cert/AmazonRootCA1.pem", NULL, NULL, NULL, NULL); + + /* Connect to test.mosquitto.org on port 1883, with a keepalive of 60 seconds. + * This call makes the socket connection only, it does not complete the MQTT + * CONNECT/CONNACK flow, you should use mosquitto_loop_start() or + * mosquitto_loop_forever() for processing net traffic. */ + rc = mosquitto_connect(mosq, "broker.hivemq.com", 8883, 60); + printf("rc=%d\t MOSQ_ERR_SUCCESS=%d\n", rc, MOSQ_ERR_SUCCESS); + if(rc != MOSQ_ERR_SUCCESS){ + mosquitto_destroy(mosq); + fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); + return; + } + + /* Run the network loop in a blocking call. The only thing we do in this + * example is to print incoming messages, so a blocking call here is fine. + * + * This call will continue forever, carrying automatic reconnections if + * necessary, until the user calls mosquitto_disconnect(). + */ + mosquitto_loop_forever(mosq, -1, 1); + + mosquitto_lib_cleanup(); + return; +} diff --git a/demos/high_res/slides/Slide1.png b/demos/high_res/slides/Slide1.png new file mode 100644 index 000000000000..52c28e8afb0d Binary files /dev/null and b/demos/high_res/slides/Slide1.png differ diff --git a/demos/high_res/slides/Slide10.png b/demos/high_res/slides/Slide10.png new file mode 100644 index 000000000000..8c1260b8cd45 Binary files /dev/null and b/demos/high_res/slides/Slide10.png differ diff --git a/demos/high_res/slides/Slide11.png b/demos/high_res/slides/Slide11.png new file mode 100644 index 000000000000..7c473adb5f56 Binary files /dev/null and b/demos/high_res/slides/Slide11.png differ diff --git a/demos/high_res/slides/Slide12.png b/demos/high_res/slides/Slide12.png new file mode 100644 index 000000000000..52dd98cfe15a Binary files /dev/null and b/demos/high_res/slides/Slide12.png differ diff --git a/demos/high_res/slides/Slide13.png b/demos/high_res/slides/Slide13.png new file mode 100644 index 000000000000..0d15905d8198 Binary files /dev/null and b/demos/high_res/slides/Slide13.png differ diff --git a/demos/high_res/slides/Slide14.png b/demos/high_res/slides/Slide14.png new file mode 100644 index 000000000000..a994a13b5f2c Binary files /dev/null and b/demos/high_res/slides/Slide14.png differ diff --git a/demos/high_res/slides/Slide15.png b/demos/high_res/slides/Slide15.png new file mode 100644 index 000000000000..65bb8859e4be Binary files /dev/null and b/demos/high_res/slides/Slide15.png differ diff --git a/demos/high_res/slides/Slide16.png b/demos/high_res/slides/Slide16.png new file mode 100644 index 000000000000..75fe55df801c Binary files /dev/null and b/demos/high_res/slides/Slide16.png differ diff --git a/demos/high_res/slides/Slide17.png b/demos/high_res/slides/Slide17.png new file mode 100644 index 000000000000..9afa54e3d0cb Binary files /dev/null and b/demos/high_res/slides/Slide17.png differ diff --git a/demos/high_res/slides/Slide18.png b/demos/high_res/slides/Slide18.png new file mode 100644 index 000000000000..432bceb56980 Binary files /dev/null and b/demos/high_res/slides/Slide18.png differ diff --git a/demos/high_res/slides/Slide19.png b/demos/high_res/slides/Slide19.png new file mode 100644 index 000000000000..0f91ac7f902c Binary files /dev/null and b/demos/high_res/slides/Slide19.png differ diff --git a/demos/high_res/slides/Slide2.png b/demos/high_res/slides/Slide2.png new file mode 100644 index 000000000000..d2fe5685bd2b Binary files /dev/null and b/demos/high_res/slides/Slide2.png differ diff --git a/demos/high_res/slides/Slide3.png b/demos/high_res/slides/Slide3.png new file mode 100644 index 000000000000..486d501ae95b Binary files /dev/null and b/demos/high_res/slides/Slide3.png differ diff --git a/demos/high_res/slides/Slide4.png b/demos/high_res/slides/Slide4.png new file mode 100644 index 000000000000..71e3e61409f7 Binary files /dev/null and b/demos/high_res/slides/Slide4.png differ diff --git a/demos/high_res/slides/Slide5.png b/demos/high_res/slides/Slide5.png new file mode 100644 index 000000000000..54ef9769cb8b Binary files /dev/null and b/demos/high_res/slides/Slide5.png differ diff --git a/demos/high_res/slides/Slide6.png b/demos/high_res/slides/Slide6.png new file mode 100644 index 000000000000..d8b70727f679 Binary files /dev/null and b/demos/high_res/slides/Slide6.png differ diff --git a/demos/high_res/slides/Slide7.png b/demos/high_res/slides/Slide7.png new file mode 100644 index 000000000000..5ab3de045094 Binary files /dev/null and b/demos/high_res/slides/Slide7.png differ diff --git a/demos/high_res/slides/Slide8.png b/demos/high_res/slides/Slide8.png new file mode 100644 index 000000000000..f684cdd39cdf Binary files /dev/null and b/demos/high_res/slides/Slide8.png differ diff --git a/demos/high_res/slides/Slide9.png b/demos/high_res/slides/Slide9.png new file mode 100644 index 000000000000..d85a44880ede Binary files /dev/null and b/demos/high_res/slides/Slide9.png differ