#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUFF_MAX 256 #define NR_OLP6500_CHANNEL_PER_DEVICE_MAX (17) #define OLP6500_HEARTBEAT_SWITCH_OBJECT (0x0600) #define OLP6500_HEARTBEAT_PACKET_OBJECT (0x0601) #define OLP6500_WORK_MODE_OBJECT (0x1010) #define OLP6500_WORK_LINE_OBJECT (0x1070) #define OLP6500_SWITCHBACK_OBJECT (0x1020) #define OLP6500_CHANNEL_INFO_OBJECT (0x0200) #define OLP6500_CHANNEL_CONF_OBJECT (0x0501) #define OLP6500_SET_LINE_INLINE (0x30) #define OLP6500_SET_LINE_BYPASS (0xc0) #define OLP6500_LINE_STATUS_INLINE (0x03) #define OLP6500_LINE_STATUS_BYPASS (0x0c) #define OLP6500_TIMER_ONE_CYCLE_US 1000 #define OLP6500_RELOAD_CONFIG_CYCLE_US 1000 #define OLP6500_LOAD_CONFIG_NOT_READY 0 #define OLP6500_LOAD_CONFIG_READY 1 #define OLP6500_WORK_MODE_MANUL 1 #define OLP6500_WORK_MODE_AUTO 2 enum { OLP_TIMER_DISABLE, OLP_TIMER_ENABLE, }; enum { OLP_CONFIG_GET, OLP_CONFIG_SET, }; enum { OLP_SET_HEARTBEAT_SWITCH = 0, OLP_SET_WORK_MODE = 1, OLP_SET_WORK_LINE = 2, OLP_SET_SWITCHBACK_MODE = 3, OLP_HEARTBEAT_PACKET = 4, OLP_GET_CHANNEL_INFO = 5, OLP_GET_CHANNEL_CONF = 6, OLP_OBJECT_MAX }; enum { OLP_SUCCESS = 0, OLP_ERR_CODE_CONN_FAIL = 1, OLP_ERR_CODE_GET_CHANNEL_INFO_FAIL = 2, OLP_ERR_CODE_HB_MODE_INCONSISTENT = 3, OLP_ERR_CODE_HB_INTERVAL_INCONSISTENT = 4, OLP_ERR_CODE_HB_COUNT_INCONSISTENT = 5, OLP_ERR_CODE_WORK_LINE_INCONSISTENT = 6, OLP_ERR_CODE_SW_BACK_INCONSISTENT = 7, OLP_ERR_CODE_WORK_MODE_INCONSISTENT = 8, }; /* * Heartbeat Switch Data Format * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Alive | Idle | Interval | Count * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Alive : enable:1 disable:0. * Idle : idle time before the initial detection (seconds). * Interval : heartbeat detection interval, in 20 milliseconds. * Count : number of detection failures for determination */ struct heartbeat_switch_data { uint8_t enable; uint8_t idle; uint8_t interval; uint8_t count; } __attribute__((packed)); /* * Work Mode Data Format * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Mode | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Mode : manual:1 auto:2. */ struct work_mode_data { uint8_t mode; } __attribute__((packed)); /* * Work Line Data Format * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Line | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Line : inline:0x30 bypass:0xC0. */ struct work_line_data { uint8_t line_status; } __attribute__((packed)); /* * Switch Back Data Format * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Enable | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Enable : enable:0x01 disable:0x02. */ struct switch_back_data { uint8_t enable; } __attribute__((packed)); struct channel_info_data { uint8_t card_function; uint8_t reserved_1; uint8_t work_line; uint16_t reserved_2; int16_t r3_optical_power; int16_t r4_optical_power; int16_t tx_optical_power; int16_t rx_optical_power; int16_t r1_optical_power; int16_t r2_optical_power; } __attribute__((packed)); struct channel_conf_data { uint8_t card_function; uint8_t reserved_1; uint8_t work_line; uint16_t reserved_2; uint8_t work_mode; uint8_t tx_wavelength; uint8_t rx_wavelength; uint16_t switch_delay; uint16_t switch_back_delay; int16_t tx_alarm_threshold; int16_t t1_alarm_threshold; int16_t t2_alarm_threshold; int16_t rx_alarm_threshold; int16_t r1_alarm_threshold; int16_t r2_alarm_threshold; int16_t switch_r1_threshold; int16_t switch_r2_threshold; int16_t high_temperature_alarm_threshold; int16_t low_temperature_alarm_threshold; uint8_t switch_back_mode; uint16_t mode_back_delay; uint8_t key_board; uint8_t bypass_mode; uint8_t bypass_back_mode; uint8_t power_down_mode; uint8_t power_down_delay; uint8_t heart_mode; uint8_t heart_detect; uint8_t heart_idle_delay; uint8_t heart_interval; uint8_t heart_count; uint8_t CRC; } __attribute__((packed)); /* * OLP6500 Format * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Action | Slot | Object * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Port | Len | Data * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Action : SET/GET 0x00:get 0x01:set 8 bits * Slot : Channal ID 8 bits * Object : Object 16 bits * Port : 0 represents the card, * 1~8 represent the SFP module port numbers. 8 bits * Len : Data length 8 bits * Data */ struct olp6500_packet { uint8_t action; uint8_t slot; uint16_t object; uint8_t port; uint8_t len; union { struct heartbeat_switch_data hb_sw; struct work_mode_data work_mode; struct work_line_data work_line; struct switch_back_data sw_back; struct channel_info_data channel_info; struct channel_conf_data channel_conf; char data[0]; }; } __attribute__((packed)); static char * g_dynamic_cfgfile; int g_olp6500_config_reload; pthread_mutex_t g_olp6500_lock; uint16_t olp6500_object_map[OLP_OBJECT_MAX] = { [OLP_SET_HEARTBEAT_SWITCH] = OLP6500_HEARTBEAT_SWITCH_OBJECT, [OLP_SET_WORK_MODE] = OLP6500_WORK_MODE_OBJECT, [OLP_SET_WORK_LINE] = OLP6500_WORK_LINE_OBJECT, [OLP_SET_SWITCHBACK_MODE] = OLP6500_SWITCHBACK_OBJECT, [OLP_HEARTBEAT_PACKET] = OLP6500_HEARTBEAT_PACKET_OBJECT, [OLP_GET_CHANNEL_INFO] = OLP6500_CHANNEL_INFO_OBJECT, [OLP_GET_CHANNEL_CONF] = OLP6500_CHANNEL_CONF_OBJECT, }; static char * str_olp_device_type(enum olp_device_type device_type) { switch (device_type) { case OLP_DEVICE_TYPE_NIAGARA_3296: return "NIAGARA-3296"; case OLP_DEVICE_TYPE_OLP_6500: return "OLP-6500"; default: return ""; } } static char * str_olp_connect_type(enum olp_connect_type conn_type) { switch (conn_type) { case OLP_CONNECT_TYPE_COM: return "COM"; case OLP_CONNECT_TYPE_USB: return "USB"; case OLP_CONNECT_TYPE_NETWORK: return "NETWORK"; default: return ""; } } static char * str_olp_workmode(enum olp_channel_state state) { switch (state) { case OLP_CHANNEL_STATE_AUTO: return "AUTO"; case OLP_CHANNEL_STATE_FORCE_PASS: return "FORCE-PASS"; case OLP_CHANNEL_STATE_FORCE_BYPASS: return "FORCE-BYPASS"; default: return ""; } } static char * str_olp_enable_or_disable(uint32_t value) { if (value) return "ENABLE"; else return "DISABLE"; } static void olp6500_device_dump_one(struct olp_dev_desc * dev_desc, uint32_t channel_id) { struct olp_channel * channel = NULL; char str_ip_addr[INET_ADDRSTRLEN] = {0}; uint16_t port; MR_INFO("OLP-6500 device name:%s: is used", dev_desc->devsym); MR_INFO("\tdevice_type:\t\t\t\t\t%s", str_olp_device_type(dev_desc->type)); MR_INFO("\tconnect_type:\t\t\t\t\t%s", str_olp_connect_type(dev_desc->conn_type)); if (dev_desc->conn_type == OLP_CONNECT_TYPE_NETWORK) { inet_ntop(AF_INET, &(dev_desc->network.addr.sin_addr), str_ip_addr, INET_ADDRSTRLEN); port = ntohs(dev_desc->network.addr.sin_port); MR_INFO("\tipaddr:\t\t\t\t\t\t%s", str_ip_addr); MR_INFO("\tport:\t\t\t\t\t\t%u", port); } channel = &dev_desc->channels[channel_id]; MR_INFO("\tchannel_id:\t\t\t\t\t%u", channel->olp_channel_id); MR_INFO("\t\tused:\t\t\t\t\t%d", channel->used); MR_INFO("\t\tworkmode:\t\t\t\t%s", str_olp_workmode(channel->state)); MR_INFO("\t\theartbeat_mode:\t\t\t\t%s", str_olp_enable_or_disable(channel->en_heartbeat)); MR_INFO("\t\theartbeat_send_interval_in_ms:\t\t%u", channel->heartbeat_send_interval_in_ms); MR_INFO("\t\theartbeat_timeout_interval_in_ms:\t%u", channel->heartbeat_timeout_interval_in_ms); MR_INFO("\t\theartbeat_lost_threshold:\t\t%u", channel->heartbeat_lost_threshold); MR_INFO("\t\tnonrevertive_mode:\t\t\t%s", str_olp_enable_or_disable(channel->nonrevertive_mode)); } __rte_unused static void olp6500_device_dump(struct olp_device * olp_dev) { struct olp_dev_desc * olp_dev_desc = NULL; struct olp_channel * channel = NULL; char str_ip_addr[INET_ADDRSTRLEN] = {0}; uint16_t port; for (uint32_t i = 0; i < olp_dev->nr_olp_dev_descs; i++) { olp_dev_desc = olp_dev->olp_dev_descs[i]; MR_INFO("OLP-6500 device name:%s", olp_dev_desc->devsym); MR_INFO("\tdevice_type:\t\t\t\t\t%s", str_olp_device_type(olp_dev_desc->type)); MR_INFO("\tconnect_type:\t\t\t\t\t%s", str_olp_connect_type(olp_dev_desc->conn_type)); if (olp_dev_desc->conn_type == OLP_CONNECT_TYPE_NETWORK) { inet_ntop(AF_INET, &(olp_dev_desc->network.addr.sin_addr), str_ip_addr, INET_ADDRSTRLEN); port = ntohs(olp_dev_desc->network.addr.sin_port); MR_INFO("\tipaddr:\t\t\t\t\t\t%s", str_ip_addr); MR_INFO("\tport:\t\t\t\t\t\t%u", port); } for (uint32_t j = 1; j < NR_OLP6500_CHANNEL_PER_DEVICE_MAX; j++) { channel = &olp_dev_desc->channels[j]; if (channel->olp_channel_id == 0) { continue; } MR_INFO("\tchannel_id:\t\t\t\t\t%u", channel->olp_channel_id); MR_INFO("\t\tused:\t\t\t\t\t%d", channel->used); MR_INFO("\t\tworkmode:\t\t\t\t%s", str_olp_workmode(channel->state)); MR_INFO("\t\theartbeat_mode:\t\t\t\t%s", str_olp_enable_or_disable(channel->en_heartbeat)); MR_INFO("\t\theartbeat_send_interval_in_ms:\t\t%u", channel->heartbeat_send_interval_in_ms); MR_INFO("\t\theartbeat_timeout_interval_in_ms:\t%u", channel->heartbeat_timeout_interval_in_ms); MR_INFO("\t\theartbeat_lost_threshold:\t\t%u", channel->heartbeat_lost_threshold); MR_INFO("\t\tnonrevertive_mode:\t\t\t%s", str_olp_enable_or_disable(channel->nonrevertive_mode)); } } } static struct olp_dev_desc * olp6500_find_device_by_symbol(struct olp_device * olp_dev, char * olp_dev_sym) { struct olp_dev_desc * dev_desc = NULL; for (uint32_t i = 0; i < olp_dev->nr_olp_dev_descs; i++) { dev_desc = olp_dev->olp_dev_descs[i]; if (dev_desc->type == OLP_DEVICE_TYPE_OLP_6500 && strncmp(olp_dev_sym, dev_desc->devsym, MR_SYMBOL_MAX) == 0) { return dev_desc; } } return NULL; } static char * olp6500_str_object(uint16_t object) { switch (object) { case OLP_SET_HEARTBEAT_SWITCH: return "HEARTBEAT_SWITCH"; case OLP_SET_WORK_MODE: return "WORK_MODE"; case OLP_SET_WORK_LINE: return "WORK_LINE"; case OLP_SET_SWITCHBACK_MODE: return "SWITCHBACK_MODE"; case OLP_HEARTBEAT_PACKET: return "HEARTBEAT_PACKET"; case OLP_GET_CHANNEL_INFO: return "GET_CHANNEL_INFO"; case OLP_GET_CHANNEL_CONF: return "GET_CHANNEL_CONF"; default: break; } return NULL; } int olp6500_check_recv_data(char * buff, uint16_t object) { struct olp6500_packet * pkt = (struct olp6500_packet *)buff; if (ntohs(pkt->object) != olp6500_object_map[object]) { MR_ERROR("deployment object [%s] failed! receive data: 0xFF 0xEE", olp6500_str_object(object)); return RT_ERR; } if (pkt->len == 2 && pkt->data[0] == 0xFF && pkt->data[1] == 0xEE) { MR_ERROR("deployment object [%s] failed! receive data: 0xFF 0xEE", olp6500_str_object(object)); return RT_ERR; } return RT_SUCCESS; } static int olp6500_send_command_over_network_sync(struct olp_dev_desc * dev_desc, char * send_buff, int send_len, char * recv_buff, int recv_len) { int ret = 0; int length = 0; struct sockaddr_in addr = dev_desc->network.addr; struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { MR_ERROR("unable to get a socket %s", strerror(errno)); return RT_ERR; } setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); do { ret = sendto(sock, send_buff, send_len, 0, (struct sockaddr *)&addr, sizeof(addr)); } while (ret == -1 && errno == EINTR); if (ret == -1) { goto errout; } do { length = recvfrom(sock, recv_buff, recv_len, 0, NULL, 0); } while (length == -1 && errno == EINTR); if (length <= 0) { goto errout; } close(sock); return length; errout: close(sock); return RT_ERR; } static int olp6500_send_command_sync(struct olp_dev_desc * dev_desc, uint16_t object, char * send_buff, int send_len, char * recv_buff, int recv_len) { int length = 0; switch (dev_desc->conn_type) { case OLP_CONNECT_TYPE_NETWORK: length = olp6500_send_command_over_network_sync(dev_desc, send_buff, send_len, recv_buff, recv_len); if (length <= 0) { return RT_ERR; } break; case OLP_CONNECT_TYPE_COM: case OLP_CONNECT_TYPE_USB: break; default: break; } return olp6500_check_recv_data(recv_buff, object); } int olp6500_packet_construct(struct olp_channel * channel, int object, char * buff) { int length = 0; struct olp6500_packet * pkt = (struct olp6500_packet *)buff; switch (object) { case OLP_SET_HEARTBEAT_SWITCH: pkt->action = OLP_CONFIG_SET; pkt->slot = channel->olp_channel_id; pkt->object = htons(olp6500_object_map[object]); pkt->port = 0; pkt->len = 4; if (channel->en_heartbeat == OLP_CHANNEL_HEARTBEAT_DISABLE) { pkt->hb_sw.enable = 0; pkt->hb_sw.idle = 0; pkt->hb_sw.interval = 0; pkt->hb_sw.count = 0; } else { pkt->hb_sw.enable = channel->en_heartbeat; pkt->hb_sw.idle = 1; pkt->hb_sw.interval = channel->heartbeat_timeout_interval_in_ms / 20; pkt->hb_sw.count = channel->heartbeat_lost_threshold; } length = 10; break; case OLP_SET_WORK_MODE: pkt->action = OLP_CONFIG_SET; pkt->slot = channel->olp_channel_id; pkt->object = htons(olp6500_object_map[object]); pkt->port = 0; pkt->len = 1; if (channel->state == OLP_CHANNEL_STATE_AUTO) { pkt->work_mode.mode = 2; } else { pkt->work_mode.mode = 1; } length = 7; break; case OLP_SET_WORK_LINE: if (channel->state != OLP_CHANNEL_STATE_AUTO) { pkt->action = OLP_CONFIG_SET; pkt->slot = channel->olp_channel_id; pkt->object = htons(olp6500_object_map[object]); pkt->port = 0; pkt->len = 1; if (channel->state == OLP_CHANNEL_STATE_FORCE_PASS) { pkt->work_line.line_status = OLP6500_SET_LINE_INLINE; } else if (channel->state == OLP_CHANNEL_STATE_FORCE_BYPASS) { pkt->work_line.line_status = OLP6500_SET_LINE_BYPASS; } else { goto out; } length = 7; } break; case OLP_SET_SWITCHBACK_MODE: pkt->action = OLP_CONFIG_SET; pkt->slot = channel->olp_channel_id; pkt->object = htons(olp6500_object_map[object]); pkt->port = 0; pkt->len = 1; pkt->sw_back.enable = channel->nonrevertive_mode == OLP_CHANNEL_NONREVERTIVE_ENABLE ? 0x02 : 0x01; length = 7; break; case OLP_HEARTBEAT_PACKET: pkt->action = OLP_CONFIG_GET; pkt->slot = channel->olp_channel_id; pkt->object = htons(olp6500_object_map[object]); pkt->port = 0; pkt->len = 0; length = 6; case OLP_GET_CHANNEL_INFO: pkt->action = OLP_CONFIG_GET; pkt->slot = channel->olp_channel_id; pkt->object = htons(olp6500_object_map[object]); pkt->port = 0; pkt->len = 0; length = 6; case OLP_GET_CHANNEL_CONF: pkt->action = OLP_CONFIG_GET; pkt->slot = channel->olp_channel_id; pkt->object = htons(olp6500_object_map[object]); pkt->port = 0; pkt->len = 0; length = 6; default: break; } out: return length; } static void * olp6500_recv_heartbeat_handler(void * args) { pthread_detach(pthread_self()); struct olp_channel * channel = (struct olp_channel *)args; struct olp_dev_desc * dev_desc = channel->dev_desc; int len = 0; int sock = channel->timer.fd; char buff[BUFF_MAX] = {0}; __atomic_fetch_add(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); while (__atomic_load_n(&channel->timer.enable, __ATOMIC_RELAXED) == OLP_TIMER_ENABLE) { usleep(OLP6500_TIMER_ONE_CYCLE_US); len = recvfrom(sock, buff, BUFF_MAX - 1, 0, NULL, 0); if (len == -1) { continue; } struct olp6500_packet * pkt = (struct olp6500_packet *)buff; if (pkt->object != htons(OLP6500_HEARTBEAT_PACKET_OBJECT)) { continue; } struct timespec last_active_time; clock_gettime(CLOCK_REALTIME, &last_active_time); channel->runtime.last_active_time = last_active_time; } __atomic_fetch_sub(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); return NULL; } static void olp6500_send_heartbeat(int socket, struct olp_channel * channel) { int ret = 0; int pkt_len = 0; char buff[BUFF_MAX] = {0}; struct olp_dev_desc * dev_desc = channel->dev_desc; struct sockaddr_in * addr = &dev_desc->network.addr; pkt_len = olp6500_packet_construct(channel, OLP_HEARTBEAT_PACKET, buff); if (pkt_len <= 0) { return; } switch (dev_desc->conn_type) { case OLP_CONNECT_TYPE_NETWORK: do { ret = sendto(socket, buff, pkt_len, 0, (struct sockaddr *)addr, sizeof(*addr)); } while (ret == -1 && errno == EINTR); break; default: break; } return; } static void * olp6500_send_heartbeat_handler(void * args) { pthread_detach(pthread_self()); struct olp_channel * channel = (struct olp_channel *)args; struct olp_dev_desc * dev_desc = channel->dev_desc; struct timespec current_time; struct timespec send_pkt_last_time; struct timespec interval_time; struct timeval timeout; pthread_t tid; int ret = 0; timeout.tv_sec = 5; timeout.tv_usec = 0; memset(&send_pkt_last_time, 0, sizeof(send_pkt_last_time)); int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { return NULL; } setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); channel->timer.fd = sock; ret = pthread_create(&tid, NULL, olp6500_recv_heartbeat_handler, (void *)channel); if (ret != 0) { MR_ERROR("OLP_6500 create receive heartbeat packet thread failed : %s", strerror(ret)); return NULL; } __atomic_fetch_add(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); while (__atomic_load_n(&channel->timer.enable, __ATOMIC_RELAXED) == OLP_TIMER_ENABLE) { clock_gettime(CLOCK_MONOTONIC, ¤t_time); timespec_diff(&send_pkt_last_time, ¤t_time, &interval_time); if ((interval_time.tv_sec * 1000 + interval_time.tv_nsec / 1000 / 1000) >= channel->heartbeat_send_interval_in_ms) { olp6500_send_heartbeat(sock, channel); send_pkt_last_time = current_time; } usleep(OLP6500_TIMER_ONE_CYCLE_US); } __atomic_fetch_sub(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); close(sock); return NULL; } static int olp6500_heartbeat_thread_create(struct olp_channel * channel) { int ret = 0; pthread_t tid; if (channel->en_heartbeat == OLP_CHANNEL_HEARTBEAT_DISABLE) { return RT_SUCCESS; } __atomic_exchange_n(&channel->timer.enable, OLP_TIMER_ENABLE, __ATOMIC_SEQ_CST); ret = pthread_create(&tid, NULL, olp6500_send_heartbeat_handler, (void *)channel); if (ret != 0) { MR_ERROR("OLP_6500 create send heartbeat packet thread failed : %s", strerror(ret)); return RT_ERR; } return RT_SUCCESS; } int olp6500_apply_control_command_to_peer(struct olp_dev_desc * dev_desc, uint32_t channel_id) { int ret = 0; int pkt_len = 0; char buff[BUFF_MAX] = {0}; char str_ip_addr[INET_ADDRSTRLEN] = {0}; struct olp_channel * channel = NULL; channel = &dev_desc->channels[channel_id]; pkt_len = olp6500_packet_construct(channel, OLP_SET_HEARTBEAT_SWITCH, buff); ret = olp6500_send_command_sync(dev_desc, OLP_SET_HEARTBEAT_SWITCH, buff, pkt_len, buff, BUFF_MAX); if (ret != RT_SUCCESS) { goto errout; } pkt_len = olp6500_packet_construct(channel, OLP_SET_WORK_MODE, buff); ret = olp6500_send_command_sync(dev_desc, OLP_SET_WORK_MODE, buff, pkt_len, buff, BUFF_MAX); if (ret != RT_SUCCESS) { goto errout; } pkt_len = olp6500_packet_construct(channel, OLP_SET_WORK_LINE, buff); if (pkt_len > 0) { ret = olp6500_send_command_sync(dev_desc, OLP_SET_WORK_LINE, buff, pkt_len, buff, BUFF_MAX); if (ret != RT_SUCCESS) { goto errout; } } pkt_len = olp6500_packet_construct(channel, OLP_SET_SWITCHBACK_MODE, buff); ret = olp6500_send_command_sync(dev_desc, OLP_SET_SWITCHBACK_MODE, buff, pkt_len, buff, BUFF_MAX); if (ret != RT_SUCCESS) { goto errout; } olp6500_heartbeat_thread_create(channel); channel->runtime.errcode = OLP_SUCCESS; return RT_SUCCESS; errout: if (channel->runtime.errcode != OLP_ERR_CODE_CONN_FAIL) { inet_ntop(AF_INET, &(dev_desc->network.addr.sin_addr), str_ip_addr, INET_ADDRSTRLEN); MR_ERROR("The deployment of the OBP[%s:%u] configuration has encountered a failure. Reason: Connect %s:%u " "failed or configuration settings failed.", dev_desc->devsym, channel->olp_channel_id, str_ip_addr, ntohs(dev_desc->network.addr.sin_port)); } channel->runtime.errcode = OLP_ERR_CODE_CONN_FAIL; return RT_ERR; } static void * _olp6500_retry_apply_control_command(void * args) { struct olp_manager_main * olp_mgr_main = (struct olp_manager_main *)args; struct olp_dev_desc * dev_desc = NULL; struct olp_channel * channel = NULL; struct olp_device * olp_dev = NULL; pthread_detach(pthread_self()); while (1) { sleep(10); pthread_mutex_lock(&g_olp6500_lock); olp_dev = olp_mgr_main->olp6500_main; for (uint32_t i = 0; i < olp_dev->nr_olp_dev_descs; i++) { dev_desc = olp_dev->olp_dev_descs[i]; __atomic_fetch_add(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); if (dev_desc->type != OLP_DEVICE_TYPE_OLP_6500 || dev_desc->used != OLP_STATE_USED) { continue; } for (uint32_t j = 1; j < NR_OLP6500_CHANNEL_PER_DEVICE_MAX; j++) { channel = &dev_desc->channels[j]; if (channel->used != OLP_STATE_USED) { continue; } if (channel->runtime.errcode == OLP_ERR_CODE_CONN_FAIL) { olp6500_apply_control_command_to_peer(dev_desc, channel->olp_channel_id); } } } for (uint32_t i = 0; i < olp_dev->nr_olp_dev_descs; i++) { dev_desc = olp_dev->olp_dev_descs[i]; __atomic_fetch_sub(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); } pthread_mutex_unlock(&g_olp6500_lock); } return NULL; } static int olp6500_retry_apply_control_command(struct olp_manager_main * olp_mgr_main) { int ret = 0; pthread_t tid; ret = pthread_create(&tid, NULL, _olp6500_retry_apply_control_command, olp_mgr_main); if (ret != 0) { MR_ERROR("OLP_6500 create retry apply control command thread failed : %s", strerror(ret)); return RT_ERR; } return RT_SUCCESS; } /* * [olp0:1] * state = 0 * heartbeat = 1 * heartbeat_send_interval_in_ms = 300 * heartbeat_timeout_interval_in_ms = 300 * heartbeat_lost_threshold = 3 * nonrevertive_mode = 1 */ static int olp6500_channel_config_load(struct olp_dev_desc * olp_dev_desc, char * cfgfile, char * devsym) { int ret = 0; struct olp_channel * channel; olp_dev_desc->channels = ZMALLOC(sizeof(struct olp_channel) * NR_OLP6500_CHANNEL_PER_DEVICE_MAX); MR_VERIFY_MALLOC(olp_dev_desc->channels); for (uint32_t i = 1; i < NR_OLP6500_CHANNEL_PER_DEVICE_MAX; i++) { char channel_section[MR_SYMBOL_MAX] = {0}; snprintf(channel_section, sizeof(channel_section) - 1, "%s:%u", devsym, i); uint32_t olp_channel_state = 0; ret = MESA_load_profile_uint_nodef(cfgfile, channel_section, "state", &olp_channel_state); if (ret < 0) { MR_DEBUG("state is not existed in section %s, ignore this section", channel_section); continue; } uint32_t olp_channel_heartbeat = 0; ret = MESA_load_profile_uint_nodef(cfgfile, channel_section, "heartbeat", &olp_channel_heartbeat); if (ret < 0) { MR_DEBUG("heartbeat is not existed in section %s, ignore this section", channel_section); continue; } channel = &olp_dev_desc->channels[i]; channel->olp_channel_id = i; channel->state = olp_channel_state; channel->dev_desc = olp_dev_desc; channel->en_heartbeat = olp_channel_heartbeat; MESA_load_profile_uint_nodef(cfgfile, channel_section, "heartbeat_timeout_interval_in_ms", &channel->heartbeat_timeout_interval_in_ms); MESA_load_profile_uint_nodef(cfgfile, channel_section, "heartbeat_send_interval_in_ms", &channel->heartbeat_send_interval_in_ms); MESA_load_profile_uint_nodef(cfgfile, channel_section, "heartbeat_lost_threshold", &channel->heartbeat_lost_threshold); MESA_load_profile_uint_nodef(cfgfile, channel_section, "nonrevertive_mode", &channel->nonrevertive_mode); } return RT_SUCCESS; } /* * [olp_device:0] * name = olp0 * type = 2 * connect = 3 * in_addr = 1.1.1.1 * port = 6800 */ static int olp6500_config_load(struct olp_device * olp_dev, char * cfgfile) { int ret = 0; for (uint32_t i = 0; i < NR_OLP_DEVICE_MAX; i++) { char dev_symbol[MR_SYMBOL_MAX] = {0}; snprintf(dev_symbol, sizeof(dev_symbol) - 1, "olp_device:%u", i); uint32_t olp_dev_type = 0; MESA_load_profile_uint_def(cfgfile, dev_symbol, "type", &olp_dev_type, OLP_DEVICE_TYPE_UNKNOWN); if (olp_dev_type != OLP_DEVICE_TYPE_OLP_6500) { continue; } if (olp_dev->nr_olp_dev_descs == NR_OLP_DEVICE_MAX) { MR_WARNING("failed to add OLP_6500 config, Configured quantity has reached its maximum limit[%d].", NR_OLP_DEVICE_MAX); continue; } struct olp_dev_desc * olp_dev_desc = ZMALLOC(sizeof(struct olp_dev_desc)); MR_VERIFY_MALLOC(olp_dev_desc); MESA_load_profile_string_nodef(cfgfile, dev_symbol, "name", olp_dev_desc->devsym, sizeof(olp_dev_desc->devsym) - 1); olp_dev_desc->type = OLP_DEVICE_TYPE_OLP_6500; uint32_t olp_conn_type = 0; MESA_load_profile_uint_def(cfgfile, dev_symbol, "connect", &olp_conn_type, OLP_CONNECT_TYPE_UNKNOW); olp_dev_desc->conn_type = olp_conn_type; if (olp_dev_desc->conn_type == OLP_CONNECT_TYPE_NETWORK) { char str_in_addr[INET_ADDRSTRLEN] = {0}; MESA_load_profile_string_nodef(cfgfile, dev_symbol, "in_addr", str_in_addr, sizeof(str_in_addr)); ret = inet_pton(AF_INET, str_in_addr, &olp_dev_desc->network.addr.sin_addr); if (ret <= 0) { MR_CFGERR_INVALID_FORMAT(cfgfile, dev_symbol, "in_addr"); return RT_ERR; } uint32_t port = 0; ret = MESA_load_profile_uint_nodef(cfgfile, dev_symbol, "port", &port); if (ret < 0) { MR_CFGERR_INVALID_FORMAT(cfgfile, dev_symbol, "port"); return RT_ERR; } olp_dev_desc->network.addr.sin_family = AF_INET; olp_dev_desc->network.addr.sin_port = htons(port); } olp6500_channel_config_load(olp_dev_desc, cfgfile, olp_dev_desc->devsym); olp_dev->olp_dev_descs[olp_dev->nr_olp_dev_descs++] = olp_dev_desc; } return RT_SUCCESS; } int olp6500_set_used_state(struct olp_device * olp_dev, char * dev_sym, uint32_t channel_id) { struct olp_dev_desc * dev_desc = NULL; dev_desc = olp6500_find_device_by_symbol(olp_dev, dev_sym); if (dev_desc == NULL) { return RT_ERR; } dev_desc->channels[channel_id].used = OLP_STATE_USED; dev_desc->used = OLP_STATE_USED; olp6500_apply_control_command_to_peer(dev_desc, channel_id); olp6500_device_dump_one(dev_desc, channel_id); return RT_SUCCESS; } static int olp6500_copy_device_state(struct olp_device * src, struct olp_device * dst) { struct olp_channel * channel = NULL; struct olp_dev_desc * src_dev_desc = NULL; struct olp_dev_desc * dst_dev_desc = NULL; for (uint32_t i = 0; i < src->nr_olp_dev_descs; i++) { src_dev_desc = src->olp_dev_descs[i]; if (src_dev_desc->type != OLP_DEVICE_TYPE_OLP_6500 || src_dev_desc->used != OLP_STATE_USED) { continue; } dst_dev_desc = olp6500_find_device_by_symbol(dst, src_dev_desc->devsym); if (dst_dev_desc == NULL) { continue; } for (uint32_t j = 1; j < NR_OLP6500_CHANNEL_PER_DEVICE_MAX; j++) { channel = &src_dev_desc->channels[j]; if (channel->used != OLP_STATE_USED) { continue; } dst_dev_desc->channels[channel->olp_channel_id].runtime.last_active_time = channel->runtime.last_active_time; dst_dev_desc->channels[channel->olp_channel_id].used = OLP_STATE_USED; dst_dev_desc->used = OLP_STATE_USED; olp6500_apply_control_command_to_peer(dst_dev_desc, channel->olp_channel_id); olp6500_device_dump_one(dst_dev_desc, channel->olp_channel_id); } } return RT_SUCCESS; } static int olp6500_get_optical_power(char * buff, struct olp_channel * channel) { struct olp6500_packet * pkt = (struct olp6500_packet *)buff; if (pkt->object != htons(OLP6500_CHANNEL_INFO_OBJECT) || pkt->len != 17) { return RT_ERR; } int16_t r1_optical_power = ntohs(pkt->channel_info.r1_optical_power); int16_t r2_optical_power = ntohs(pkt->channel_info.r2_optical_power); int16_t r3_optical_power = ntohs(pkt->channel_info.r3_optical_power); int16_t r4_optical_power = ntohs(pkt->channel_info.r4_optical_power); channel->runtime.r1_optical_power = ((float)r1_optical_power) / 100; channel->runtime.r2_optical_power = ((float)r2_optical_power) / 100; channel->runtime.r3_optical_power = ((float)r3_optical_power) / 100; channel->runtime.r4_optical_power = ((float)r4_optical_power) / 100; channel->runtime.workline = pkt->channel_info.work_line; return RT_SUCCESS; } static int olp6500_check_channel_config(struct olp_channel * channel, char * buff, char * str_err_reason, int sz_err_reason) { struct olp6500_packet * pkt = (struct olp6500_packet *)buff; struct olp_dev_desc * dev_desc = channel->dev_desc; if (pkt->object != htons(OLP6500_CHANNEL_CONF_OBJECT)) { snprintf(str_err_reason, sz_err_reason, "get channel %d config fail.", channel->olp_channel_id); return RT_ERR; } if (pkt->channel_conf.heart_detect != channel->en_heartbeat) { snprintf(str_err_reason, sz_err_reason, "The current device[%s:%u] configuration[heartbeat_mode:%s] is inconsistent with the administrator's " "settings[heartbeat_mode:%s].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.heart_detect ? "enable" : "disable", channel->en_heartbeat ? "enable" : "disable"); if (channel->runtime.errcode != OLP_ERR_CODE_HB_MODE_INCONSISTENT) { MR_ERROR("The current device[%s:%u] configuration[heartbeat_mode:%s] is inconsistent with the " "administrator's settings[heartbeat_mode:%s].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.heart_detect ? "enable" : "disable", channel->en_heartbeat ? "enable" : "disable"); } channel->runtime.errcode = OLP_ERR_CODE_HB_MODE_INCONSISTENT; return RT_ERR; } if (channel->en_heartbeat) { if (pkt->channel_conf.heart_interval != (channel->heartbeat_timeout_interval_in_ms / 20)) { snprintf(str_err_reason, sz_err_reason, "The current device[%s:%u] configuration[heartbeat_timeout_interval_in_ms:%u] is inconsistent " "with the administrator's settings[heartbeat_timeout_interval_in_ms:%d].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.heart_interval * 20, channel->heartbeat_timeout_interval_in_ms); if (channel->runtime.errcode != OLP_ERR_CODE_HB_INTERVAL_INCONSISTENT) { MR_ERROR("The current device[%s:%u] configuration[heartbeat_timeout_interval_in_ms:%u] is inconsistent " "with the administrator's settings[heartbeat_timeout_interval_in_ms:%d].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.heart_interval * 20, channel->heartbeat_timeout_interval_in_ms); } channel->runtime.errcode = OLP_ERR_CODE_HB_INTERVAL_INCONSISTENT; return RT_ERR; } if (pkt->channel_conf.heart_count != channel->heartbeat_lost_threshold) { snprintf(str_err_reason, sz_err_reason, "The current device[%s:%u] configuration[heartbeat_lost_threshold:%u] is inconsistent with the " "administrator's settings[heartbeat_lost_threshold:%u].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.heart_count, channel->heartbeat_lost_threshold); if (channel->runtime.errcode != OLP_ERR_CODE_HB_COUNT_INCONSISTENT) { MR_ERROR("The current device[%s:%u] configuration[heartbeat_lost_threshold:%u] is inconsistent with " "the administrator's settings[heartbeat_lost_threshold:%u].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.heart_count, channel->heartbeat_lost_threshold); } channel->runtime.errcode = OLP_ERR_CODE_HB_COUNT_INCONSISTENT; return RT_ERR; } } uint8_t channel_work_mode = 0; if (channel->state == OLP_CHANNEL_STATE_AUTO) { channel_work_mode = OLP6500_WORK_MODE_AUTO; } else { channel_work_mode = OLP6500_WORK_MODE_MANUL; } if (pkt->channel_conf.work_mode != channel_work_mode) { snprintf(str_err_reason, sz_err_reason, "The current device[%s:%u] configuration[workmode:%s] is inconsistent with the administrator's " "settings[workmode:%s].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.work_mode == OLP6500_WORK_MODE_AUTO ? "auto" : "manual", channel_work_mode == OLP6500_WORK_MODE_AUTO ? "auto" : "manual"); if (channel->runtime.errcode != OLP_ERR_CODE_WORK_MODE_INCONSISTENT) { MR_ERROR("The current device[%s:%u] configuration[workmode:%s] is inconsistent with the administrator's " "settings[workmode:%s].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.work_mode == OLP6500_WORK_MODE_AUTO ? "auto" : "manual", channel_work_mode == OLP6500_WORK_MODE_AUTO ? "auto" : "manual"); } channel->runtime.errcode = OLP_ERR_CODE_WORK_MODE_INCONSISTENT; return RT_ERR; } if (channel->state != OLP_CHANNEL_STATE_AUTO) { uint8_t channel_work_line = 0; if (channel->state == OLP_CHANNEL_STATE_FORCE_PASS) { channel_work_line = OLP6500_LINE_STATUS_INLINE; } else if (channel->state == OLP_CHANNEL_STATE_FORCE_BYPASS) { channel_work_line = OLP6500_LINE_STATUS_BYPASS; } if (pkt->channel_conf.work_line != channel_work_line) { snprintf(str_err_reason, sz_err_reason, "The current device[%s:%u] configuration[workline:%s] is inconsistent with the administrator's " "settings[workline:%s].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.work_line == OLP6500_LINE_STATUS_INLINE ? "inline" : "bypass", channel_work_line == OLP6500_LINE_STATUS_INLINE ? "inline" : "bypass"); if (channel->runtime.errcode != OLP_ERR_CODE_WORK_LINE_INCONSISTENT) { MR_ERROR("The current device[%s:%u] configuration[workline:%s] is inconsistent with the " "administrator's settings[workline:%s].", dev_desc->devsym, channel->olp_channel_id, pkt->channel_conf.work_line == OLP6500_LINE_STATUS_INLINE ? "inline" : "bypass", channel_work_line == OLP6500_LINE_STATUS_INLINE ? "inline" : "bypass"); } channel->runtime.errcode = OLP_ERR_CODE_WORK_LINE_INCONSISTENT; return RT_ERR; } } if ((!pkt->channel_conf.switch_back_mode) != channel->nonrevertive_mode) { snprintf(str_err_reason, sz_err_reason, "The current device[%s:%u] configuration[nonrevertive_mode:%s] is inconsistent with the " "administrator's settings[nonrevertive_mode:%s].", dev_desc->devsym, channel->olp_channel_id, (!pkt->channel_conf.switch_back_mode) ? "yes" : "no", channel->nonrevertive_mode ? "yes" : "no"); if (channel->runtime.errcode != OLP_ERR_CODE_SW_BACK_INCONSISTENT) { MR_ERROR("The current device[%s:%u] configuration[nonrevertive_mode:%s] is inconsistent with the " "administrator's settings[nonrevertive_mode:%s].", dev_desc->devsym, channel->olp_channel_id, (!pkt->channel_conf.switch_back_mode) ? "yes" : "no", channel->nonrevertive_mode ? "yes" : "no"); } channel->runtime.errcode = OLP_ERR_CODE_SW_BACK_INCONSISTENT; return RT_ERR; } channel->runtime.errcode = OLP_SUCCESS; return RT_SUCCESS; } cJSON * olp6500_monit_loop(struct sc_main * sc_main) { int ret = 0; int pkt_len = 0; char str_time[80] = {0}; char buff[BUFF_MAX] = {0}; char str_ip_addr[INET_ADDRSTRLEN] = {0}; char str_err_reason[MR_STRING_MAX] = {0}; char str_optical_power[16] = {0}; struct olp_dev_desc * dev_desc = NULL; struct olp_channel * channel = NULL; struct olp_device * olp_dev = NULL; cJSON * j_obp_device = NULL; cJSON * j_channel = NULL; struct cJSON * j_obp_device_array = cJSON_CreateArray(); struct cJSON * j_channel_array = NULL; pthread_mutex_lock(&g_olp6500_lock); olp_dev = sc_main->olp_mgr_main->olp6500_main; for (int index = 0; index < olp_dev->nr_olp_dev_descs; index++) { dev_desc = olp_dev->olp_dev_descs[index]; __atomic_fetch_add(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); if (dev_desc->type != OLP_DEVICE_TYPE_OLP_6500 || dev_desc->used != OLP_STATE_USED) { continue; } j_obp_device = cJSON_CreateObject(); cJSON_AddStringToObject(j_obp_device, "symbol", dev_desc->devsym); j_channel_array = cJSON_CreateArray(); for (uint32_t j = 1; j < NR_OLP6500_CHANNEL_PER_DEVICE_MAX; j++) { channel = &dev_desc->channels[j]; if (channel->used == OLP_STATE_UNUSED) { continue; } j_channel = cJSON_CreateObject(); if (channel->runtime.errcode == OLP_ERR_CODE_CONN_FAIL) { cJSON_AddNumberToObject(j_channel, "channel_id", channel->olp_channel_id); inet_ntop(AF_INET, &(dev_desc->network.addr.sin_addr), str_ip_addr, INET_ADDRSTRLEN); snprintf(str_err_reason, sizeof(str_err_reason), "The deployment of the OBP configuration has encountered a failure. Reason: Connect %s:%u " "failed or configuration settings failed. ", str_ip_addr, ntohs(dev_desc->network.addr.sin_port)); cJSON_AddStringToObject(j_channel, "error_reason", str_err_reason); cJSON_AddItemToArray(j_channel_array, j_channel); continue; } pkt_len = olp6500_packet_construct(channel, OLP_GET_CHANNEL_INFO, buff); ret = olp6500_send_command_sync(dev_desc, OLP_GET_CHANNEL_INFO, buff, pkt_len, buff, BUFF_MAX); if (ret != RT_SUCCESS) { cJSON_AddNumberToObject(j_channel, "channel_id", channel->olp_channel_id); cJSON_AddStringToObject(j_channel, "workline", "--"); cJSON_AddStringToObject(j_channel, "R1", "--"); cJSON_AddStringToObject(j_channel, "R2", "--"); cJSON_AddStringToObject(j_channel, "R3", "--"); cJSON_AddStringToObject(j_channel, "R4", "--"); snprintf(str_time, sizeof(str_time), "%ld", channel->runtime.last_active_time.tv_sec); cJSON_AddStringToObject(j_channel, "last_active_time", str_time); inet_ntop(AF_INET, &(dev_desc->network.addr.sin_addr), str_ip_addr, INET_ADDRSTRLEN); snprintf(str_err_reason, sizeof(str_err_reason), "Get channel info error: connect %s:%u failed.", str_ip_addr, ntohs(dev_desc->network.addr.sin_port)); cJSON_AddStringToObject(j_channel, "error_reason", str_err_reason); cJSON_AddItemToArray(j_channel_array, j_channel); if (channel->runtime.errcode != OLP_ERR_CODE_GET_CHANNEL_INFO_FAIL) { MR_ERROR("Get channel info error: connect %s:%u failed.", str_ip_addr, ntohs(dev_desc->network.addr.sin_port)); } channel->runtime.errcode = OLP_ERR_CODE_GET_CHANNEL_INFO_FAIL; continue; } olp6500_get_optical_power(buff, channel); cJSON_AddNumberToObject(j_channel, "channel_id", channel->olp_channel_id); switch (channel->runtime.workline) { case OLP6500_LINE_STATUS_INLINE: cJSON_AddStringToObject(j_channel, "workline", "inline"); break; case OLP6500_LINE_STATUS_BYPASS: cJSON_AddStringToObject(j_channel, "workline", "bypass"); break; default: cJSON_AddStringToObject(j_channel, "workline", "error"); } snprintf(str_optical_power, sizeof(str_optical_power), "%.2f", channel->runtime.r1_optical_power); cJSON_AddStringToObject(j_channel, "r1", str_optical_power); snprintf(str_optical_power, sizeof(str_optical_power), "%.2f", channel->runtime.r2_optical_power); cJSON_AddStringToObject(j_channel, "r2", str_optical_power); snprintf(str_optical_power, sizeof(str_optical_power), "%.2f", channel->runtime.r3_optical_power); cJSON_AddStringToObject(j_channel, "r3", str_optical_power); snprintf(str_optical_power, sizeof(str_optical_power), "%.2f", channel->runtime.r4_optical_power); cJSON_AddStringToObject(j_channel, "r4", str_optical_power); snprintf(str_time, sizeof(str_time), "%ld", channel->runtime.last_active_time.tv_sec); cJSON_AddStringToObject(j_channel, "last_active_time", str_time); pkt_len = olp6500_packet_construct(channel, OLP_GET_CHANNEL_CONF, buff); ret = olp6500_send_command_sync(dev_desc, OLP_GET_CHANNEL_CONF, buff, pkt_len, buff, BUFF_MAX); if (ret == RT_SUCCESS) { ret = olp6500_check_channel_config(channel, buff, str_err_reason, sizeof(str_err_reason)); if (ret != RT_SUCCESS) { cJSON_AddStringToObject(j_channel, "error_reason", str_err_reason); } } cJSON_AddItemToArray(j_channel_array, j_channel); } cJSON_AddItemToObject(j_obp_device, "channel", j_channel_array); cJSON_AddItemToArray(j_obp_device_array, j_obp_device); } for (int index = 0; index < olp_dev->nr_olp_dev_descs; index++) { dev_desc = olp_dev->olp_dev_descs[index]; __atomic_fetch_sub(&dev_desc->refcnt, 1, __ATOMIC_RELAXED); } pthread_mutex_unlock(&g_olp6500_lock); return j_obp_device_array; } int olp6500_destroy_timer(struct olp_device * olp_dev) { struct olp_channel * channel = NULL; struct olp_dev_desc * dev_desc = NULL; for (uint32_t i = 0; i < olp_dev->nr_olp_dev_descs; i++) { dev_desc = olp_dev->olp_dev_descs[i]; if (dev_desc->type != OLP_DEVICE_TYPE_OLP_6500 || dev_desc->used != OLP_STATE_USED) { continue; } for (uint32_t j = 1; j < NR_OLP6500_CHANNEL_PER_DEVICE_MAX; j++) { channel = &dev_desc->channels[j]; if (channel->used == OLP_STATE_UNUSED) { continue; } __atomic_exchange_n(&channel->timer.enable, OLP_TIMER_DISABLE, __ATOMIC_SEQ_CST); } } return RT_SUCCESS; } static int olp6500_device_deinit(struct olp_device * olp_dev) { struct olp_dev_desc * dev_desc = NULL; for (uint32_t i = 0; i < olp_dev->nr_olp_dev_descs; i++) { dev_desc = olp_dev->olp_dev_descs[i]; while (__atomic_load_n(&dev_desc->refcnt, __ATOMIC_RELAXED) > 0) { usleep(OLP6500_TIMER_ONE_CYCLE_US); } } for (uint32_t i = 0; i < olp_dev->nr_olp_dev_descs; i++) { dev_desc = olp_dev->olp_dev_descs[i]; FREE(dev_desc->channels); FREE(dev_desc); } FREE(olp_dev); return RT_SUCCESS; } int olp6500_set_reload_flag() { __atomic_exchange_n(&g_olp6500_config_reload, 1, __ATOMIC_SEQ_CST); return RT_SUCCESS; } static void * olp6500_config_reload(void * args) { int ret = 0; struct olp_manager_main * olp_mgr_main = (struct olp_manager_main *)args; struct olp_device * olp_dev_old = NULL; struct olp_device * olp_dev_new = NULL; pthread_detach(pthread_self()); while (1) { usleep(OLP6500_RELOAD_CONFIG_CYCLE_US); if (__atomic_load_n(&g_olp6500_config_reload, __ATOMIC_RELAXED) == 0) { continue; } __atomic_exchange_n(&g_olp6500_config_reload, 0, __ATOMIC_SEQ_CST); ret = 0; olp_dev_old = olp_mgr_main->olp6500_main; olp_dev_new = ZMALLOC(sizeof(struct olp_device)); MR_VERIFY_MALLOC(olp_dev_new); ret = olp6500_config_load(olp_dev_new, g_dynamic_cfgfile); if (ret != RT_SUCCESS) { goto errout; } pthread_mutex_lock(&g_olp6500_lock); olp6500_copy_device_state(olp_dev_old, olp_dev_new); olp6500_destroy_timer(olp_dev_old); olp_mgr_main->olp6500_main = olp_dev_new; olp6500_device_deinit(olp_dev_old); pthread_mutex_unlock(&g_olp6500_lock); continue; errout: olp6500_device_deinit(olp_dev_new); continue; } return NULL; } static int olp6500_create_thread_config_reload(struct olp_manager_main * olp_mgr_main) { int ret = 0; pthread_t tid; ret = pthread_create(&tid, NULL, olp6500_config_reload, olp_mgr_main); if (ret != 0) { MR_ERROR("OLP_6500 create config reload thread failed : %s", strerror(ret)); return RT_ERR; } return RT_SUCCESS; } int olp6500_init(struct olp_manager_main * olp_mgr_main, char * local_cfgfile) { int ret = 0; g_dynamic_cfgfile = local_cfgfile; pthread_mutex_init(&g_olp6500_lock, NULL); struct olp_device * olp_dev = ZMALLOC(sizeof(struct olp_device)); MR_VERIFY_MALLOC(olp_dev); ret = olp6500_config_load(olp_dev, local_cfgfile); if (ret != RT_SUCCESS) { MR_ERROR("load OLP_6500 config failed. "); goto errout; } pthread_mutex_lock(&g_olp6500_lock); olp_mgr_main->olp6500_main = olp_dev; olp6500_retry_apply_control_command(olp_mgr_main); olp6500_create_thread_config_reload(olp_mgr_main); pthread_mutex_unlock(&g_olp6500_lock); return RT_SUCCESS; errout: return RT_ERR; }