当前位置: 首页 > article >正文

Arduino_ConnectionHandler库:嵌入式网络连接状态管理与自适应重连

1. Arduino_ConnectionHandler 库深度解析嵌入式网络连接管理的工程实践指南1.1 库定位与核心价值Arduino_ConnectionHandler是 Arduino 官方生态中面向物联网终端设备的网络连接抽象管理层其设计目标并非替代底层通信协议栈如 WiFiClient、GSMClient而是解决嵌入式系统在真实工业/消费场景中普遍存在的连接脆弱性问题。该库最初作为ArduinoIoTCloud的核心依赖模块开发后独立为通用组件体现了从“功能可用”到“工程可靠”的演进路径。在资源受限的 MCU 环境下网络连接失败是常态而非例外WiFi 信号衰减、蜂窝基站切换、LoRa 网关离线、以太网物理断开、Notecard 模块休眠唤醒延迟等均会导致 TCP 连接中断。传统做法是在应用层轮询client.connected()并手动重连但存在三大缺陷状态耦合严重业务逻辑需感知网络状态违反单一职责原则重连策略粗糙固定延时重试无法适应不同网络介质的恢复特性如 NB-IoT 注册耗时可达 30 秒而 WiFi 重连通常 2 秒事件通知缺失无法在连接建立瞬间触发初始化动作如 MQTT 订阅、HTTP 首次上报或在断开时执行安全清理如关闭传感器采样任务。ConnectionHandler通过分层抽象 事件驱动 自适应重连三重机制将网络连接管理从“应用代码负担”转化为“可配置基础设施”。其本质是一个运行于loop()中的轻量级状态机引擎不依赖 RTOS仅需约 1.2KB Flash 和 256B RAM以 STM32F401RE 为例适用于所有 Arduino 兼容平台。1.2 支持的硬件平台与协议栈映射该库通过预编译宏识别硬件能力自动绑定对应协议栈实现。其支持矩阵覆盖了当前主流物联网通信模组关键映射关系如下表所示硬件平台标识宏对应硬件型号示例底层协议栈实现典型应用场景BOARD_HAS_WIFIMKR WiFi 1010, Nano 33 IoT, Portenta H7, UNO R4 WiFi, ESP32, ESP8266Arduino WiFiNINA / ESP-IDF室内局域网、AP 模式热点接入BOARD_HAS_GSMMKR GSM 1400Arduino MKRGSM广域移动网络、短信收发BOARD_HAS_NBMKR NB 1500Arduino MKRNB低功耗广域网NB-IoT、远程抄表BOARD_HAS_LORAMKR WAN 1300/1310Arduino LoRa超远距离低速率传输、农业传感网BOARD_HAS_ETHERNETPortenta H7 Vision Shield Ethernet, OPTA RS485, Portenta C33 Vision ShieldArduino Ethernet2 / W5500工业现场总线、高可靠性有线连接BOARD_HAS_NOTECARD任意搭载 Notecard 模块的主控板通过 I2C/UART 接入Notehub SDK卫星/蜂窝/LoRa 多模冗余通信工程提示BOARD_HAS_NOTECARD是唯一不绑定特定 MCU 的选项其设计哲学是“通信模组即服务”。Notecard 本身集成 eSIM、LoRaWAN 栈、卫星调制解调器及边缘计算能力主控 MCU 仅需通过串口发送 JSON 命令即可完成复杂网络操作极大降低主控侧固件开发复杂度。此模式特别适合需要快速部署多地域、多网络制式的项目。1.3 架构设计原理状态机与事件回调机制ConnectionHandler的核心是一个三态有限状态机FSM其状态转换严格遵循网络连接生命周期stateDiagram-v2 [*] -- DISCONNECTED DISCONNECTED -- CONNECTING: conMan.begin() 或自动重连触发 CONNECTING -- CONNECTED: 底层协议栈返回 success CONNECTING -- DISCONNECTED: 连接超时/认证失败 CONNECTED -- DISCONNECTED: 底层检测到链路中断如 socket close CONNECTED -- CONNECTED: keep-alive 心跳成功 DISCONNECTED -- CONNECTING: 自动重连定时器到期该状态机通过conMan.check()函数驱动其内部逻辑可分解为三个关键阶段状态检查State Check调用底层协议栈的connected()方法如WiFiClient.connected()若返回false则触发断开事件并进入重连流程。保活探测Keep-Alive Probe在CONNECTED状态下周期性发送轻量级探测包如 TCP ACK、HTTP HEAD 请求、Notecardhub.sync命令。探测间隔由setKeepAliveInterval()配置默认 30 秒。若连续N次探测失败N可配置则判定连接失效。自适应重连Adaptive Reconnect采用指数退避算法Exponential Backoff首次重连延时T01s失败后延时T12*T0依此类推直至Tmax300s5 分钟。此设计避免在网络拥塞时加剧信道竞争符合 RFC 5681 规范。事件回调机制通过addCallback()注册其设计遵循嵌入式实时系统最佳实践零内存分配回调函数指针在setup()中静态注册运行时不涉及malloc/free无阻塞设计回调函数内禁止调用delay()、Serial.println()除非确认串口缓冲区未满等可能阻塞的 API上下文隔离回调执行期间check()主循环被挂起确保状态机一致性。1.4 关键 API 详解与参数工程化配置1.4.1 连接管理器实例化实例化方式严格依赖硬件宏体现编译期多态思想// WiFi 场景需提供 SSID 和密码明文存储生产环境建议使用 Secure Element #if defined(BOARD_HAS_WIFI) WiFiConnectionHandler conMan(MyHomeWiFi, SecurePass123); #endif // GSM 场景PIN 码、APN、用户名/密码构成完整接入点配置 #if defined(BOARD_HAS_GSM) GSMConnectionHandler conMan(1234, internet.mnc001.mcc001.gprs, user, pass); #endif // Notecard 场景productUID 是 Notehub 平台分配的唯一设备标识 #if defined(BOARD_HAS_NOTECARD) NotecardConnectionHandler conMan(com.mycompany.sensors:temperature-sensor-001); #endif参数配置要点APN字符串必须与运营商要求完全一致区分大小写常见错误包括遗漏.gprs后缀或错误 MCC/MNC 编码Notecard 的productUID格式为com.domain:product-name其中domain需在 Notehub 控制台注册product-name由开发者定义所有密钥类参数WiFi 密码、GSM PIN在编译时固化若需动态配置须修改库源码添加setCredentials()方法。1.4.2 核心控制 APIAPI 函数签名参数说明工程用途void begin()无参数启动连接流程首次调用进入CONNECTING状态void check()无参数必须在 loop() 中高频调用建议 ≥ 10Hz驱动状态机运转bool isConnected()无参数返回当前连接状态快照用于条件判断如if(conMan.isConnected()) {...}void setKeepAliveInterval(uint32_t ms)ms: 心跳间隔毫秒数默认 30000根据网络质量调整WiFi 可设为 5000msNB-IoT 建议 ≥ 60000msvoid setReconnectMaxDelay(uint32_t ms)ms: 最大重连延时默认 300000防止无限重试工业场景建议设为 180000030 分钟void addCallback(NetworkConnectionEvent event, void (*callback)())event: 枚举值CONNECTED/DISCONNECTED/ERRORcallback: 无参函数指针注册事件处理器实现状态变化响应1.4.3 事件回调类型与典型处理逻辑// 连接成功回调执行业务初始化 void onNetworkConnect() { Serial.println( CONNECTED to network); // 示例MQTT 客户端连接 mqttClient.connect(device-001); // 示例启动传感器采样任务FreeRTOS 环境 xTaskCreate(vSensorTask, SENSOR, 2048, NULL, 2, NULL); } // 连接断开回调执行安全降级 void onNetworkDisconnect() { Serial.println( DISCONNECTED from network); // 示例停止非必要外设 ledStatus.setBrightness(0); // 熄灭状态指示灯 sensorPower.disable(); // 关闭传感器供电 // 示例切换至本地存储模式 sdCardLogger.startBuffering(); } // 错误回调记录诊断信息 void onNetworkError() { Serial.println( ERROR); // 示例读取底层错误码需扩展库源码 // int errCode conMan.getLastError(); // Serial.printf(Error Code: %d\n, errCode); }关键约束回调函数内禁止调用conMan.check()或任何可能修改连接状态的操作否则引发递归调用导致栈溢出。1.5 源码级实现逻辑剖析以WiFiConnectionHandler为例其核心逻辑位于WiFiConnectionHandler.cpp// 状态检查主干逻辑简化版 void WiFiConnectionHandler::check() { switch (currentState) { case DISCONNECTED: if (millis() - lastAttemptTime reconnectDelay) { attemptConnection(); // 尝试连接 } break; case CONNECTING: if (isConnectionEstablished()) { // 调用 WiFiClient.connected() currentState CONNECTED; lastConnectedTime millis(); triggerCallback(CONNECTED); } else if (millis() - connectionStartTime CONNECT_TIMEOUT_MS) { currentState DISCONNECTED; triggerCallback(ERROR); } break; case CONNECTED: if (millis() - lastKeepAliveTime keepAliveInterval) { if (!sendKeepAliveProbe()) { // 发送 HTTP HEAD 或 TCP ping currentState DISCONNECTED; triggerCallback(DISCONNECTED); } else { lastKeepAliveTime millis(); } } break; } }关键设计细节时间戳管理所有超时判断基于millis()规避delay()导致的精度丢失连接超时保护CONNECT_TIMEOUT_MS默认 15000ms防止 WiFi 扫描卡死保活探针选择WiFi 场景优先使用 TCP 层 ACK 探测低开销HTTP 探测作为备选错误码抽象当前版本未暴露底层错误码如需调试可在attemptConnection()中捕获WiFi.status()返回值如WL_CONNECT_FAILED,WL_NO_SSID_AVAIL并存入私有成员变量。1.6 实战集成与 FreeRTOS 和 HAL 库协同工作在资源更丰富的平台如 Portenta H7常需与 RTOS 协同。以下为 FreeRTOS 集成范例// 创建专用网络管理任务优先级高于应用任务 void vNetworkTask(void *pvParameters) { WiFiConnectionHandler conMan(SSID, PASS); conMan.addCallback(CONNECTED, onNetworkConnect); conMan.addCallback(DISCONNECTED, onNetworkDisconnect); // 初始化后立即开始连接 conMan.begin(); for(;;) { conMan.check(); // 状态机驱动 vTaskDelay(10); // 10ms 周期确保 loop 高频执行 } } // 在 setup() 中创建任务 void setup() { Serial.begin(9600); xTaskCreate(vNetworkTask, NETWORK, 4096, NULL, 3, NULL); vTaskStartScheduler(); }HAL 库集成要点若使用 STM32CubeMX 生成的 HAL 代码需在main.c的while(1)循环中调用conMan.check()注意HAL_UART_Transmit()等阻塞函数会延迟check()执行建议改用HAL_UART_Transmit_IT()中断模式或 DMA 方式对于以太网场景EthernetConnectionHandler依赖Ethernet.h需确保ETH外设在MX_ETH_Init()中正确使能。1.7 常见问题诊断与工程优化策略1.7.1 连接反复震荡Flapping现象日志显示CONNECTED→DISCONNECTED→CONNECTED快速循环。根因分析保活间隔过短网络瞬时抖动被误判为故障底层 WiFi 模块驱动存在 Bug如某些 ESP32 版本的WiFi.disconnect()未彻底释放资源。解决方案// 增加保活间隔并启用连接稳定性计数器 conMan.setKeepAliveInterval(60000); // 60秒 // 需修改库源码添加 minStableTimeMs 成员在 CONNECTED 状态持续 N 秒后才触发回调1.7.2 重连失败后无法恢复现象断开后check()不再尝试重连。排查步骤检查reconnectDelay是否已达reconnectMaxDelay上限验证lastAttemptTime时间戳是否被意外重置使用逻辑分析仪抓取底层 UART/I2C 通信确认模组是否返回ERROR响应。预防措施在onNetworkError()中强制复位模组如digitalWrite(RESET_PIN, LOW)实现看门狗监控若conMan.isConnected()持续 5 分钟为false触发NVIC_SystemReset()。1.7.3 内存泄漏风险风险点addCallback()注册的函数指针若指向栈内存如 lambda 表达式在回调时将访问非法地址。安全写法// ✅ 正确全局函数或 static 成员函数 void onConnect() { ... } conMan.addCallback(CONNECTED, onConnect); // ❌ 错误局部 lambda栈内存 auto cb [](){...}; conMan.addCallback(CONNECTED, cb); // 编译警告non-trivial capture1.8 生产环境部署建议密钥安全管理禁止在源码中硬编码 WiFi 密码改用#include secrets.h并将该文件加入.gitignore对于高端平台Portenta H7利用 TrustZone 安全区存储密钥。连接状态持久化断电重启后从 EEPROM/Flash 读取上次连接状态避免冷启动时盲目重连示例EEPROM.read(0) 0xAA ? conMan.restoreState() : conMan.begin();多网络冗余设计// 伪代码WiFi 失败后自动切换至 LTE if (!wifiConMan.isConnected()) { lteConMan.begin(); // 启动备用连接 }功耗优化在DISCONNECTED状态下调用WiFi.disconnect()和WiFi.mode(WIFI_OFF)彻底关闭射频使用conMan.setKeepAliveInterval(300000)降低心跳频率。当 Portenta H7 的 LED 在深夜稳定亮起绿光且串口日志中不再出现 DISCONNECTED的闪烁意味着这套连接管理机制已融入设备的呼吸节律——它不再是一个待调试的模块而成为系统沉默可靠的神经末梢。

相关文章:

Arduino_ConnectionHandler库:嵌入式网络连接状态管理与自适应重连

1. Arduino_ConnectionHandler 库深度解析:嵌入式网络连接管理的工程实践指南1.1 库定位与核心价值Arduino_ConnectionHandler是 Arduino 官方生态中面向物联网终端设备的网络连接抽象管理层,其设计目标并非替代底层通信协议栈(如 WiFiClient…...

bilibili-downloader完全指南:从入门到精通的4个关键步骤

bilibili-downloader完全指南:从入门到精通的4个关键步骤 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 一、痛点分析&am…...

ComfyUI-FramePackWrapper功能选择指南:如何根据资源控制与使用便捷性选择最优方案

ComfyUI-FramePackWrapper功能选择指南:如何根据资源控制与使用便捷性选择最优方案 【免费下载链接】ComfyUI-FramePackWrapper 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-FramePackWrapper ComfyUI-FramePackWrapper作为一款高效的AI视频生成插…...

YOLOv10镜像作品集:高清图像目标检测惊艳案例分享

YOLOv10镜像作品集:高清图像目标检测惊艳案例分享 1. 引言:YOLOv10带来的视觉革命 在计算机视觉领域,目标检测技术正经历着前所未有的变革。YOLOv10作为最新一代的目标检测模型,以其无与伦比的速度和精度重新定义了实时检测的标…...

手把手教你用ENA-TDR实测USB3.0线:阻抗、延时、串扰一个不漏

深度解析USB3.0线缆全参数测试:从TDR原理到实战报告解读 在高速数据传输领域,一根优质USB3.0线缆的价值往往被严重低估。当工程师们为系统稳定性问题焦头烂额时,很少有人会想到问题可能出在那根不起眼的连接线上。事实上,根据行业…...

5分钟掌握:billd-desk跨平台远程控制高效解决方案

5分钟掌握:billd-desk跨平台远程控制高效解决方案 【免费下载链接】billd-desk 基于Vue3 WebRTC Nodejs Flutter搭建的远程桌面控制 项目地址: https://gitcode.com/gh_mirrors/bi/billd-desk 还在为远程办公的卡顿和限制而烦恼吗?当你急需远程…...

别再只加Mask了!手把手教你用FlashAttention实现真正的Sliding Window Attention(附代码)

突破传统误区:用FlashAttention实现高效滑动窗口注意力的实战指南 在Transformer模型优化领域,许多开发者对滑动窗口注意力(Sliding Window Attention, SWA)存在一个普遍误解——认为只需在注意力矩阵上添加滑动窗口掩码就能实现线性复杂度。这种错误认…...

Element UI表格样式改造避坑指南:透明化后文字看不清、边框错位怎么办?

Element UI表格透明化实战:解决文字模糊与样式错位的专业方案 当我们在Vue项目中采用Element UI的el-table组件实现透明化效果时,经常会遇到一些棘手的样式问题。本文将深入分析四个典型场景的成因,并提供经过实战检验的解决方案。 1. 透明背…...

专业数据恢复工具对决:UFS Explorer与R-Studio的实战选型指南

1. 数据恢复工具的核心价值与选型逻辑 当硬盘突然罢工或重要文件被误删时,专业数据恢复软件就像数字世界的急救医生。我经历过太多凌晨三点被叫醒处理服务器崩溃的案例,选对工具往往能决定数据"复活"的成功率。UFS Explorer和R-Studio这对老对…...

Android tinyalsa深度解析之pcm_params_get_periods_min调用流程与实战(一百七十三)

简介: CSDN博客专家、《Android系统多媒体进阶实战》作者 博主新书推荐:《Android系统多媒体进阶实战》🚀 Android Audio工程师专栏地址: Audio工程师进阶系列【原创干货持续更新中……】🚀 Android多媒体专栏地址&a…...

别再踩坑了!Django Ckeditor配置全指南:从基础使用到高级定制(2023最新版)

Django Ckeditor实战手册:2023年高效配置与深度定制技巧 如果你正在为Django项目寻找一个功能强大且可定制的富文本编辑器,Ckeditor无疑是最佳选择之一。但配置过程中那些令人头疼的兼容性问题、图片上传失败、工具栏自定义困难,确实让不少开…...

Android tinyalsa深度解析之pcm_params_get_period_size_max调用流程与实战(一百七十二)

简介: CSDN博客专家、《Android系统多媒体进阶实战》作者 博主新书推荐:《Android系统多媒体进阶实战》🚀 Android Audio工程师专栏地址: Audio工程师进阶系列【原创干货持续更新中……】🚀 Android多媒体专栏地址&a…...

Applied Intelligence投稿实战:从格式要求到高接受率的5个关键策略

1. 精准匹配期刊范围:避免编辑秒拒的第一道防线 投稿Applied Intelligence期刊时,最容易被忽视却最关键的一步就是研究范围匹配。我审过30篇稿件,发现80%的"desk rejection"(编辑直接拒稿)都源于研究方向与…...

6大维度深度测评:如何挑选最可靠的开源付费墙绕过工具?

6大维度深度测评:如何挑选最可靠的开源付费墙绕过工具? 【免费下载链接】bypass-paywalls-chrome-clean 项目地址: https://gitcode.com/GitHub_Trending/by/bypass-paywalls-chrome-clean 在数字阅读时代,优质内容的付费壁垒逐渐形成…...

避坑指南:lidar_align标定IMU外参时,loader.cpp源码修改与运动轨迹设计的那些关键细节

避坑指南:lidar_align标定IMU外参的核心细节与实战优化 在自动驾驶和机器人定位领域,激光雷达与IMU的联合标定是系统搭建的关键环节。许多开发者在初次使用lidar_align工具时会遇到各种问题——从源码适配的困惑到标定结果的不可靠。本文将深入剖析两个最…...

如何通过Snap Hutao实现原神游戏决策的智能化?

如何通过Snap Hutao实现原神游戏决策的智能化? 【免费下载链接】Snap.Hutao 实用的开源多功能原神工具箱 🧰 / Multifunctional Open-Source Genshin Impact Toolkit 🧰 项目地址: https://gitcode.com/GitHub_Trending/sn/Snap.Hutao …...

优化算法中的‘0.618’魔法:黄金分割法为何是工程优化的首选入门工具?

黄金分割法:从古希腊美学到现代工程优化的优雅解决方案 在工程优化领域,算法选择往往让初学者感到困惑。面对梯度下降、牛顿法等复杂方法,有一种源自公元前300年的数学比例——黄金分割比(0.618),却成为了…...

Argos Translate:5分钟掌握开源离线翻译API的全面集成方案

Argos Translate:5分钟掌握开源离线翻译API的全面集成方案 【免费下载链接】argos-translate Open-source offline translation library written in Python 项目地址: https://gitcode.com/GitHub_Trending/ar/argos-translate Argos Translate是一款基于Ope…...

水墨江南模型效果对比:不同参数下的笔触与渲染风格

水墨江南模型效果对比:不同参数下的笔触与渲染风格 最近在尝试用AI生成水墨画,发现一个挺有意思的现象:同一个“水墨江南”模型,用不同的参数设置,画出来的效果天差地别。有时候是寥寥几笔的写意小品,有时…...

避坑指南:用高德DistrictSearch获取精准行政边界时遇到的5个典型问题(含最新GeoJson处理技巧)

高德DistrictSearch深度避坑:5个实战难题与GeoJson优化方案 当你在深夜调试地图边界数据时,突然发现某个街道的轮廓出现了诡异的锯齿状变形——这不是恐怖片情节,而是使用高德DistrictSearch时可能遇到的真实场景。作为经历过数十个地图项目…...

AI专著写作快车道:特色工具大集合,助力科研成果出版

学术专著写作困境与AI工具助力 学术专著的写作并不只是简单的“写出来”,更在于能否顺利“出版、得到认可”。在当前的出版市场,学术专著的受众本就相对有限,因此出版社对学术价值和作者的影响力要求非常高。许多作者虽然完成了初稿&#xf…...

价值投资中的智能城市废水处理与再利用系统分析

价值投资中的智能城市废水处理与再利用系统分析 关键词:价值投资、智能城市、废水处理、废水再利用、系统分析 摘要:本文聚焦于价值投资视角下的智能城市废水处理与再利用系统。首先介绍了研究的背景,包括目的、预期读者、文档结构和相关术语。接着阐述了智能城市废水处理与…...

从羊肠小道到智能高速:HTTP1到HTTP3的演进之路

引言 计算机网络就像一张遍布全球的道路系统,服务器是一座座城市、村庄,客户端是穿梭其中的车辆,而HTTP协议,就是规范车辆通行、货物传递的交通规则。从HTTP1到HTTP3的演进,本质上就是这条“网络道路”的升级史——从泥…...

springboot+vue基于web的药店管理系统 药品商城在线购药系统

目录同行可拿货,招校园代理 ,本人源头供货商功能模块分析技术实现要点扩展功能建议项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作同行可拿货,招校园代理 ,本人源头供货商 功能模块分析 后台管理系统(SpringBoot&…...

springboot+vue基于web的演唱会音乐会购票管理系统设计系统

目录同行可拿货,招校园代理 ,本人源头供货商系统功能模块分析技术架构设计核心业务流程安全防护措施项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作同行可拿货,招校园代理 ,本人源头供货商 系统功能模块分析 用户模块 注册登…...

docker部署jar包的几种方式

docker部署jar包的几种方式前言使用Dockerfile手动打包jarDockerfile可复用容器jdk镜像直接创建可复用容器maven插件打包maven打包自动推送镜像到指定服务器关于docker容器启动后注册到nacos的ip是docker容器ip问题!总结前言 简单记录一下docker打包jar部署的几种方…...

Linux配置静态ip地址和Oracle VM VirtualBox导入/导出虚拟机Centos7

导入虚拟机选择管理 - 导入虚拟电脑找到自己的虚拟机位置修改内存大小,默认虚拟机电脑位置,MAC地址等导入后点击设置如下图:修改网络-网 -- 卡1,其他基本不需要修改桥接网络选好网卡接入网线;设置好网络以后使用命令重…...

Kindle漫画转换终极方案:如何解决电子阅读器上的格式兼容性问题

Kindle漫画转换终极方案:如何解决电子阅读器上的格式兼容性问题 【免费下载链接】kcc KCC (a.k.a. Kindle Comic Converter) is a comic and manga converter for ebook readers. 项目地址: https://gitcode.com/gh_mirrors/kc/kcc 你是否曾经尝试在Kindle上…...

Wan2.1 VAE与微信小程序开发结合:打造个人AI头像生成工具

Wan2.1 VAE与微信小程序开发结合:打造个人AI头像生成工具 你有没有想过,用一张自己的照片,就能快速生成几十种不同风格的艺术头像?无论是动漫风、油画感,还是赛博朋克,都能一键搞定。以前这可能需要专业的…...

ExcelDataReader实战指南:高效处理Excel文件3步法掌握跨格式解析

ExcelDataReader实战指南:高效处理Excel文件3步法掌握跨格式解析 【免费下载链接】ExcelDataReader Lightweight and fast library written in C# for reading Microsoft Excel files 项目地址: https://gitcode.com/gh_mirrors/ex/ExcelDataReader ExcelDat…...