STRUCT_OFFSET( s, m )宏

本文介绍了一个用于计算C/C++结构体成员相对于结构体起始位置偏移量的宏定义方法。通过示例代码展示了如何使用该宏来获取man结构体中各成员的偏移量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#define    STRUCT_OFFSET( s, m )    ( (UINT8)( & ((s *)0) -> m ) )    /* 定义获取结构成员相对偏移地址的宏 */

如上宏的意义,获取结构体S中元素M,相对于首元素的偏移量。

#include <stdio.h>
#define STRUCT_OFFSET(s,m)   ( (int)(&((s*)0)->m)) /* 定义获取结构成员相对偏移地址的宏 */

struct man
{
	char name[63];
	int year;
	char son_name[59];
	char son_year;
};
int main()
{ 
    printf("name offset:%d\n",STRUCT_OFFSET( struct man, name ));
    printf("year offset:%d\n",STRUCT_OFFSET( struct man, year ));
	printf("son_name offset:%d\n",STRUCT_OFFSET( struct man, son_name ));
	printf("son_year offset:%d\n",STRUCT_OFFSET( struct man, son_year ));
    return 0;
}
name offset:0
year offset:64
son_name offset:68
son_year offset:127

 

void SdNavigationHighway::GetHarborStopInfo() { auto sd_map_info = INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr(); if (!sd_map_info) { AWARN << "[SDNOA] Failed: sd_map_info is null!"; return; } uint64_t ego_section_id = sd_map_info->navi_start.section_id; double ego_s_offset = sd_map_info->navi_start.s_offset; #ifdef ENABLE_DEBUG_SDNAVIGATION AINFO << "[SDNOA] Ego section ID: " << ego_section_id << ", Ego s_offset: " << ego_s_offset; #endif int ego_section_index = -1; for (size_t i = 0; i < sd_map_info->mpp_sections.size(); ++i) { if (sd_map_info->mpp_sections[i].id == ego_section_id) { ego_section_index = static_cast<int>(i); break; } } if (ego_section_index == -1) { AWARN << "[SDNOA] Failed: ego_section not found!"; return; } // 计算自车的全局 s 坐标 double ego_global_s = 0.0; for (int i = 0; i < ego_section_index; ++i) { ego_global_s += sd_map_info->mpp_sections[i].length; } ego_global_s += ego_s_offset; #ifdef ENABLE_DEBUG_SDNAVIGATION AINFO << "[SDNOA] Ego global s: " << ego_global_s; #endif double min_s = rear_distance_; // -100.0 double max_s = front_distance_; // 300.0 sd_harbor_stop_info_.exists = false; sd_harbor_stop_info_.is_left_most = false; sd_harbor_stop_info_.is_right_most = false; sd_harbor_stop_info_.ranges.clear(); std::vector<std::pair<double, double>> harbor_stop_ranges; bool current_leftmost = false; bool current_rightmost = false; double current_s = 0.0; for (size_t i = 0; i < sd_map_info->mpp_sections.size(); ++i) { const auto &section = sd_map_info->mpp_sections[i]; double section_start_s = current_s; double section_end_s = current_s + section.length; if (section_end_s < ego_global_s + min_s || section_start_s > ego_global_s + max_s) { current_s += section.length; continue; } #ifdef ENABLE_DEBUG_SDNAVIGATION AINFO << "[SDNOA] Section ID: " << section.id << " start from s: " << section_start_s << " to s: " << section_end_s; #endif // 遍历 Section 中的 LaneGroup for (const auto &lg_idx : section.lane_group_idx) { const auto *lane_group = INTERNAL_PARAMS.sd_map_data.GetSDLaneGroupInfoById(lg_idx.id); if (lane_group && !lane_group->lane_info.empty()) { double lg_start_s = section_start_s + lg_idx.start_range_offset; double lg_end_s = section_start_s + lg_idx.end_range_offset; #ifdef ENABLE_DEBUG_SDNAVIGATION AINFO << " [SDNOA] LaneGroup ID: " << lg_idx.id << " start from s: " << lg_start_s << " to s: " << lg_end_s << ", lanes: " << lane_group->lane_info.size(); #endif // 检测港湾停靠站 for (const auto &lane : lane_group->lane_info) { if (lane.type == cem::message::env_model::LaneType::LANE_HARBOR_STOP) { double lane_start_s = std::max(lg_start_s - ego_global_s, min_s); double lane_end_s = std::min(lg_end_s - ego_global_s, max_s); if (lane_start_s < lane_end_s) { // 动态合并港湾停靠站区间 if (!harbor_stop_ranges.empty() && lane_start_s <= harbor_stop_ranges.back().second) { harbor_stop_ranges.back().second = std::max(harbor_stop_ranges.back().second, lane_end_s); } else { harbor_stop_ranges.emplace_back(lane_start_s, lane_end_s); } SD_COARSE_MATCH_LOG << " Harbor stop lane detected, range: [" << lane_start_s << ", " << lane_end_s << "]"; } } } size_t lane_count = lane_group->lane_info.size(); // 检测港湾车道并记录位置 for (size_t idx = 0; idx < lane_count; ++idx) { if (lane_group->lane_info[idx].type == cem::message::env_model::LaneType::LANE_HARBOR_STOP) { // 记录首尾位置 if (idx == 0) { current_leftmost = true; } if (idx == lane_count - 1) { current_rightmost = true; } } } } } current_s += section.length; } sd_harbor_stop_info_.ranges = harbor_stop_ranges; sd_harbor_stop_info_.exists = !harbor_stop_ranges.empty(); sd_harbor_stop_info_.is_left_most = current_leftmost; sd_harbor_stop_info_.is_right_most = current_rightmost; if (sd_harbor_stop_info_.exists) { SD_COARSE_MATCH_LOG << "[GetHarborStopInfo] Harbor stop exists in merged ranges:"; for (const auto &range : sd_harbor_stop_info_.ranges) { SD_COARSE_MATCH_LOG << " [" << range.first << ", " << range.second << "] " << " is_left_most: " << sd_harbor_stop_info_.is_left_most << " is_right_most: " << sd_harbor_stop_info_.is_right_most; } } else { SD_COARSE_MATCH_LOG << "[GetHarborStopInfo] No harbor stop found."; } } struct HarborStopInfo { bool exists = false; // 是否存在港湾停靠站 std::vector<std::pair<double, double>> ranges; // 港湾停靠站的区间 [start_s, end_s] bool is_left_most = false; // 最左 bool is_right_most = false; // 最右 }; 解释代码,并且依据该函数写2个新的函数,分别是计算LANE_ACC的信息和LANE_DEC的信息。定义好输出的结构,按照上面函数的计算方式进行实现。C++。 添加注释和调试信息。
最新发布
08-13
/* * SEMIDRIVE Copyright Statement * Copyright (c) SEMIDRIVE. All rights reserved * This software and all rights therein are owned by SEMIDRIVE, * and are protected by copyright law and other relevant laws, regulations and protection. * Without SEMIDRIVE’s prior written consent and /or related rights, * please do not use this software or any potion thereof in any form or by any means. * You may not reproduce, modify or distribute this software except in compliance with the License. * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * You should have received a copy of the License along with this program. * If not, see <http://www.semidrive.com/licenses/>. */ #ifndef __SDRV_G2D_H__ #define __SDRV_G2D_H__ #include <linux/platform_device.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <linux/list.h> #include <asm/io.h> #include <linux/iommu.h> #include <linux/wait.h> #include <uapi/drm/drm_fourcc.h> #include <uapi/drm/sdrv_g2d_cfg.h> #include "g2d_common.h" #define PR_INFO pr_info #define ERROR pr_err typedef unsigned long int addr_t; #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif extern int debug_g2d; #define G2D_INFO(fmt, args...) do {\ PR_INFO("[g2d] [%20s] " fmt, __func__, ##args);\ }while(0) #define G2D_DBG(fmt, args...) do {\ if (debug_g2d >= 1) {\ PR_INFO("[g2d] <%d> [%20s] " fmt, __LINE__, __func__, ##args);}\ }while(0) #define G2D_ERROR(fmt, args...) ERROR("[g2d] <%d> [%20s] Error: " fmt, __LINE__, __func__, ##args) #define DDBG(x) G2D_DBG(#x " -> %d\n", x) #define XDBG(x) G2D_DBG(#x " -> 0x%x\n", x) #define PDBG(x) G2D_DBG(#x " -> %p\n", x) #define ENTRY() G2D_DBG("call <%d>\n", __LINE__) #define GP_ECHO_NAME "g2d_gpipe_echo" #define GP_MID_NAME "g2d_gpipe_mid" #define GP_HIGH_NAME "g2d_gpipe_high" #define SPIPE_NAME "g2d_spipe" #define G2D_NR_DEVS 4 /*Kunlun DP layer format TILE vsize*/ enum { TILE_VSIZE_1 = 0b000, TILE_VSIZE_2 = 0b001, TILE_VSIZE_4 = 0b010, TILE_VSIZE_8 = 0b011, TILE_VSIZE_16 = 0b100, }; /*Kunlun DP layer format TILE hsize*/ enum { TILE_HSIZE_1 = 0b000, TILE_HSIZE_8 = 0b001, TILE_HSIZE_16 = 0b010, TILE_HSIZE_32 = 0b011, TILE_HSIZE_64 = 0b100, TILE_HSIZE_128 = 0b101, }; /**/ enum { FBDC_U8U8U8U8 = 0xc, FBDC_U16 = 0x9, FBDC_R5G6B5 = 0x5, FBDC_U8 = 0x0, FBDC_NV21 = 0x37, FBDC_YUV420_16PACK = 0x65 }; enum kunlun_plane_property { PLANE_PROP_ALPHA, PLANE_PROP_BLEND_MODE, PLANE_PROP_FBDC_HSIZE_Y, PLANE_PROP_FBDC_HSIZE_UV, PLANE_PROP_CAP_MASK, PLANE_PROP_MAX_NUM }; enum { DRM_MODE_BLEND_PIXEL_NONE = 0, DRM_MODE_BLEND_PREMULTI, DRM_MODE_BLEND_COVERAGE }; enum { PLANE_DISABLE, PLANE_ENABLE }; enum { PROP_PLANE_CAP_RGB = 0, PROP_PLANE_CAP_YUV, PROP_PLANE_CAP_XFBC, PROP_PLANE_CAP_YUV_FBC, PROP_PLANE_CAP_ROTATION, PROP_PLANE_CAP_SCALING, }; enum { TYPE_GP_ECHO = 0, TYPE_GP_MID, TYPE_GP_HIGH, TYPE_SPIPE }; struct g2d_pipe; struct pipe_operation { int (*init)(struct g2d_pipe *); int (*set)(struct g2d_pipe *, int , struct g2d_layer *); void (*csc_coef_set)(struct g2d_pipe *, struct g2d_coeff_table *); }; struct g2d_pipe { void __iomem *iomem_regs; void __iomem *regs; unsigned long reg_offset; int id; // the ordered id from 0 struct sdrv_g2d *gd; const char *name; int type; struct pipe_operation *ops; struct g2d_pipe_capability *cap; struct g2d_pipe *next; }; struct g2d_monitor { int is_monitor; int is_init; ktime_t timeout; struct hrtimer timer; bool g2d_on_task; int occupancy_rate; int timer_count; int valid_times; int sampling_time; }; struct sdrv_g2d { struct platform_device *pdev; struct cdev cdev; struct miscdevice mdev; void __iomem *iomem_regs; void __iomem *regs; bool iommu_enable; struct iommu_domain *domain; struct mutex m_lock; struct wait_queue_head wq; bool frame_done; int id; const char *name; int irq; int write_mode; cmdfile_info cmd_info[G2D_CMDFILE_MAX_NUM]; unsigned long dma_buf; const struct g2d_ops *ops; struct g2d_capability cap; struct g2d_pipe *pipes[PIPE_MAX]; int num_pipe; int du_inited; struct g2d_monitor monitor; }; struct g2d_ops { int (*init)(struct sdrv_g2d *); int (*enable)(struct sdrv_g2d*, int); int (*reset)(struct sdrv_g2d *); int (*mlc_set)(struct sdrv_g2d *, int , struct g2d_input *); int (*fill_rect)(struct sdrv_g2d *, struct g2d_bg_cfg *, struct g2d_output_cfg *); int (*fastcopy)(struct sdrv_g2d *, addr_t , u32 , u32 , u32 , addr_t , u32); int (*config)(struct sdrv_g2d *); int (*irq_handler)(struct sdrv_g2d *); int (*rwdma)(struct sdrv_g2d *, struct g2d_input *); void (*close_fastcopy)(struct sdrv_g2d *); int (*wpipe_set)(struct sdrv_g2d *, int, struct g2d_output_cfg *); int (*check_stroke)(struct g2d_input *); int (*scaler_coef_set)(struct sdrv_g2d *, struct g2d_coeff_table *); }; struct sdrv_g2d_data { const char *version; const struct g2d_ops* ops; }; struct ops_entry { const char *ver; void *ops; }; int g2d_get_capability(struct g2d_capability *cap); unsigned int get_compval_from_comp(struct pix_g2dcomp *comp); unsigned int get_frm_ctrl_from_comp(struct pix_g2dcomp *comp); int sdrv_wpipe_pix_comp(uint32_t format, struct pix_g2dcomp *comp); int sdrv_pix_comp(uint32_t format, struct pix_g2dcomp *comp); bool g2d_format_is_yuv(uint32_t format); int g2d_format_wpipe_bypass(uint32_t format); struct ops_list { struct list_head head; struct ops_entry *entry; }; extern struct list_head g2d_pipe_list_head; int g2d_ops_register(struct ops_entry *entry, struct list_head *head); void *g2d_ops_attach(const char *str, struct list_head *head); #define g2d_pipe_ops_register(entry) g2d_ops_register(entry, &g2d_pipe_list_head) #define g2d_pipe_ops_attach(str) g2d_ops_attach(str, &g2d_pipe_list_head) int g2d_choose_pipe(struct sdrv_g2d *gd, int hwid, int type, uint32_t offset); struct sdrv_g2d *get_g2d_by_id(int id); extern struct ops_entry gpipe_mid_g2d_entry; extern struct ops_entry gpipe_high_g2d_entry; extern struct ops_entry spipe_g2d_entry; #endif //__SDRV_G2D_H__ 请提供以上代码详细的中文注释,包括函数声明、结构体成员、枚举成员等。
07-25
int Filling_Group(uint8_t *read_buffer, AddrGroup *group, int bytes_read) { int i = 0; // 将数据填充到原始参数位置 for (i = 0; i < group->param_count; i++) { DEVICEID_PARAID *param = group->params[i]; int bit_offset = group->bit_offsets[i]; AddrParseResult parsed = parse_address(param->RegAddress); // 计算数据在缓冲区中的位置 int addr_offset = parsed.base_addr - group->start_addr; int buffer_offset = addr_offset * (group->is_double_byte ? 2 : 1); if (buffer_offset < 0 || buffer_offset >= bytes_read) { printf("Invalid buffer offset: %d\n", buffer_offset); continue; } // 处理位访问 if (bit_offset >= 0) { // 位访问 - 只处理单个位 uint8_t byte_value = read_buffer[buffer_offset]; uint8_t bit_value = extract_bit_value(byte_value, bit_offset); // 将位值存储在第一个字节中 memset(param->RegByteValue, 0, sizeof(param->RegByteValue)); param->RegByteValue[0] = bit_value; param->RegByteLen = 1; } else { // 字节访问 - 根据类型复制数据 int bytes_to_copy = group->is_double_byte ? 4 : 2; if (buffer_offset + bytes_to_copy > bytes_read) { bytes_to_copy = bytes_read - buffer_offset; } memcpy(param->RegByteValue, read_buffer + buffer_offset, bytes_to_copy); param->RegByteLen = bytes_to_copy; } } } #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <ctype.h> #include <stdbool.h> #include <unistd.h> #include <time.h> /* 定义常量 */ #define MODBUS_MAX_REGISTERS 125 // modbus最多只支持采集125个 #define MAX_DATA_PACKET_SIZE 4096 // 地址类型定义 #define SINGLE_BYTE_TYPES “%V”, “%IX”, “%QX”, “%MX”, “%DBX” #define DOUBLE_BYTE_TYPES “%MD”, “%DBD”, “%DBW”, “%DB” #define BIT_ADDR_TYPES “%MX”, “%DBX” #define SINGLE_BYTE_THRESHOLD 1 // 单字节地址连续阈值 #define DOUBLE_BYTE_THRESHOLD 2 // 双字节地址连续阈值 /* 寄存器类型枚举 / typedef enum { REG_V, / V寄存器 / REG_IX, / IX寄存器 / REG_QX, / QX寄存器 / REG_MX, / MX寄存器 / REG_MW, / MW寄存器 / REG_MD, / MD寄存器 / REG_DBX, / DBX寄存器 / REG_DBW, / DBW寄存器 / REG_DBD, / DBD寄存器 / REG_DB, / DB寄存器 / REG_UNKNOWN / 未知类型 */ } RegType; /* 寄存器类型属性 */ typedef struct { RegType type; const char prefix; / 字符串前缀 / bool is_bit_addressable; / 是否支持位寻址 / int byte_size; / 字节大小(2或4) */ } RegTypeInfo; /* 地址解析结果 / typedef struct { RegType type; / 寄存器类型 / int base_addr; / 基地址 / int bit_offset; / 位偏移 (-1表示无位偏移) */ } AddrParseResult; /* 定义参数位置信息结构体 */ typedef struct { DEVICEID_PARAID *param; // 参数指针 int device_index; // 设备在DeviceNumber数组中的索引 int data_index; // 设备数据在DeviceData数组中的索引 int param_index; // 参数在DeviceParaID数组中的索引 } ParamLocation; /* 地址分组结构 / typedef struct AddrGroup { RegType type; / 寄存器类型 / int slave_addr; / 从机地址 / int portfd; / 使用的485端口 / int start_addr; / 起始地址 / int end_addr; / 结束地址 / int param_count; / 包含的参数数量 */ DEVICEID_PARAID *params; / 动态参数指针数组 */ int bit_offsets; / 位偏移数组 */ struct AddrGroup next; / 链表指针 */ } AddrGroup; // 全局地址组链表头 AddrGroup *addr_groups_head; void init_addr_groups(DEVICE_PARA *device_para, DEVICE_ARGV *device_argv); void print_addr_groups(); /* 获取寄存器类型信息 */ const RegTypeInfo *get_reg_type_info(RegType type); void perform_collection(uint8_t *read_buffer, AddrGroup *group, const RegTypeInfo *info, int bytes_read); /* 寄存器类型信息表 / static const RegTypeInfo reg_type_info[] = { {REG_V, “%V”, false, 2}, {REG_IX, “%IX”, false, 2}, {REG_QX, “%QX”, false, 2}, {REG_MX, “%MX”, true, 2}, / 虽然支持位寻址,但byte_size为2 / {REG_MW, “%MW”, false, 2}, {REG_MD, “%MD”, false, 4}, {REG_DBX, “%DBX”, true, 2}, / 虽然支持位寻址,但byte_size为2 */ {REG_DBW, “%DBW”, false, 2}, {REG_DBD, “%DBD”, false, 4}, {REG_DB, “%DB”, false, 2}, {REG_UNKNOWN, “”, false, 0}}; /* 获取寄存器类型信息 */ const RegTypeInfo get_reg_type_info(RegType type) { size_t i; for (i = 0; i < sizeof(reg_type_info) / sizeof(reg_type_info[0]); i++) { if (reg_type_info[i].type == type) { return &reg_type_info[i]; } } return &reg_type_info[sizeof(reg_type_info) / sizeof(reg_type_info[0]) - 1]; / 返回UNKNOWN */ } /* 解析地址(支持位偏移) */ AddrParseResult parse_address(const char *reg_addr) { int i = 0; AddrParseResult result = {REG_UNKNOWN, -1, -1}; const RegTypeInfo *info; // 提取寄存器类型和数值地址 char type_str[10] = {0}; int addr_value = 0; int bit_offset = -1; // 解析地址字符串 if (sscanf(reg_addr, “%40-9%d.%d”, type_str, &addr_value, &bit_offset) >= 2 || sscanf(reg_addr, “%40-9%d”, type_str, &addr_value) >= 1) { // 转换为大写以便比较 for (i = 0; type_str[i]; i++) { type_str[i] = toupper(type_str[i]); } /* 确定寄存器类型 */ if (strcmp(type_str, “%V”) == 0) result.type = REG_V; else if (strcmp(type_str, “%IX”) == 0) result.type = REG_IX; else if (strcmp(type_str, “%QX”) == 0) result.type = REG_QX; else if (strcmp(type_str, “%MX”) == 0) result.type = REG_MX; else if (strcmp(type_str, “%MW”) == 0) result.type = REG_MW; else if (strcmp(type_str, “%MD”) == 0) result.type = REG_MD; else if (strcmp(type_str, “%DBX”) == 0) result.type = REG_DBX; else if (strcmp(type_str, “%DBW”) == 0) result.type = REG_DBW; else if (strcmp(type_str, “%DBD”) == 0) result.type = REG_DBD; else if (strcmp(type_str, “%DB”) == 0) result.type = REG_DB; else result.type = REG_UNKNOWN; result.base_addr = addr_value; result.bit_offset = bit_offset; } return result; } /* 获取从机地址 */ int get_slave_addr(DEVICE_NUMBER *dev_num) { return dev_num->Number; } /* 获取端口fd */ int get_portfd(int device_index, DEVICE_ARGV *device_argv) { int i; for (i = 0; i < device_argv->Device_num; i++) { if (device_argv->DeviceArgvList[i].DeviceNumber_s[device_index] == ‘1’) { return device_argv->DeviceArgvList[i].portfd; } } return -1; } /* 创建新的地址分组 */ AddrGroup *create_addr_group(RegType type, int slave_addr, int portfd, int base_addr) { AddrGroup *new_group = (AddrGroup *)malloc(sizeof(AddrGroup)); if (!new_group) return NULL; new_group->type = type; new_group->slave_addr = slave_addr; new_group->portfd = portfd; new_group->start_addr = base_addr; new_group->end_addr = base_addr; new_group->param_count = 0; new_group->next = NULL; /* 初始化动态数组 */ new_group->params = (DEVICEID_PARAID **)malloc(sizeof(DEVICEID_PARAID *) * 10); new_group->bit_offsets = (int *)malloc(sizeof(int) * 10); if (!new_group->params || !new_group->bit_offsets) { free(new_group->params); free(new_group->bit_offsets); free(new_group); return NULL; } return new_group; } /* 向地址组添加参数 */ bool add_param_to_group(AddrGroup *group, DEVICEID_PARAID param, int bit_offset) { / 检查是否需要扩展数组 */ if (group->param_count % 10 == 0) { size_t new_size = (group->param_count + 10) * sizeof(DEVICEID_PARAID *); DEVICEID_PARAID **new_params = (DEVICEID_PARAID **)realloc( group->params, new_size); if (!new_params) return false; group->params = new_params; int *new_offsets = (int )realloc( group->bit_offsets, (group->param_count + 10) * sizeof(int)); if (!new_offsets) return false; group->bit_offsets = new_offsets; } / 添加参数 */ group->params[group->param_count] = param; group->bit_offsets[group->param_count] = bit_offset; group->param_count++; return true; } /* 查找匹配的地址分组 */ AddrGroup *find_matching_group(RegType type, int slave_addr, int portfd, int base_addr) { AddrGroup *current = addr_groups_head; const RegTypeInfo *info = get_reg_type_info(type); int threshold; int min_next; while (current != NULL) { if (current->type == type && current->slave_addr == slave_addr && current->portfd == portfd) { /* 检查地址连续性 (考虑阈值) / threshold = info->byte_size / 2; / 使用字节大小计算阈值 */ min_next = current->end_addr + threshold; if (base_addr >= current->start_addr && base_addr <= min_next) { return current; } } current = current->next; } return NULL; } /* 参数排序比较函数 */ int compare_params(const void *a, const void *b) { const ParamLocation *pa = (const ParamLocation *)a; const ParamLocation *pb = (const ParamLocation *)b; AddrParseResult res_a = parse_address(pa->param->RegAddress); AddrParseResult res_b = parse_address(pb->param->RegAddress); // 先按类型排序 if (res_a.type != res_b.type) return res_a.type - res_b.type; // 相同类型按基地址排序 return res_a.base_addr - res_b.base_addr; } /* 初始化地址分组 */ void init_addr_groups(DEVICE_PARA *device_para, DEVICE_ARGV *device_argv) { int i = 0; int t1, t2, t3; AddrGroup *current; AddrGroup *next; DEVICE_NUMBER *dev_num; DEVICE_DATA *dev_data; DEVICEID_PARAID *param; AddrParseResult parsed; AddrGroup *group; int slave_addr; int portfd; /* 清空现有分组 / current = addr_groups_head; while (current != NULL) { next = current->next; free(current->params); free(current->bit_offsets); free(current); current = next; } addr_groups_head = NULL; / 第一步:收集所有参数位置信息 */ int total_params = 0; for (t1 = 0; t1 < device_para->DeviceNumberIndex; t1++) { dev_num = &device_para->DeviceNumber[t1]; for (t2 = 0; t2 < dev_num->DeviceDataIndex; t2++) { dev_data = &dev_num->DeviceData[t2]; total_params += dev_data->DeviceIdIndex; } } if (total_params == 0) return; // 创建参数位置数组 ParamLocation *param_locations = (ParamLocation )malloc(total_params * sizeof(ParamLocation)); if (!param_locations) return; int index = 0; for (t1 = 0; t1 < device_para->DeviceNumberIndex; t1++) { dev_num = &device_para->DeviceNumber[t1]; for (t2 = 0; t2 < dev_num->DeviceDataIndex; t2++) { dev_data = &dev_num->DeviceData[t2]; for (t3 = 0; t3 < dev_data->DeviceIdIndex; t3++) { param_locations[index].param = &dev_data->DeviceParaID[t3]; param_locations[index].device_index = t1; param_locations[index].data_index = t2; param_locations[index].param_index = t3; index++; } } } / 第二步:按类型和基地址排序 / qsort(param_locations, total_params, sizeof(ParamLocation), compare_params); / 第三步:处理排序后的参数 / for (i = 0; i < total_params; i++) { param = param_locations[i].param; parsed = parse_address(param->RegAddress); if (parsed.base_addr < 0 || parsed.type == REG_UNKNOWN) continue; // 直接从位置信息获取设备索引 t1 = param_locations[i].device_index; dev_num = &device_para->DeviceNumber[t1]; slave_addr = get_slave_addr(dev_num); portfd = get_portfd(t1, device_argv); if (portfd == -1) continue; / 查找匹配的分组 / group = find_matching_group(parsed.type, slave_addr, portfd, parsed.base_addr); if (group) { / 更新地址范围 / if (parsed.base_addr < group->start_addr) { group->start_addr = parsed.base_addr; } if (parsed.base_addr > group->end_addr) { group->end_addr = parsed.base_addr; } / 添加参数到组 / if (!add_param_to_group(group, param, parsed.bit_offset)) { printf(“Failed to add param to group!\n”); } } else { / 创建新分组 */ AddrGroup new_group = create_addr_group(parsed.type, slave_addr, portfd, parsed.base_addr); if (!new_group) { printf(“Failed to create new group!\n”); continue; } / 添加到链表 / if (!addr_groups_head) { addr_groups_head = new_group; } else { new_group->next = addr_groups_head; addr_groups_head = new_group; } / 添加第一个参数 */ if (!add_param_to_group(new_group, param, parsed.bit_offset)) { printf(“Failed to add param to new group!\n”); } } } free(param_locations); } /* 从位偏移中提取位值 */ uint8_t extract_bit_value(uint8_t byte_value, int bit_offset) { if (bit_offset < 0 || bit_offset > 7) return 0; return (byte_value >> bit_offset) & 0x01; } /* 执行采集 */ void perform_collection(uint8_t *read_buffer, AddrGroup *group, const RegTypeInfo *info, int bytes_read) { int i; DEVICEID_PARAID *param; int bit_offset; AddrParseResult parsed; int addr_offset; int buffer_offset; int bytes_to_copy; uint8_t byte_value; uint8_t bit_value; /* 处理每个参数 / for (i = 0; i < group->param_count; i++) { param = group->params[i]; bit_offset = group->bit_offsets[i]; parsed = parse_address(param->RegAddress); / 计算数据在缓冲区中的位置 / addr_offset = parsed.base_addr - group->start_addr; buffer_offset = addr_offset * (info->byte_size / 2); / 2字节为单位 / if (buffer_offset < 0 || buffer_offset >= bytes_read) { printf(“Invalid buffer offset: %d\n”, buffer_offset); continue; } / 处理位访问 / if (bit_offset >= 0) { / 位寻址:数据长度为1字节 / byte_value = read_buffer[buffer_offset]; bit_value = extract_bit_value(byte_value, bit_offset); memset(param->RegByteValue, 0, sizeof(param->RegByteValue)); param->RegByteValue[0] = bit_value; param->RegByteLen = 1; } else { / 非位寻址:使用寄存器类型的byte_size */ bytes_to_copy = info->byte_size; if (buffer_offset + bytes_to_copy > bytes_read) { bytes_to_copy = bytes_read - buffer_offset; } memcpy(param->RegByteValue, read_buffer + buffer_offset, bytes_to_copy); param->RegByteLen = bytes_to_copy; } } } /* 主采集循环 */ void collection_loop(DEVICE_PARA *device_para, DEVICE_ARGV *device_argv) { uint32_t start_time; uint32_t elapsed; AddrGroup *current; int i; /* 初始化分组 / init_addr_groups(device_para, device_argv); print_addr_groups(); / 主循环 / while (1) { / 执行采集 / perform_single_collection(); / 等待下一个采集周期 */ } } /* 打印分组信息 */ void print_addr_groups() { AddrGroup *current = addr_groups_head; int group_num = 0; const RegTypeInfo *info; printf(“\n===== Address Groups =\n"); while (current != NULL) { info = get_reg_type_info(current->type); printf(“Group %d: %s, slave=%d, portfd=%d, addr_range=%d-%d, params=%d\n”, group_num, info->prefix, current->slave_addr, current->portfd, current->start_addr, current->end_addr, current->param_count); current = current->next; group_num++; } printf("======================\n\n”); } // 执行单次采集 void perform_single_collection() { AddrGroup *current = addr_groups_head; uint32_t current_time = get_current_timestamp(); while (current != NULL) { AddrGroup group = current; current = current->next; // 检查是否需要采集 if (current_time - group->last_collection_time < COLLECTION_INTERVAL_MS) { continue; } group->last_collection_time = current_time; group->needs_collection = false; const RegTypeInfo info = get_reg_type_info(group->type); int reg_count = group->end_addr - group->start_addr + 1; // 根据数据类型调整寄存器计数 if (info->is_double_byte) { reg_count = (reg_count + 1) / 2; } if (reg_count > MODBUS_MAX_REGISTERS) { reg_count = MODBUS_MAX_REGISTERS; } // 分配缓冲区 uint8_t read_buffer = (uint8_t)malloc(reg_count * 2); if (!read_buffer) { printf(“Memory allocation failed for read buffer!\n”); continue; } // 执行MODBUS读取 int bytes_read = modbus_read(group->portfd, group->slave_addr, group->start_addr, reg_count, read_buffer); if (bytes_read != reg_count * 2) { printf(“MODBUS read error! Expected %d bytes, got %d\n”, reg_count * 2, bytes_read); free(read_buffer); continue; } // 处理每个参数 for (int i = 0; i < group->param_count; i++) { DEVICEID_PARAID *param = group->params[i]; int bit_offset = group->bit_offsets[i]; AddrParseResult parsed = parse_address(param->RegAddress); // 计算数据在缓冲区中的位置 int addr_offset = parsed.base_addr - group->start_addr; int buffer_offset = addr_offset * (info->is_double_byte ? 2 : 1); if (buffer_offset < 0 || buffer_offset >= bytes_read) { printf(“Invalid buffer offset: %d\n”, buffer_offset); continue; } // 处理位访问 if (bit_offset >= 0) { uint8_t byte_value = read_buffer[buffer_offset]; uint8_t bit_value = extract_bit_value(byte_value, bit_offset); memset(param->RegByteValue, 0, sizeof(param->RegByteValue)); param->RegByteValue[0] = bit_value; } else { int bytes_to_copy = info->byte_size; if (buffer_offset + bytes_to_copy > bytes_read) { bytes_to_copy = bytes_read - buffer_offset; } memcpy(param->RegByteValue, read_buffer + buffer_offset, bytes_to_copy); } param->lastUpdate = current_time; } free(read_buffer); } } // 测试函数 void test_parse_address() { const char *test_addresses[] = { “MX10”, “MX10.3”, “DBD200”, “V123”, “QX55”, “UNKNOWN30” }; printf(“===== Address Parsing Test =\n"); for (int i = 0; i < sizeof(test_addresses)/sizeof(test_addresses[0]); i++) { AddrParseResult result = parse_address(test_addresses[i]); const RegTypeInfo* info = get_reg_type_info(result.type); printf(“Address: %s\n”, test_addresses[i]); printf(" Type: %s (%d)\n", info->prefix, result.type); printf(" Base: %d\n", result.base_addr); printf(" Bit offset: %d\n", result.bit_offset); printf(" Byte size: %d\n", info->byte_size); printf(" Bit addressable: %s\n", info->is_bit_addressable ? “yes” : “no”); printf(" Double byte: %s\n\n", info->is_double_byte ? “yes” : “no”); } printf("===========================\n\n”); } int main() { // 运行地址解析测试 test_parse_address(); // 初始化设备参数和采集参数 DEVICE_PARA device_para = {0}; DEVICE_ARGV device_argv = {0}; // 设置示例数据 device_para.DeviceNumberIndex = 2; device_para.DeviceNumber = (DEVICE_NUMBER*)malloc(2 * sizeof(DEVICE_NUMBER)); memset(device_para.DeviceNumber, 0, 2 * sizeof(DEVICE_NUMBER)); // 设备1 (包含位访问) device_para.DeviceNumber[0].Number = 1; device_para.DeviceNumber[0].DeviceDataIndex = 1; device_para.DeviceNumber[0].DeviceData = (DEVICE_DATA*)malloc(sizeof(DEVICE_DATA)); memset(device_para.DeviceNumber[0].DeviceData, 0, sizeof(DEVICE_DATA)); device_para.DeviceNumber[0].DeviceData->DeviceIdIndex = 3; device_para.DeviceNumber[0].DeviceData->DeviceParaID = (DEVICEID_PARAID*)malloc(3 * sizeof(DEVICEID_PARAID)); strcpy(device_para.DeviceNumber[0].DeviceData->DeviceParaID[0].RegAddress, “MX10”); device_para.DeviceNumber[0].DeviceData->DeviceParaID[0].ParaId = 101; strcpy(device_para.DeviceNumber[0].DeviceData->DeviceParaID[1].RegAddress, “MX10.3”); device_para.DeviceNumber[0].DeviceData->DeviceParaID[1].ParaId = 102; strcpy(device_para.DeviceNumber[0].DeviceData->DeviceParaID[2].RegAddress, “MD20”); device_para.DeviceNumber[0].DeviceData->DeviceParaID[2].ParaId = 103; // 设备2 (双字节类型) device_para.DeviceNumber[1].Number = 2; device_para.DeviceNumber[1].DeviceDataIndex = 1; device_para.DeviceNumber[1].DeviceData = (DEVICE_DATA*)malloc(sizeof(DEVICE_DATA)); memset(device_para.DeviceNumber[1].DeviceData, 0, sizeof(DEVICE_DATA)); device_para.DeviceNumber[1].DeviceData->DeviceIdIndex = 2; device_para.DeviceNumber[1].DeviceData->DeviceParaID = (DEVICEID_PARAID*)malloc(2 * sizeof(DEVICEID_PARAID)); strcpy(device_para.DeviceNumber[1].DeviceData->DeviceParaID[0].RegAddress, “DBD200”); device_para.DeviceNumber[1].DeviceData->DeviceParaID[0].ParaId = 201; strcpy(device_para.DeviceNumber[1].DeviceData->DeviceParaID[1].RegAddress, “DBX55”); device_para.DeviceNumber[1].DeviceData->DeviceParaID[1].ParaId = 202; // 设置采集参数 device_argv.Device_num = 2; device_argv.DeviceArgvList[0].portfd = 1; strcpy(device_argv.DeviceArgvList[0].DeviceNumber_s, “10”); device_argv.DeviceArgvList[1].portfd = 2; strcpy(device_argv.DeviceArgvList[1].DeviceNumber_s, “01”); // 进入采集循环 collection_loop(&device_para, &device_argv); // 释放资源 cleanup(&device_para); return 0; } 采用的是MODBUS采集,还须区分采集的从机地址相同,地址连续的才能合并在一起一次采集,从机地址是DevicePara_t->DeviceNumber[t1].Number决定 ,并且我有两个RS485接口及两个fd,可以随意确定使用那个485采集也用DevicePara_t->DeviceNumber[t1].Number判断决定吧 也不一定是奇数用4851偶数用4852,有可能全用一个485采集 采集寄存器个数和返回值长度关系是:个数*2=长度 这里有以下改动:首先地址分组规则需要改动,首先还是fd优于从机地址优于地址大小排序,然后对地址分组,首先在初始化函数会加一个参数用于区分西门子还是施耐德,还有RegType有变动,现在为QX BDX M MB MW BDW VW DBD MD IX MX ,其中当参数表示西门子时IX MX 和QX分在一组,功能码标志为1 ,表示为施莱德时IX MX 和DBX M分在一组功能码标志为2,剩下其他的功能码都标志为3,但是其中DBD和MD byte_size字节大小为4,采集个数为2,地址连续判断为2,其余的都是字节大小为2,采集个数为1,地址连续判断为1,还希望有些地址中间不连续但相差很小可以分在一组一次采集, 因为在功能码03中采集个数不一致,所以在最后放在原来结构体时需要注意偏移量,依旧支持有些寄存器的位寻址,有些在同一组内地址是相同,计算采集个数时需要注意,fro循环内不能定义变量,也不需要间隔时间,请生成完整C语言代码,不能是伪代码
07-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值