<s:if test="canSubscribe == 'Y'">能 </s:if> <s:else>不能 </s:else> 单字符需加.toString()...

本文探讨了在Struts2框架中,当进行字符串对比时,若字符串为单字母,可能会触发类型错误的问题,并提供了解决方案。通过将字符串转换为字符串类型,可以避免此类错误,确保程序稳定运行。
首先这样写是没错的:<s:if test="canSubscribe == 'Y'">能 </s:if>
<s:else>不能 </s:else>


但是,问题在于在struts2中,如果你的==号右方就一个字母比如我的是'y',那么,Struts2会认为这是在对比一个char,会出现例外的,因为canSubscribe在anction中是String。解决方法是这样写:<s:if test="canSubscribe == 'Y'.toString()">能 </s:if>
<s:else>不能 </s:else>
当然,如果你对比的是多个字母那就没问题了,比如:<s:if test="canSubscribe == 'Yes'">能 </s:if>
<s:else>不能 </s:else>
就不用写.toString()了。


世界真美好!!
/**************************************************************************** * drivers/sensors/sensor.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include <nuttx/config.h> #include <sys/types.h> #include <stdbool.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <errno.h> #include <debug.h> #include <poll.h> #include <fcntl.h> #include <nuttx/list.h> #include <nuttx/kmalloc.h> #include <nuttx/circbuf.h> #include <nuttx/mutex.h> #include <nuttx/sensors/sensor.h> #include <nuttx/lib/lib.h> /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Device naming ************************************************************/ #define ROUND_DOWN(x, y) (((x) / (y)) * (y)) #define DEVNAME_FMT "/dev/uorb/sensor_%s%s%d" #define DEVNAME_UNCAL "_uncal" #define TIMING_BUF_ESIZE (sizeof(uint32_t)) /**************************************************************************** * Private Types ****************************************************************************/ struct sensor_axis_map_s { int8_t src_x; int8_t src_y; int8_t src_z; int8_t sign_x; int8_t sign_y; int8_t sign_z; }; /* This structure describes sensor meta */ struct sensor_meta_s { size_t esize; FAR char *name; }; typedef enum sensor_role_e { SENSOR_ROLE_NONE, SENSOR_ROLE_WR, SENSOR_ROLE_RD, SENSOR_ROLE_RDWR, } sensor_role_t; /* This structure describes user info of sensor, the user may be * advertiser or subscriber */ struct sensor_user_s { /* The common info */ struct list_node node; /* Node of users list */ struct pollfd *fds; /* The poll structure of thread waiting events */ sensor_role_t role; /* The is used to indicate user's role based on open flags */ bool changed; /* This is used to indicate event happens and need to * asynchronous notify other users */ unsigned int event; /* The event of this sensor, eg: SENSOR_EVENT_FLUSH_COMPLETE. */ bool flushing; /* The is used to indicate user is flushing */ sem_t buffersem; /* Wakeup user waiting for data in circular buffer */ size_t bufferpos; /* The index of user generation in buffer */ /* The subscriber info * Support multi advertisers to subscribe their own data when they * appear in dual role */ struct sensor_ustate_s state; }; /* This structure describes the state of the upper half driver */ struct sensor_upperhalf_s { FAR struct sensor_lowerhalf_s *lower; /* The handle of lower half driver */ struct sensor_state_s state; /* The state of sensor device */ struct circbuf_s timing; /* The circular buffer of generation */ struct circbuf_s buffer; /* The circular buffer of data */ rmutex_t lock; /* Manages exclusive access to file operations */ struct list_node userlist; /* List of users */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role); static int sensor_open(FAR struct file *filep); static int sensor_close(FAR struct file *filep); static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes); /**************************************************************************** * Private Data ****************************************************************************/ static const struct sensor_axis_map_s g_remap_tbl[] = { { 0, 1, 2, 1, 1, 1 }, /* P0 */ { 1, 0, 2, 1, -1, 1 }, /* P1 */ { 0, 1, 2, -1, -1, 1 }, /* P2 */ { 1, 0, 2, -1, 1, 1 }, /* P3 */ { 0, 1, 2, -1, 1, -1 }, /* P4 */ { 1, 0, 2, -1, -1, -1 }, /* P5 */ { 0, 1, 2, 1, -1, -1 }, /* P6 */ { 1, 0, 2, 1, 1, -1 }, /* P7 */ }; static const struct sensor_meta_s g_sensor_meta[] = { {0, NULL}, {sizeof(struct sensor_accel), "accel"}, {sizeof(struct sensor_mag), "mag"}, {sizeof(struct sensor_orientation), "orientation"}, {sizeof(struct sensor_gyro), "gyro"}, {sizeof(struct sensor_light), "light"}, {sizeof(struct sensor_baro), "baro"}, {sizeof(struct sensor_noise), "noise"}, {sizeof(struct sensor_prox), "prox"}, {sizeof(struct sensor_rgb), "rgb"}, {sizeof(struct sensor_accel), "linear_accel"}, {sizeof(struct sensor_rotation), "rotation"}, {sizeof(struct sensor_humi), "humi"}, {sizeof(struct sensor_temp), "temp"}, {sizeof(struct sensor_pm25), "pm25"}, {sizeof(struct sensor_pm1p0), "pm1p0"}, {sizeof(struct sensor_pm10), "pm10"}, {sizeof(struct sensor_event), "motion_detect"}, {sizeof(struct sensor_event), "step_detector"}, {sizeof(struct sensor_step_counter), "step_counter"}, {sizeof(struct sensor_ph), "ph"}, {sizeof(struct sensor_hrate), "hrate"}, {sizeof(struct sensor_event), "tilt_detector"}, {sizeof(struct sensor_event), "wake_gesture"}, {sizeof(struct sensor_event), "glance_gesture"}, {sizeof(struct sensor_event), "pickup_gesture"}, {sizeof(struct sensor_event), "wrist_tilt"}, {sizeof(struct sensor_orientation), "device_orientation"}, {sizeof(struct sensor_pose_6dof), "pose_6dof"}, {sizeof(struct sensor_gas), "gas"}, {sizeof(struct sensor_event), "significant_motion"}, {sizeof(struct sensor_hbeat), "hbeat"}, {sizeof(struct sensor_force), "force"}, {sizeof(struct sensor_hall), "hall"}, {sizeof(struct sensor_event), "offbody_detector"}, {sizeof(struct sensor_uv), "uv"}, {sizeof(struct sensor_angle), "hinge_angle"}, {sizeof(struct sensor_ir), "ir"}, {sizeof(struct sensor_hcho), "hcho"}, {sizeof(struct sensor_tvoc), "tvoc"}, {sizeof(struct sensor_dust), "dust"}, {sizeof(struct sensor_ecg), "ecg"}, {sizeof(struct sensor_ppgd), "ppgd"}, {sizeof(struct sensor_ppgq), "ppgq"}, {sizeof(struct sensor_impd), "impd"}, {sizeof(struct sensor_ots), "ots"}, {sizeof(struct sensor_co2), "co2"}, {sizeof(struct sensor_cap), "cap"}, {sizeof(struct sensor_eng), "eng"}, {sizeof(struct sensor_gnss), "gnss"}, {sizeof(struct sensor_gnss_satellite), "gnss_satellite"}, {sizeof(struct sensor_gnss_measurement), "gnss_measurement"}, {sizeof(struct sensor_gnss_clock), "gnss_clock"}, {sizeof(struct sensor_gnss_geofence_event), "gnss_geofence_event"}, }; static const struct file_operations g_sensor_fops = { sensor_open, /* open */ sensor_close, /* close */ sensor_read, /* read */ sensor_write, /* write */ NULL, /* seek */ sensor_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ sensor_poll /* poll */ }; /**************************************************************************** * Private Functions ****************************************************************************/ static void sensor_lock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_lock(&upper->lock); } static void sensor_unlock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_unlock(&upper->lock); } static int sensor_update_interval(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t interval) { FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *tmp; uint32_t min_interval = interval; uint32_t min_latency = interval != UINT32_MAX ? user->state.latency : UINT32_MAX; int ret = 0; if (interval == user->state.interval) { return 0; } list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp->state.interval == UINT32_MAX) { continue; } if (min_interval > tmp->state.interval) { min_interval = tmp->state.interval; } if (min_latency > tmp->state.latency) { min_latency = tmp->state.latency; } } if (lower->ops->set_interval) { if (min_interval != UINT32_MAX && min_interval != upper->state.min_interval) { uint32_t expected_interval = min_interval; ret = lower->ops->set_interval(lower, filep, &min_interval); if (ret < 0) { return ret; } else if (min_interval > expected_interval) { return -EINVAL; } } if (min_latency == UINT32_MAX) { min_latency = 0; } if (lower->ops->batch && (min_latency != upper->state.min_latency || (min_interval != upper->state.min_interval && min_latency))) { ret = lower->ops->batch(lower, filep, &min_latency); if (ret >= 0) { upper->state.min_latency = min_latency; } } } upper->state.min_interval = min_interval; user->state.interval = interval; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static int sensor_update_latency(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t latency) { FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *tmp; uint32_t min_latency = latency; int ret = 0; if (latency == user->state.latency) { return 0; } if (user->state.interval == UINT32_MAX) { user->state.latency = latency; return 0; } if (latency <= upper->state.min_latency) { goto update; } list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp->state.interval == UINT32_MAX) { continue; } if (min_latency > tmp->state.latency) { min_latency = tmp->state.latency; } } update: if (min_latency == UINT32_MAX) { min_latency = 0; } if (min_latency == upper->state.min_latency) { user->state.latency = latency; return ret; } if (lower->ops->batch) { ret = lower->ops->batch(lower, filep, &min_latency); if (ret < 0) { return ret; } } upper->state.min_latency = min_latency; user->state.latency = latency; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static void sensor_generate_timing(FAR struct sensor_upperhalf_s *upper, unsigned long nums) { uint32_t interval = upper->state.min_interval != UINT32_MAX ? upper->state.min_interval : 1; while (nums-- > 0) { upper->state.generation += interval; circbuf_overwrite(&upper->timing, &upper->state.generation, TIMING_BUF_ESIZE); } } static bool sensor_is_updated(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { long delta = (long long)upper->state.generation - user->state.generation; if (delta <= 0) { return false; } else if (user->state.interval == UINT32_MAX) { return true; } else { /* Check whether next generation user want in buffer. * generation next generation(not published yet) * ____v_____________v * ////|//////^ | * ^ middle point * next generation user want */ return delta >= user->state.interval - (upper->state.min_interval >> 1); } } static void sensor_catch_up(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { uint32_t generation; long delta; circbuf_peek(&upper->timing, &generation, TIMING_BUF_ESIZE); delta = (long long)generation - user->state.generation; if (delta > 0) { user->bufferpos = upper->timing.tail / TIMING_BUF_ESIZE; if (user->state.interval == UINT32_MAX) { user->state.generation = generation - 1; } else { delta -= upper->state.min_interval >> 1; user->state.generation += ROUND_DOWN(delta, user->state.interval); } } } static ssize_t sensor_do_samples(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, FAR char *buffer, size_t len) { uint32_t generation; ssize_t ret = 0; size_t nums; size_t pos; size_t end; sensor_catch_up(upper, user); nums = upper->timing.head / TIMING_BUF_ESIZE - user->bufferpos; if (len < nums * upper->state.esize) { nums = len / upper->state.esize; } len = nums * upper->state.esize; /* Take samples continuously */ if (user->state.interval == UINT32_MAX) { if (buffer != NULL) { ret = circbuf_peekat(&upper->buffer, user->bufferpos * upper->state.esize, buffer, len); } else { ret = len; } user->bufferpos += nums; circbuf_peekat(&upper->timing, (user->bufferpos - 1) * TIMING_BUF_ESIZE, &user->state.generation, TIMING_BUF_ESIZE); return ret; } /* Take samples one-bye-one, to determine whether a sample needed: * * If user's next generation is on the left side of middle point, * we should copy this sample for user. * next_generation(or end) * ________________v____ * timing buffer: //|//////. | * ^ middle * generation * next sample(or end) * ________________v____ * data buffer: | | * ^ * sample */ pos = user->bufferpos; end = upper->timing.head / TIMING_BUF_ESIZE; circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE, &generation, TIMING_BUF_ESIZE); while (pos++ != end) { uint32_t next_generation; long delta; if (pos * TIMING_BUF_ESIZE == upper->timing.head) { next_generation = upper->state.generation + upper->state.min_interval; } else { circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE, &next_generation, TIMING_BUF_ESIZE); } delta = next_generation + generation - ((user->state.generation + user->state.interval) << 1); if (delta >= 0) { if (buffer != NULL) { ret += circbuf_peekat(&upper->buffer, (pos - 1) * upper->state.esize, buffer + ret, upper->state.esize); } else { ret += upper->state.esize; } user->bufferpos = pos; user->state.generation += user->state.interval; if (ret >= len) { break; } } generation = next_generation; } if (pos - 1 == end && sensor_is_updated(upper, user)) { generation = upper->state.generation - user->state.generation + (upper->state.min_interval >> 1); user->state.generation += ROUND_DOWN(generation, user->state.interval); } return ret; } static void sensor_pollnotify_one(FAR struct sensor_user_s *user, pollevent_t eventset, sensor_role_t role) { if (!(user->role & role)) { return; } if (eventset == POLLPRI) { user->changed = true; } poll_notify(&user->fds, 1, eventset); } static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role) { FAR struct sensor_user_s *user; list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { sensor_pollnotify_one(user, eventset, role); } } static int sensor_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user; int ret = 0; nxrmutex_lock(&upper->lock); user = kmm_zalloc(sizeof(struct sensor_user_s)); if (user == NULL) { ret = -ENOMEM; goto errout_with_lock; } if (lower->ops->open) { ret = lower->ops->open(lower, filep); if (ret < 0) { goto errout_with_user; } } if ((filep->f_oflags & O_DIRECT) == 0) { if (filep->f_oflags & O_RDOK) { if (upper->state.nsubscribers == 0 && lower->ops->activate) { ret = lower->ops->activate(lower, filep, true); if (ret < 0) { goto errout_with_open; } } user->role |= SENSOR_ROLE_RD; upper->state.nsubscribers++; } if (filep->f_oflags & O_WROK) { user->role |= SENSOR_ROLE_WR; upper->state.nadvertisers++; if (filep->f_oflags & SENSOR_PERSIST) { lower->persist = true; } } } if (upper->state.generation && lower->persist) { user->state.generation = upper->state.generation - 1; user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE - 1; } else { user->state.generation = upper->state.generation; user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE; } user->state.interval = UINT32_MAX; user->state.esize = upper->state.esize; nxsem_init(&user->buffersem, 0, 0); list_add_tail(&upper->userlist, &user->node); /* The new user generation, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); filep->f_priv = user; goto errout_with_lock; errout_with_open: if (lower->ops->close) { lower->ops->close(lower, filep); } errout_with_user: kmm_free(user); errout_with_lock: nxrmutex_unlock(&upper->lock); return ret; } static int sensor_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; int ret = 0; nxrmutex_lock(&upper->lock); if (lower->ops->close) { ret = lower->ops->close(lower, filep); if (ret < 0) { nxrmutex_unlock(&upper->lock); return ret; } } if ((filep->f_oflags & O_DIRECT) == 0) { if (filep->f_oflags & O_RDOK) { upper->state.nsubscribers--; if (upper->state.nsubscribers == 0 && lower->ops->activate) { lower->ops->activate(lower, filep, false); } } if (filep->f_oflags & O_WROK) { upper->state.nadvertisers--; } } list_delete(&user->node); sensor_update_latency(filep, upper, user, UINT32_MAX); sensor_update_interval(filep, upper, user, UINT32_MAX); nxsem_destroy(&user->buffersem); /* The user is closed, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); nxrmutex_unlock(&upper->lock); kmm_free(user); return ret; } static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; ssize_t ret; if (!len) { return -EINVAL; } nxrmutex_lock(&upper->lock); if (lower->ops->fetch) { if (buffer == NULL) { return -EINVAL; } if (!(filep->f_oflags & O_NONBLOCK)) { nxrmutex_unlock(&upper->lock); ret = nxsem_wait_uninterruptible(&user->buffersem); if (ret < 0) { return ret; } nxrmutex_lock(&upper->lock); } else if (!upper->state.nsubscribers) { ret = -EAGAIN; goto out; } ret = lower->ops->fetch(lower, filep, buffer, len); } else if (circbuf_is_empty(&upper->buffer)) { ret = -ENODATA; } else if (sensor_is_updated(upper, user)) { ret = sensor_do_samples(upper, user, buffer, len); } else if (lower->persist) { if (buffer == NULL) { ret = upper->state.esize; } else { /* Persistent device can get latest old data if not updated. */ ret = circbuf_peekat(&upper->buffer, (user->bufferpos - 1) * upper->state.esize, buffer, upper->state.esize); } } else { ret = -ENODATA; } out: nxrmutex_unlock(&upper->lock); return ret; } static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; return lower->push_event(lower->priv, buffer, buflen); } static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; uint32_t arg1 = (uint32_t)arg; int ret = 0; switch (cmd) { case SNIOC_GET_STATE: { nxrmutex_lock(&upper->lock); memcpy((FAR void *)(uintptr_t)arg, &upper->state, sizeof(upper->state)); user->changed = false; nxrmutex_unlock(&upper->lock); } break; case SNIOC_GET_USTATE: { nxrmutex_lock(&upper->lock); memcpy((FAR void *)(uintptr_t)arg, &user->state, sizeof(user->state)); nxrmutex_unlock(&upper->lock); } break; case SNIOC_SET_INTERVAL: { nxrmutex_lock(&upper->lock); ret = sensor_update_interval(filep, upper, user, arg1 ? arg1 : UINT32_MAX); nxrmutex_unlock(&upper->lock); } break; case SNIOC_BATCH: { nxrmutex_lock(&upper->lock); ret = sensor_update_latency(filep, upper, user, arg1); nxrmutex_unlock(&upper->lock); } break; case SNIOC_SELFTEST: { if (lower->ops->selftest == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->selftest(lower, filep, arg); } break; case SNIOC_SET_CALIBVALUE: { if (lower->ops->set_calibvalue == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->set_calibvalue(lower, filep, arg); } break; case SNIOC_CALIBRATE: { if (lower->ops->calibrate == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->calibrate(lower, filep, arg); } break; case SNIOC_SET_USERPRIV: { nxrmutex_lock(&upper->lock); upper->state.priv = (uint64_t)arg; nxrmutex_unlock(&upper->lock); } break; case SNIOC_SET_BUFFER_NUMBER: { nxrmutex_lock(&upper->lock); if (!circbuf_is_init(&upper->buffer)) { if (arg1 >= lower->nbuffer) { lower->nbuffer = arg1; upper->state.nbuffer = arg1; } else { ret = -ERANGE; } } else { ret = -EBUSY; } nxrmutex_unlock(&upper->lock); } break; case SNIOC_UPDATED: { nxrmutex_lock(&upper->lock); *(FAR bool *)(uintptr_t)arg = sensor_is_updated(upper, user); nxrmutex_unlock(&upper->lock); } break; case SNIOC_GET_INFO: { if (lower->ops->get_info == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->get_info(lower, filep, (FAR struct sensor_device_info_s *)(uintptr_t)arg); } break; case SNIOC_GET_EVENTS: { nxrmutex_lock(&upper->lock); *(FAR unsigned int *)(uintptr_t)arg = user->event; user->event = 0; user->changed = false; nxrmutex_unlock(&upper->lock); } break; case SNIOC_FLUSH: { nxrmutex_lock(&upper->lock); /* If the sensor is not activated, return -EINVAL. */ if (upper->state.nsubscribers == 0) { nxrmutex_unlock(&upper->lock); return -EINVAL; } if (lower->ops->flush != NULL) { /* Lower half driver will do flush in asynchronous mode, * flush will be completed until push event happened with * bytes is zero. */ ret = lower->ops->flush(lower, filep); if (ret >= 0) { user->flushing = true; } } else { /* If flush is not supported, complete immediately */ user->event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user->role); } nxrmutex_unlock(&upper->lock); } break; default: /* Lowerhalf driver process other cmd. */ if (lower->ops->control) { ret = lower->ops->control(lower, filep, cmd, arg); } else { ret = -ENOTTY; } break; } return ret; } static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; pollevent_t eventset = 0; int semcount; int ret = 0; nxrmutex_lock(&upper->lock); if (setup) { /* Don't have enough space to store fds */ if (user->fds) { ret = -ENOSPC; goto errout; } user->fds = fds; fds->priv = filep; if (lower->ops->fetch) { /* Always return POLLIN for fetch data directly(non-block) */ if (filep->f_oflags & O_NONBLOCK) { eventset |= POLLIN; } else { nxsem_get_value(&user->buffersem, &semcount); if (semcount > 0) { eventset |= POLLIN; } } } else if (sensor_is_updated(upper, user)) { eventset |= POLLIN; } if (user->changed) { eventset |= POLLPRI; } poll_notify(&fds, 1, eventset); } else { user->fds = NULL; fds->priv = NULL; } errout: nxrmutex_unlock(&upper->lock); return ret; } static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user; unsigned long envcount; int semcount; int ret; nxrmutex_lock(&upper->lock); if (bytes == 0) { list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { if (user->flushing) { user->flushing = false; user->event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user->role); } } nxrmutex_unlock(&upper->lock); return 0; } envcount = bytes / upper->state.esize; if (bytes != envcount * upper->state.esize) { nxrmutex_unlock(&upper->lock); return -EINVAL; } if (!circbuf_is_init(&upper->buffer)) { /* Initialize sensor buffer when data is first generated */ ret = circbuf_init(&upper->buffer, NULL, lower->nbuffer * upper->state.esize); if (ret < 0) { nxrmutex_unlock(&upper->lock); return ret; } ret = circbuf_init(&upper->timing, NULL, lower->nbuffer * TIMING_BUF_ESIZE); if (ret < 0) { circbuf_uninit(&upper->buffer); nxrmutex_unlock(&upper->lock); return ret; } } circbuf_overwrite(&upper->buffer, data, bytes); sensor_generate_timing(upper, envcount); list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { if (sensor_is_updated(upper, user)) { nxsem_get_value(&user->buffersem, &semcount); if (semcount < 1) { nxsem_post(&user->buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } } nxrmutex_unlock(&upper->lock); return bytes; } static void sensor_notify_event(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_user_s *user; int semcount; nxrmutex_lock(&upper->lock); list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { nxsem_get_value(&user->buffersem, &semcount); if (semcount < 1) { nxsem_post(&user->buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } nxrmutex_unlock(&upper->lock); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: sensor_remap_vector_raw16 * * Description: * This function remap the sensor data according to the place position on * board. The value of place is determined base on g_remap_tbl. * * Input Parameters: * in - A pointer to input data need remap. * out - A pointer to output data. * place - The place position of sensor on board, * ex:SENSOR_BODY_COORDINATE_PX * ****************************************************************************/ void sensor_remap_vector_raw16(FAR const int16_t *in, FAR int16_t *out, int place) { FAR const struct sensor_axis_map_s *remap; int16_t tmp[3]; DEBUGASSERT(place < (sizeof(g_remap_tbl) / sizeof(g_remap_tbl[0]))); remap = &g_remap_tbl[place]; tmp[0] = in[remap->src_x] * remap->sign_x; tmp[1] = in[remap->src_y] * remap->sign_y; tmp[2] = in[remap->src_z] * remap->sign_z; memcpy(out, tmp, sizeof(tmp)); } /**************************************************************************** * Name: sensor_register * * Description: * This function binds an instance of a "lower half" Sensor driver with the * "upper half" Sensor device and registers that device so that can be used * by application code. * * We will register the chararter device by node name format based on the * type of sensor. Multiple types of the same type are distinguished by * numbers. eg: accel0, accel1 * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. If the * devno alerady exists, -EEXIST will be returned. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; int ret; DEBUGASSERT(lower != NULL); path = lib_get_pathbuffer(); if (path == NULL) { return -ENOMEM; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower->type].name, lower->uncalibrated ? DEVNAME_UNCAL : "", devno); ret = sensor_custom_register(lower, path, g_sensor_meta[lower->type].esize); lib_put_pathbuffer(path); return ret; } /**************************************************************************** * Name: sensor_custom_register * * Description: * This function binds an instance of a "lower half" Sensor driver with the * "upper half" Sensor device and registers that device so that can be used * by application code. * * You can register the character device type by specific path and esize. * This API corresponds to the sensor_custom_unregister. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device. ex: /dev/uorb/xxx. * esize - The element size of intermediate circular buffer. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower, FAR const char *path, size_t esize) { FAR struct sensor_upperhalf_s *upper; int ret = -EINVAL; DEBUGASSERT(lower != NULL); if (lower->type >= SENSOR_TYPE_COUNT || !esize) { snerr("ERROR: type is invalid\n"); return ret; } /* Allocate the upper-half data structure */ upper = kmm_zalloc(sizeof(struct sensor_upperhalf_s)); if (!upper) { snerr("ERROR: Allocation failed\n"); return -ENOMEM; } /* Initialize the upper-half data structure */ list_initialize(&upper->userlist); upper->state.esize = esize; upper->state.min_interval = UINT32_MAX; if (lower->ops->activate) { upper->state.nadvertisers = 1; } nxrmutex_init(&upper->lock); /* Bind the lower half data structure member */ lower->priv = upper; lower->sensor_lock = sensor_lock; lower->sensor_unlock = sensor_unlock; if (!lower->ops->fetch) { if (!lower->nbuffer) { lower->nbuffer = 1; } lower->push_event = sensor_push_event; } else { lower->notify_event = sensor_notify_event; lower->nbuffer = 0; } #ifdef CONFIG_SENSORS_RPMSG lower = sensor_rpmsg_register(lower, path); if (lower == NULL) { ret = -EIO; goto rpmsg_err; } #endif upper->state.nbuffer = lower->nbuffer; upper->lower = lower; sninfo("Registering %s\n", path); ret = register_driver(path, &g_sensor_fops, 0666, upper); if (ret) { goto drv_err; } return ret; drv_err: #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); rpmsg_err: #endif nxrmutex_destroy(&upper->lock); kmm_free(upper); return ret; } /**************************************************************************** * Name: sensor_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. ****************************************************************************/ void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; path = lib_get_pathbuffer(); if (path == NULL) { return; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower->type].name, lower->uncalibrated ? DEVNAME_UNCAL : "", devno); sensor_custom_unregister(lower, path); lib_put_pathbuffer(path); } /**************************************************************************** * Name: sensor_custom_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. This API corresponds to the sensor_custom_register. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device, ex: /dev/uorb/xxx ****************************************************************************/ void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *lower, FAR const char *path) { FAR struct sensor_upperhalf_s *upper; DEBUGASSERT(lower != NULL); DEBUGASSERT(lower->priv != NULL); upper = lower->priv; sninfo("UnRegistering %s\n", path); unregister_driver(path); #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); #endif nxrmutex_destroy(&upper->lock); if (circbuf_is_init(&upper->buffer)) { circbuf_uninit(&upper->buffer); circbuf_uninit(&upper->timing); } kmm_free(upper); }
07-11
#include <sys/termios.h> #include <mosquitto.h> #include <sys/wait.h> #include <sys/time.h> #include "signal.h" #include "rc.h" #include "mqtt.h" static struct list_head mqtt_upflow; static pthread_mutex_t upflow_mutex; //extern struct list_head mqtt_downflow; static struct mosquitto *mosq = NULL; static int publish_finished = 1; static int already_connected = 0; static int need_restart = 0; int g_mqtt_sigid[150]; int g_mqtt_data = 0; int mqtt_public_message_enqueue(char *data, char *topic, int qos) { struct pub_msg *msg; msg = (struct pub_msg *)malloc(sizeof(struct pub_msg)); if(msg == NULL) { return 0; } memset(msg, 0, sizeof(struct pub_msg)); snprintf(msg->data, sizeof(msg->data), "%s", data); snprintf(msg->topic, sizeof(msg->topic), "%s", topic); msg->qos = qos; msg->mid = -1; pthread_mutex_lock(&upflow_mutex); list_add_tail(&msg->list, &mqtt_upflow); pthread_mutex_unlock(&upflow_mutex); return 1; } /* *why need this function? *when mqtt process exit, always has one mqtt thread not exit , so case mqtt process can not restart *add by jerry, 22-06-21 * * */ static void mqtt_exit(void) { int ret; /* *ret != -1 *WIFEXITED(ret) is true *0 == WEXITSTATUS(ret) *all above success, system function is success, other is failed * */ do { ret = system("killall -9 mqtt"); }while(!((ret != -1) && (WIFEXITED(ret)) && (0 == WEXITSTATUS(ret)))); } static void mqtt_sig_handler(int sig) { switch (sig) { case SIGTERM: case SIGKILL: case SIGINT: syslog(LOG_NOTICE, "Got a signal! exit!!"); mqtt_exit(); break; case SIGHUP: syslog(LOG_NOTICE, "Got a signal! exit!!"); mqtt_exit(); break; case SIGUSR1: break; case SIGUSR2: break; } } static void mqtt_deamon() { struct sigaction sa; FILE *fp; if ( fork() !=0 ) exit(0); openlog("mqtt", LOG_PID, LOG_USER); sa.sa_handler = mqtt_sig_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR2, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGKILL, &sa, NULL); sigaction(SIGINT, &sa, NULL); signal(SIGCHLD, chld_reap); if ( setsid() < 0 ) exit(1); if ( chdir("/") == -1 ) exit(1); kill_pidfile_tk(MQTT_PID_FILE); if ((fp = fopen(MQTT_PID_FILE, "w")) != NULL) { fprintf(fp, "%d", getpid()); fclose(fp); } } /* Callback called when the client receives a CONNACK message from the broker. */ static void on_connect(struct mosquitto *mosq, void *obj, int reason_code) { // int rc; // char sub_topic[256] = {0}; /* 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(). */ syslog(LOG_ERR, "on_connect: %s", 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); } else { already_connected = 1; //subscribe when mqtt connect success #if 0 /* 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. */ snprintf(sub_topic, sizeof(sub_topic), "VirtualTopic/mqtt/command/%s", nvram_safe_get("iot_sendorid")); syslog(LOG_INFO, "sub topic: %s", sub_topic); rc = mosquitto_subscribe(mosq, NULL, sub_topic, 0); if(rc != MOSQ_ERR_SUCCESS){ syslog(LOG_ERR, "Error subscribing: %s\n", mosquitto_strerror(rc)); /* We might as well disconnect if we were unable to subscribe */ mosquitto_disconnect(mosq); } #endif } } /* Callback called when the broker sends a SUBACK in response to a SUBSCRIBE. */ static void on_subscribe(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; i<qos_count; i++){ syslog(LOG_ERR, "on_subscribe: %d:granted qos = %d", i, granted_qos[i]); if(granted_qos[i] <= 2){ have_subscription = true; } } if(have_subscription == false){ /* The broker rejected all of our subscriptions, we know we only sent * the one SUBSCRIBE, so there is no point remaining connected. */ syslog(LOG_ERR, "Error: All subscriptions rejected."); mosquitto_disconnect(mosq); } } /* 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. */ static void on_publish(struct mosquitto *mosq, void *obj, int mid) { struct list_head *pos = NULL; struct pub_msg *msg = NULL; syslog(LOG_ERR, "Message with mid %d has been published.", mid); //when qos is 1 or 2, message publish success, delete message from queue here pthread_mutex_lock(&upflow_mutex); list_for_next_each(pos, &mqtt_upflow) { msg = container_of(pos,struct pub_msg,list); if(msg->mid == mid) { //syslog(LOG_INFO,"2content:%s, topic:%s, qos:%d, mid:%d", msg->data, msg->topic, msg->qos, msg->mid); list_del(&msg->list); free(msg); publish_finished = 1; break; } } pthread_mutex_unlock(&upflow_mutex); } /* Callback called when the client receives a message. */ static void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) { syslog(LOG_INFO, "-----on message"); mqtt_public_message_enqueue("hello", "mqtt1", 0); } char *get_time_str(int type, char *buf, int blen) { struct tm *info; struct timeval tv; struct timezone tz; if(buf == NULL) { return NULL; } gettimeofday(&tv, &tz); info = localtime(&tv.tv_sec); if(type == 0) { snprintf(buf, blen, "%d-%.2d-%.2d %.2d:%.2d:%.2d.%ld", 1900 + info->tm_year, info->tm_mon + 1, info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec, tv.tv_usec/1000); } else if(type = 1) { snprintf(buf, blen, "%d%.2d%.2d%.2d%.2d%.2d", 1900 + info->tm_year, info->tm_mon + 1, info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec); } return buf; } char *printf_time_sub(char sub, uint8_t count, char *out) { time_t current_time; struct tm * timeinfo; time(&current_time); timeinfo = localtime(&current_time); switch (sub) { case 'Y': if (count == 4) sprintf(out, "%d", timeinfo->tm_year + 1900); else sprintf(out, "%d", timeinfo->tm_year + 1900 - 2000); break; case 'M': if (count == 2) sprintf(out, "%02d", timeinfo->tm_mon + 1); else sprintf(out, "%d", timeinfo->tm_mon + 1); break; case 'D': if (count == 2) sprintf(out, "%02d", timeinfo->tm_mday); else sprintf(out, "%d", timeinfo->tm_mday); break; case 'h': if (count == 2) sprintf(out, "%02d", timeinfo->tm_hour); else sprintf(out, "%d", timeinfo->tm_hour); break; case 'm': if (count == 2) sprintf(out, "%02d", timeinfo->tm_min); else sprintf(out, "%d", timeinfo->tm_min); break; case 's': if (count == 2) sprintf(out, "%02d", timeinfo->tm_sec); else sprintf(out, "%d", timeinfo->tm_sec); break; default: break; } return (out + strlen(out)); } uint16_t get_length(char *line) { uint16_t len = 0; while ( *line) { if (*line == '\n') { if (len) len++; break; } else { len++; line++; } } return len; } char *printf_intf_data(char *line) { uint16_t line_len = get_length(line); uint16_t pos = 0; char *result = strstr(line, "<<"); if(NULL == result) { return; } pos = result - line; line += pos; line_len -= pos; result = strstr(line, "INTF"); if(NULL == result) { return; } pos = result - line; char temp_pos[6] = {0}; snprintf(temp_pos, sizeof(temp_pos), "%d", pos); nvram_set("intf_pos", temp_pos); line += (pos + 4); line_len -= (pos + 4); char intf_data[6] = {0}; int i = 0; char temp[32] = {0}; char temp_val[32] = {0}; char mqtt_data[32] = {0}; char buf[6] = {0}; while(*line != ')') { if(*line == '(') { line ++; continue; } intf_data[i] = *line; i ++; line ++; } int j; for(j = 0; j <= nvram_get_int("g_reg_num"); j++) { memset(temp, 0, sizeof(temp)); memset(temp_val, 0, sizeof(temp_val)); memset(mqtt_data, 0, sizeof(mqtt_data)); snprintf(temp, sizeof(temp), "regAddr_%d", j+1); if(!strlen(nvram_safe_get(temp))) { sleep(1); } if(nvram_get_int(temp) == atoi(intf_data)) { snprintf(temp_val, sizeof(temp_val), "signalval_%d", j+1); snprintf(mqtt_data, sizeof(mqtt_data), "mqtt_report_data%d", g_mqtt_data); nvram_set(mqtt_data, nvram_safe_get(temp_val)); g_mqtt_data ++; snprintf(buf, sizeof(buf), "%d", g_mqtt_data); nvram_set("g_mqtt_data", buf); } } return; } char *printf_time(char *line) { /* "time":"%s"<<TIME(YYYY-MM-DD hh:mm:ss.SSSzz) YYYY年 MM月 DD日 hh时 mm分 ss秒 SSS毫秒 zz +-08 zzzz +-08:00 */ uint16_t line_len = get_length(line); uint16_t pos = 0; char *result = strstr(line, "<<"); pos = result - line; line += pos; line_len -= pos; //定位TIME result = strstr(line, "TIME"); pos = result - line; char temp_pos[6] = {0}; snprintf(temp_pos, sizeof(temp_pos), "%d", pos); nvram_set("time_pos", temp_pos); line += (pos + 4); line_len -= (pos + 4); char field[5]; uint8_t start = 0; char *timestr = (char *)malloc(50); //memset(timestr, ' ', 50); // 初始化内存空间 char *temp = timestr; do { switch (*line) { case 'Y': case 'M': case 'D': case 'h': case 'm': case 's': case 'S': case 'z': switch (start) { case 0: field[start++] = *line; break; case 4: start = 0; continue; default: if (*line == field[start - 1]) field[start++] = *line; else { timestr = printf_time_sub(field[0], start, timestr); start = 0; continue; } } break; case '(': break; case ')': if (start) { timestr = printf_time_sub(field[0], start, timestr); start = 0; } else { *timestr = 0; } nvram_set("mqtt_time", temp); return temp; default: if (start) { timestr = printf_time_sub(field[0], start, timestr); start = 0; *timestr++ = *line; } else *timestr++ = *line; break; } line++; } while (*line); if (temp == timestr) { free(timestr); return NULL; } else return temp; } char *encode_mqtt_pack() { char *line = NULL; char line_temp[2000] = {0}; line = nvram_safe_get("mqtt_template"); //line_temp = line; char report_packet_string[1000] = {0}; syslog(LOG_INFO, "========================%s", line); snprintf(line_temp, sizeof(line_temp),"%s", line); char *result = strstr(line_temp, "\":"); while(nvram_get_int("g_modbus_start") == 1) { sleep(1); syslog(LOG_INFO, "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{wait for modbus}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}"); continue; } // g_mqtt_start = 1; nvram_set("g_mqtt_start", "1"); sleep(1); while(result != NULL) { if(nvram_get_int("g_reg_num") != nvram_get_int("g_mqtt_flag")) { sleep(1); } printf_intf_data(result); result = strstr(result + strlen("\":"), "\":"); } int i = 0; char mqtt_data[32] = {0}; printf_time(line); float num[50] = {0}; for(i = 0; i < nvram_get_int("g_mqtt_data"); i ++) { memset(mqtt_data, 0, sizeof(mqtt_data)); snprintf(mqtt_data, sizeof(mqtt_data), "mqtt_report_data%d", i); sscanf(nvram_safe_get(mqtt_data), "%f", &num[i]); //syslog(LOG_INFO, "======================num%d :%f", i, num[i]); } if(num[nvram_get_int("g_reg_num")] == 0) { syslog(LOG_INFO, "num[%d] = 0", nvram_get_int("g_reg_num")); return NULL; } // char tmp_buf[10] = {0}; // snprintf(tmp_buf, sizeof(tmp_buf), ) // if(nvram_get_int("intf_pos") < nvram_get_int("time_pos")) //将intf和time值赋值给模板 char *tmp_line = line; char tmp_string[70] = {0}; char packet_string[80] = {0}; char add_n_string[90] = {0}; i = 0; int m = 0; int data_num = 0; while(tmp_line[m]) { if(tmp_line[m] == '\n') { if(NULL != strstr(tmp_string, "INTF")) { sprintf(packet_string, tmp_string, num[data_num]); data_num ++; sprintf(add_n_string, "%s\n", packet_string); memset(tmp_string, 0, sizeof(tmp_string)); } else if(NULL != strstr(tmp_string, "TIME")) { sprintf(packet_string, tmp_string, nvram_safe_get("mqtt_time")); sprintf(add_n_string, "%s\n", packet_string); memset(tmp_string, 0, sizeof(tmp_string)); } else { sprintf(packet_string, "%s", tmp_string); sprintf(add_n_string, "%s\n", packet_string); memset(tmp_string, 0, sizeof(tmp_string)); } strcat(report_packet_string, add_n_string); m ++; i = 0; } tmp_string[i] = tmp_line[m]; i++; m++; } strcat(report_packet_string, tmp_string); char *token = report_packet_string; char report_mqtt_string[1000] = {0}; int k = 0; while(*token != NULL) { if(*token != ',') { report_mqtt_string[k] = *token; k ++; token ++; } else { report_mqtt_string[k] = *token; k ++; token ++; report_mqtt_string[k] = '\n'; k ++; while(*token != '\n') { token ++; } token ++; } } if(NULL == strstr(report_mqtt_string, "{") || NULL == strstr(report_mqtt_string, "}")) { return NULL; } return report_mqtt_string; } static void *formate_data_thread(void *arg) { char *buf = NULL; while(1) { buf = encode_mqtt_pack(); syslog(LOG_INFO, "======================buf :%s", buf); if(buf == NULL) { sleep(3); continue; } // snprintf(buf, sizeof(buf), "hello world%d", count); mqtt_public_message_enqueue(buf, nvram_safe_get("iot_topic"), 0); sleep(nvram_get_int("iot_mqtt_interval")); } } static void *publish_thread(void *arg) { int rc; struct list_head *pos; struct pub_msg *msg = NULL; while(1) { if((publish_finished) == 0 || (already_connected == 0)) { //syslog(LOG_ERR, "Mqtt not connected or message is null"); sleep(1); if(need_restart == 1) { mosquitto_disconnect(mosq); } continue; } pthread_mutex_lock(&upflow_mutex); list_for_next_each(pos, &mqtt_upflow) { msg = container_of(pos,struct pub_msg,list); break; } pthread_mutex_unlock(&upflow_mutex); //mqtt_upflow is not null if(pos != &mqtt_upflow) { publish_finished = 0; //syslog(LOG_INFO,"1content:%s, topic:%s, qos:%d, mid:%d", msg->data, msg->topic, msg->qos, msg->mid); rc = mosquitto_publish(mosq, &msg->mid, msg->topic, strlen(msg->data), msg->data, msg->qos, false); g_mqtt_data = 0; if(rc != MOSQ_ERR_SUCCESS) { publish_finished = 1; syslog(LOG_ERR, "Error publishing: %s", mosquitto_strerror(rc)); sleep(1); } nvram_set("g_mqtt_start", "0"); } else { //syslog(LOG_ERR, "current msg is NULL"); sleep(1); if(need_restart == 1) { mosquitto_disconnect(mosq); } } } } static void mqtt_tls_config(void) { char buf[64]; FILE *fp = NULL; int rc = 0; mkdir("/etc/mqtt",0755); snprintf(buf, sizeof(buf), "/etc/mqtt/ca.crt"); fp = fopen(buf,"wb"); if(fp != NULL) { chmod(buf,S_IRUSR|S_IWUSR); fprintf(fp,"%s",nvram_safe_get("iot_root_ca")); fclose(fp); } if(nvram_match("iot_mutual_enable", "1")) { snprintf(buf, sizeof(buf), "/etc/mqtt/client.crt"); fp = fopen(buf,"wb"); if(fp != NULL) { chmod(buf,S_IRUSR|S_IWUSR); fprintf(fp,"%s",nvram_safe_get("iot_client_ca")); fclose(fp); } snprintf(buf, sizeof(buf), "/etc/mqtt/client.key"); fp = fopen(buf,"wb"); if(fp != NULL) { chmod(buf,S_IRUSR|S_IWUSR); fprintf(fp,"%s",nvram_safe_get("iot_client_key")); fclose(fp); } rc = mosquitto_tls_set(mosq, "/etc/mqtt/ca.crt", "/etc/mqtt", "/etc/mqtt/client.crt", "/etc/mqtt/client.key", NULL); if(rc != MOSQ_ERR_SUCCESS) { syslog(LOG_ERR, "Error: set tls %s\n", mosquitto_strerror(rc)); } } else { rc = mosquitto_tls_set(mosq, "/etc/mqtt/ca.crt", NULL, NULL, NULL, NULL); if(rc != MOSQ_ERR_SUCCESS) { syslog(LOG_ERR, "Error: set tls %s\n", mosquitto_strerror(rc)); } } } int mqtt_main(int argc, char *argv[]) { int rc; pthread_t publish_pid, formate_pid, modbus_pid; char *username = NULL, *passwd = NULL; //char will_buf[1024] = {0}; nvram_set("g_mqtt_start", "0"); nvram_set("g_modbus_start", "1"); mqtt_deamon(); if (!strcmp(nvram_safe_get("mqtt_enable_rtu"), "0")) { syslog( LOG_NOTICE, "MQTT Disabled, Pause!!" ); while (1) { pause(); } } //check ppp online while( !check_wanup() ) { syslog(LOG_NOTICE, "MQTT : Cellular Offline" ); sleep( 3 ); } //等待modbus进程读取数据 sleep(10); /* Required before calling other mosquitto functions */ mosquitto_lib_init(); INIT_LIST_HEAD(&mqtt_upflow); pthread_mutex_init(&upflow_mutex, NULL); /* 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(nvram_match("iot_clientid", "") ? NULL : nvram_safe_get("iot_clientid"), true, NULL); if(mosq == NULL) { syslog(LOG_ERR, "Error: Out of memory."); return 0; } mqtt_tls_config(); //downflow data //INIT_LIST_HEAD(&mqtt_downflow); //mqtt will message set //mosquitto_will_set(mosq, MQTT_PUBLISH_TOPIC, strlen(will_buf), will_buf, 1, false); username = nvram_safe_get("iot_username"); passwd = nvram_safe_get("iot_passwd"); if(strlen(username) == 0) { username = NULL; } if(strlen(passwd) == 0) { passwd = NULL; } rc = mosquitto_username_pw_set(mosq, username, passwd); if(rc != MOSQ_ERR_SUCCESS) { syslog(LOG_ERR, "Error1: %s", mosquitto_strerror(rc)); goto ERROR; } /* Configure callbacks. This should be done before connecting ideally. */ mosquitto_connect_callback_set(mosq, on_connect); mosquitto_publish_callback_set(mosq, on_publish); //mosquitto_subscribe_callback_set(mosq, on_subscribe); mosquitto_message_callback_set(mosq, on_message); /* 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, nvram_safe_get("iot_hostname"), nvram_get_int("iot_port"), 60); if(rc != MOSQ_ERR_SUCCESS){ syslog(LOG_ERR, "Error connect: %s", mosquitto_strerror(rc)); goto ERROR; } if (pthread_create(&publish_pid, NULL, (void *)publish_thread, NULL) != 0) { syslog(LOG_NOTICE, "MQTT Thread %d ERR",(int) publish_pid); goto ERROR; } else { pthread_detach(publish_pid); } #if 1 if (pthread_create(&formate_pid, NULL, (void *)formate_data_thread, NULL) != 0) { syslog(LOG_NOTICE, "MQTT formate Thread %d ERR",(int) formate_pid); goto ERROR; } else { pthread_detach(formate_pid); } #endif // if (pthread_create(&modbus_pid, NULL, (void *)modbus_process_thread, NULL) != 0) // { // syslog(LOG_NOTICE, "MQTT modbus Thread %d ERR",(int) modbus_pid); // goto ERROR; // } // else // { // pthread_detach(modbus_pid); // } /* 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, 60*1000, 1);//keeplive 60 second do{ rc = mosquitto_loop(mosq, 50, 1); }while(rc == MOSQ_ERR_SUCCESS); syslog(LOG_ERR, "End Error: %s", mosquitto_strerror(rc)); ERROR: pthread_mutex_destroy(&upflow_mutex); mosquitto_loop_stop(mosq, false); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); mqtt_exit(); return 0; } 使用上述代码有了更详细的错误日志TLS Error in mosquitto_connect: A TLS error occurred. (code: 8);TLS Error: Generic TLS connection error;Check certificate paths, permissions, and validity;Failed to connect to MQTT broker for device 3: A TLS error occurred.请根据错误日志分析原因并解决
最新发布
10-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值