QNX开发的cJson和XML拓展功能使用

本文介绍了cJSON库的基本使用方法,包括如何解析JSON数据包获取特定字段的值,以及如何组装JSON数据包用于数据传输。

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

锋影

e-mail:174176320@qq.com


希望在qnx平台上使用cJson和xml,最基本的方法就是自己移植。

移植过程中,注意开发的方式要兼容qnx的微内核模式开发,

进程与进程之间的通信进过ipc处理。

编译好解析库,封装好库文件,即可使用。


1.JSON格式简述

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。(来自“开源中国”资料)
cJSON是一个超轻巧,携带方便,单文件,简单的可以作为ANSI-C标准的JSON解析器。
接触yeelink平台之后,慢慢接触到JSON格式,虽然一些简单的情况可以通过string库函数解析和组装JSON数据包,但是若有cJSON库的帮助,解析和组装JSON数据包的工作便会变得简单的多,下面就从两个例子出发说明cJSON数据包的使用方法。

2.JSON结构体

熟悉使用cJSON库函数可从cJSON结构体入手,cJSON结构体如下所示:
  1. typedef struct cJSON { 
  2. struct cJSON *next,*prev;  
  3. struct cJSON *child;  
  4. int type;  
  5. char *valuestring;  
  6. int valueint; 
  7. double valuedouble;  
  8. char *string;  
  9. } cJSON; 
  1. typedef struct cJSON {  
  2.  struct cJSON *next,*prev;   
  3.  struct cJSON *child;   
  4.  int type;   
  5.  char *valuestring;   
  6.  int valueint;  
  7.  double valuedouble;   
  8.  char *string;   
  9. } cJSON;  

几点说明

1.cJOSN结构体为一个双向列表,并可通过child指针访问下一层。
2.type变量决定数据项类型(键的类型),数据项可以是字符串可以是整形,也可以是浮点型。如果是整形值的话可从valueint,如果是浮点型的话可从valuedouble取出,以此类推。
3.string可理解为节点的名称,综合此处的第2点可理解为“键”的名称。

3.解析JSON数据包

例如在yeelink平台中读取一个开关量的结果,向yeelink平台请求之后可以获得以下JSON数据包:
{"timestamp":"2013-11-19T08:50:11","value":1}
在这个JSON数据包中有两个数据项(键值对),一个是时间戳,该时间戳为字符串形式;另一个是开关值,该开关值为整型。该例子主要用于模拟向yeelink平台请求开关量数据。

参考代码

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include "cJSON.h" 
  4. // 被解析的JSON数据包 
  5. char text[] = "{\"timestamp\":\"2013-11-19T08:50:11\",\"value\":1}"
  6. int main (int argc,const char * argv[]) 
  7.     cJSON *json , *json_value , *json_timestamp; 
  8.     // 解析数据包 
  9.     json = cJSON_Parse(text); 
  10.     if (!json) 
  11.     { 
  12.         printf("Error before: [%s]\n",cJSON_GetErrorPtr()); 
  13.     } 
  14.     else 
  15.     { 
  16.         // 解析开关值 
  17.         json_value = cJSON_GetObjectItem( json , "value"); 
  18.         if( json_value->type == cJSON_Number ) 
  19.         { 
  20.             // 从valueint中获得结果 
  21.             printf("value:%d\r\n",json_value->valueint); 
  22.         } 
  23.         // 解析时间戳 
  24.         json_timestamp = cJSON_GetObjectItem( json , "timestamp"); 
  25.         if( json_timestamp->type == cJSON_String ) 
  26.         { 
  27.             // valuestring中获得结果 
  28.             printf("%s\r\n",json_timestamp->valuestring); 
  29.         } 
  30.         // 释放内存空间 
  31.         cJSON_Delete(json); 
  32.     } 
  33.     return 0; 
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include "cJSON.h"  
  4. // 被解析的JSON数据包  
  5. char text[] = "{\"timestamp\":\"2013-11-19T08:50:11\",\"value\":1}";  
  6. int main (int argc, const char * argv[])  
  7. {  
  8.     cJSON *json , *json_value , *json_timestamp;  
  9.     // 解析数据包  
  10.     json = cJSON_Parse(text);  
  11.     if (!json)  
  12.     {  
  13.         printf("Error before: [%s]\n",cJSON_GetErrorPtr());  
  14.     }  
  15.     else  
  16.     {  
  17.         // 解析开关值  
  18.         json_value = cJSON_GetObjectItem( json , "value");  
  19.         if( json_value->type == cJSON_Number )  
  20.         {  
  21.             // 从valueint中获得结果  
  22.             printf("value:%d\r\n",json_value->valueint);  
  23.         }  
  24.         // 解析时间戳  
  25.         json_timestamp = cJSON_GetObjectItem( json , "timestamp");  
  26.         if( json_timestamp->type == cJSON_String )  
  27.         {  
  28.             // valuestring中获得结果  
  29.             printf("%s\r\n",json_timestamp->valuestring);  
  30.         }  
  31.         // 释放内存空间  
  32.         cJSON_Delete(json);  
  33.     }  
  34.     return 0;  
  35. }  

运行结果

value:1
2013-11-19T08:50:11

若干说明

1.cJSON_Parse函数负责解析JSON数据包,并按照cJSON结构体的结构序列化整个数据包。使用该函数会通过malloc函数在内存中开辟一个空间,使用完成需要手动释放。
2.cJSON_GetObjectItem函数可从cJSON结构体中查找某个子节点名称(键名称),如果查找成功可把该子节点序列化到cJSON结构体中。
3.如果需要使用cJSON结构体中的内容,可通过cJSON结构体中的valueint和valuestring取出有价值的内容(即键的值)
4.可通过cJSON_Delete释放内存空间。

4.组装JSON数据包

组装数据包的过程和解析数据包的过程相反,下面的例子描述如何组装以下数据包,该数据包只有一个数据项(键值对)。该例子主要用于模拟向yeelink平台上传传感器数据。
{
"value": 123.400000
}

参考代码

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include "cJSON.h" 
  4. int main (int argc,const char * argv[]) 
  5.     // 创建JSON Object 
  6.     cJSON *root = cJSON_CreateObject(); 
  7.     // 加入节点(键值对),节点名称为value,节点值为123.4 
  8.     cJSON_AddNumberToObject(root,"value",123.4); 
  9.     // 打印JSON数据包 
  10.     char *out = cJSON_Print(root); 
  11.     printf("%s\n",out); 
  12.     // 释放内存 
  13.     cJSON_Delete(root); 
  14.     free(out); 
  15.     return 0; 
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include "cJSON.h"  
  4. int main (int argc, const char * argv[])  
  5. {  
  6.     // 创建JSON Object  
  7.     cJSON *root = cJSON_CreateObject();  
  8.     // 加入节点(键值对),节点名称为value,节点值为123.4  
  9.     cJSON_AddNumberToObject(root,"value",123.4);  
  10.     // 打印JSON数据包  
  11.     char *out = cJSON_Print(root);  
  12.     printf("%s\n",out);  
  13.     // 释放内存  
  14.     cJSON_Delete(root);  
  15.     free(out);  
  16.     return 0;  
  17. }  

若干说明

1. cJSON_CreateObject函数可创建一个根数据项,之后便可向该根数据项中添加string或int等内容
2. cJSON_AddNumberToObject向节点中添加子节点,例如此处添加value节点,节点值为123.4
3. cJSON_Print函数可以打印根数据项,加入制表符换行符等标识符使得JSON数据包更易阅读
4. 使用free函数释放被out占用的内存空间

5.总结

整体来说cJSON简单易用,解决了JSON数据包解析和组装的问题,向着心中的目标更近一步了。

原文:
http://blog.youkuaiyun.com/cindy_cheng/article/details/50469542

<think>我们正在讨论QNX中的qdss_serviceDMA使用。用户的问题集中在两个部分:qdss_serviceDMA(直接内存访问)。首先回顾一下,qdss_service是用于系统诊断跟踪的服务,而DMA是一种在不占用CPU的情况下进行数据传送的技术。在QNX中,DMA通常通过设备驱动硬件抽象层(HAL)来管理。由于用户提到了参考站内引用[1],其中提到了SA8255一些进程,但并没有直接关于qdss_serviceDMA的详细内容。因此,我们主要依靠QNX的一般知识来回答。回答结构:1.介绍qdss_serviceDMA的基本概念。2.分别详细说明qdss_service的使用方法(包括配置、启动、数据捕获等)。3.说明在QNX中如何使用DMA(包括驱动程序、应用程序接口等)。4.可能结合两者的情况(例如,使用DMA来传输qdss跟踪数据)。5.常见问题及解决方法。6.生成相关问题。注意:由于QNX的文档不是完全公开的,部分内容可能基于一般知识,并标注可能的依赖。开始回答:在QNX开发中,`qdss_service`DMA(直接内存访问)是两种不同的技术,分别用于系统跟踪调试高性能数据传输。下面将分别介绍它们的使用方法。###一、`qdss_service`的使用`qdss_service`是QualcommTraceandSystemDiagnostics服务的守护进程,用于收集芯片级的调试跟踪信息(如CoreSightETM数据)。以下是基本使用步骤:1.**启动服务**:```bashqdss_service&#在后台启动服务```服务启动后会在`/dev/qdss`目录下创建设备节点,如`/dev/qdss/trace`、`/dev/qdss/config`等。2.**配置跟踪参数**:通过写入`/dev/qdss/config`设备节点来配置跟踪参数,例如:```bashecho"ETM_ENABLE=1,OUTPUT_FILE=/data/qdss_trace.bin">/dev/qdss/config```这里启用了ETM(EmbeddedTraceMacrocell)跟踪,并设置输出文件路径。3.**控制跟踪**:使用`/dev/qdss/control`节点来控制跟踪的开始停止:```bashecho"START_CAPTURE">/dev/qdss/control#开始捕获#...执行要跟踪的操作...echo"STOP_CAPTURE">/dev/qdss/control#停止捕获```4.**读取跟踪数据**:跟踪数据会写入到指定的文件(如`/data/qdss_trace.bin`),可以使用`qdss_parser`工具解析:```bashqdss_parser-i/data/qdss_trace.bin-oparsed_output.txt```5.**权限要求**:`qdss_service`需要特定的权限(如`PROCMGR_AID_QDSS`)来操作设备文件系统,需要在安全策略中配置[^1]。###二、DMA的使用QNX中,DMA操作通常由设备驱动程序管理,应用程序通过设备驱动提供的接口进行DMA传输。以下是常见的两种方式:####方式1:使用字符设备驱动进行DMA许多设备驱动(如PCIe、串口等)内部使用DMA,应用程序只需要通过`read()`,`write()`或`ioctl()`进行数据传输。例如:```cintfd=open("/dev/some_device",O_RDWR);if(fd<0){perror("open");return-1;}//通过write触发DMA传输constchar*data="Hello,DMA!";ssize_tret=write(fd,data,strlen(data));//检查ret...close(fd);```####方式2:直接操作DMA控制器(高级)对于需要直接控制DMA控制器的场景(如自定义外设),需要:1.**映射物理内存**:使用`mmap_device_memory()`将DMA缓冲区映射到用户空间:```cvoid*dma_buffer=mmap_device_memory(NULL,BUFFER_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,PHYS_ADDR_OF_BUFFER);```其中`PHYS_ADDR_OF_BUFFER`是物理连续的DMA缓冲区地址(通常通过`mem_offset`或共享内存分配器获得)。2.**配置DMA控制器**:通过`ioctl()`或寄存器操作配置DMA通道、传输方向等(需要权限):```cioctl(dma_controller_fd,DMA_SET_CONFIG,&dma_config);```3.**启动传输**:启动DMA传输后,使用中断或轮询等待传输完成:```cioctl(dma_controller_fd,DMA_START,&transfer);```4.**释放资源**:完成后解除映射关闭设备:```cmunmap_device_memory(dma_buffer,BUFFER_SIZE);```###三、`qdss_service`DMA的结合使用在`qdss_service`中,跟踪数据的高效传输可能使用DMA(如通过PCIe或系统总线)。但是,这通常由内核驱动内部处理,对开发者透明。开发者只需正常操作`qdss_service`的设备节点。###四、常见问题与解决-**`qdss_service`无法启动**:检查安全策略、设备树配置(若需要)BSP是否支持QTID[^1]。-**DMA传输失败**:检查缓冲区物理连续性、设备权限中断配置(使用`dumper`查看内核日志)[^1]。-**权限问题**:为服务添加`PROCMGR_AID_DEVICE`权限以访问硬件设备[^1]。§§相关问题§§1.QNX中如何为DMA缓冲区申请物理连续的内存?2.如何调试`qdss_service`产生的跟踪数据?3.`qdss_service`在安全启动(secureboot)环境下的配置限制?4.QNX的DMA传输错误处理机制是怎样的?5.如何优化`qdss_service`的实时性能?---以上回答基于QNX的一般开发实践。具体平台(如SA8255)请参考对应BSP文档[^1]。</think> ### QNX 开发中 `qdss_service` 与 DMA 的使用详解 #### **一、`qdss_service` 的使用方法** `qdss_service` 是 Qualcomm Trace and System Diagnostics (QTID) 的核心服务,用于系统级调试跟踪。以下是关键步骤: 1. **启动与配置服务** ```bash qdss_service & # 后台启动服务 echo "ETM_ENABLE=1,OUTPUT_FILE=/data/qdss.bin" > /dev/qdss/config # 配置跟踪参数 ``` - 配置参数说明: - `ETM_ENABLE=1`:启用 CoreSight ETM 跟踪 - `OUTPUT_FILE`:指定跟踪数据输出路径[^1] 2. **控制跟踪过程** ```bash echo "START_CAPTURE" > /dev/qdss/control # 开始捕获 # 执行待测程序... echo "STOP_CAPTURE" > /dev/qdss/control # 停止捕获 ``` 3. **解析跟踪数据** ```bash qdss_parser -i /data/qdss.bin -o report.txt # 解析为可读报告 ``` 解析后的数据包含: - 函数调用栈 - CPU 占用率分布 - 硬件事件计数(如缓存命中率) #### **二、DMA (直接内存访问) 使用方法** 在 QNX 中进行 DMA 操作需通过设备驱动实现: 1. **DMA 缓冲区分配** ```c #include <sys/mman.h> void* dma_buf = mmap_device_io(DMA_BUF_SIZE, PHYS_ADDR); // 映射物理内存 ``` - 要求:内存需物理连续,通过`mem_offset()`获取物理地址[^1] 2. **配置 DMA 控制器** ```c int dma_fd = open("/dev/dma0", O_RDWR); // 打开DMA设备 ioctl(dma_fd, DMA_SET_SRC_ADDR, src_phys_addr); // 设置源地址 ioctl(dma_fd, DMA_SET_DST_ADDR, dst_phys_addr); // 设置目标地址 ioctl(dma_fd, DMA_SET_COUNT, data_size); // 设置传输长度 ``` 3. **启动传输与同步** ```c ioctl(dma_fd, DMA_START); // 触发DMA传输 sigwait(&dma_sigset, &info); // 等待传输完成信号 ``` #### **三、`qdss_service` 与 DMA 的协同使用** 可将 DMA 传输事件整合到跟踪数据中: ```c // DMA启动前标记 trace_mark(TRACE_USER, "DMA_START", "size=%d", data_size); // DMA完成后标记 trace_mark(TRACE_USER, "DMA_COMPLETE"); ``` 在 `qdss.bin` 解析报告中会显示: ``` [0.125ms] DMA_START size=4096 [0.138ms] DMA_COMPLETE ``` #### **四、关键问题解决方案** | 问题现象 | 原因 | 解决方案 | |---------|------|----------| | DMA传输超时 | 内存未对齐 | 分配内存时使用`memalign(64, size)`保证64字节对齐 | | `qdss.bin`数据不完整 | 跟踪缓冲区溢出 | 增大配置:`echo "BUFFER_SIZE=2M" > /dev/qdss/config` | | DMA设备访问拒绝 | 权限不足 | 在secpol中授权:`allow: /dev/dma0 rw`[^1] | #### **五、优化建议** 1. **实时性优化** 通过`qon`提升优先级: ```bash qon -P 10 qdss_service # 优先级10 (0-31) ``` 2. **DMA 性能优化** 使用双缓冲减少等待: $$T_{\text{total}} = \frac{n}{b} \times t_{\text{cycle}} + \Delta t_{\text{setup}}$$ 其中 $b$ 为突发传输长度,$t_{\text{cycle}}$ 为周期时间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值