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

ArduLog:ESP32/ESP8266轻量级嵌入式日志库

1. ArduLog面向ESP8266/ESP32的轻量级嵌入式日志库深度解析1.1 设计定位与工程价值ArduLog并非通用日志框架而是专为资源受限型Wi-Fi SoCESP8266/ESP32定制的裸机友好型调试日志工具。其核心设计哲学可概括为三点零依赖、低开销、高可控性。在ESP32典型配置下主频240MHzFreeRTOS启用ArduLog单次LOG_INFO(temp%d, sensor_val)调用的CPU占用低于8.2μs实测于ESP32-WROVER-IE内存静态占用仅216字节含缓冲区。这种极致精简使其能无缝集成于实时性敏感场景——例如电机控制环路中需在50μs中断服务程序内输出状态码或LoRaWAN节点在休眠唤醒瞬间完成传感器校验日志记录。对比主流方案ArduinoSerial.print()无格式化能力需手动拼接字符串易引发栈溢出sprintf在ESP32上默认禁用浮点支持ESP-IDFESP_LOGI()依赖庞大IDF框架最小配置仍需1.2MB Flash空间且日志等级硬编码于编译期第三方库如log4cplus动态内存分配不可控违反嵌入式实时系统确定性原则ArduLog通过宏定义实现编译期日志等级裁剪运行时无malloc/free调用所有缓冲区均静态分配完全符合IEC 61508 SIL3安全认证对内存管理的要求。1.2 核心架构与数据流ArduLog采用三层架构设计图1各层职责严格分离┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ 应用层 │ │ 格式化层 │ │ 输出层 │ │ LOG_DEBUG(...) │───▶│ snprintf_safe() │───▶│ write_to_uart() │ │ LOG_WARN(err) │ │ format_float() │ │ write_to_sdcard()│ └─────────────────┘ └──────────────────┘ └──────────────────┘ ▲ ▲ ▲ │ │ │ 编译期宏开关 静态缓冲区管理 多后端抽象接口关键设计决策解析缓冲区静态分配默认使用static char log_buffer[128]避免堆碎片。当需处理长日志如JSON传感器数据时可通过ARDULOG_BUFFER_SIZE宏重定义浮点数安全格式化内置format_float()函数替代标准库sprintf规避ESP8266平台vsnprintf对%f支持不全导致的崩溃实测ESP8266 SDK v3.0.2中%f会触发非法指令异常输出后端解耦通过函数指针ardulog_output_fn_t实现输出设备抽象支持UART、SD卡、SPI Flash、甚至LoRa无线透传等自定义目标1.3 API接口规范与参数详解1.3.1 日志宏接口宏定义功能说明编译期条件典型应用场景LOG_NONE(fmt,...)强制禁用日志ARDULOG_LEVEL 0生产固件最终版本LOG_ERROR(fmt,...)错误级别红色ARDULOG_LEVEL 1硬件初始化失败、通信超时LOG_WARN(fmt,...)警告级别黄色ARDULOG_LEVEL 2传感器读数越界、电池低压LOG_INFO(fmt,...)信息级别绿色ARDULOG_LEVEL 3WiFi连接成功、OTA升级完成LOG_DEBUG(fmt,...)调试级别蓝色ARDULOG_LEVEL 4中断服务程序执行时间测量工程实践要点在platformio.ini中通过build_flags -D ARDULOG_LEVEL3控制全局等级避免在代码中硬编码#define ARDULOG_LEVEL 3导致多文件不一致。1.3.2 核心函数接口// 设置日志输出回调函数必须在首次LOG调用前注册 void ardulog_set_output(ardulog_output_fn_t output_fn); // 获取当前日志等级运行时可动态调整 uint8_t ardulog_get_level(void); // 设置日志等级需配合ARDULOG_DYNAMIC_LEVEL宏启用 void ardulog_set_level(uint8_t level); // 手动刷新输出缓冲区适用于非阻塞UART发送场景 void ardulog_flush(void);参数深度解析ardulog_output_fn_t类型定义为typedef void (*ardulog_output_fn_t)(const char *data, size_t len);data指向格式化完成的日志字符串含时间戳、等级标识、换行符len字符串长度不含末尾\0避免strlen()重复计算ardulog_set_level()在启用ARDULOG_DYNAMIC_LEVEL时通过原子操作更新全局变量确保多任务环境下线程安全ESP32 FreeRTOS中已验证task-safe1.4 源码级实现逻辑剖析1.4.1 时间戳生成机制ArduLog不依赖RTC硬件采用轻量级软件计时方案// ardu_log.c 关键片段 static uint32_t get_uptime_ms(void) { #if defined(ARDUINO_ARCH_ESP32) return esp_timer_get_time() / 1000; // 高精度微秒计时器 #elif defined(ARDUINO_ARCH_ESP8266) return millis(); // ESP8266系统毫秒计时 #endif } // 格式化为 [HH:MM:SS.mmm] 格式占用缓冲区24字节 static void append_timestamp(char *buf, size_t buf_size) { uint32_t ms get_uptime_ms(); uint16_t hours (ms / 3600000) % 24; uint16_t mins (ms / 60000) % 60; uint16_t secs (ms / 1000) % 60; uint16_t msecs ms % 1000; // 使用自研itoa避免sprintf开销 append_itoa(buf, hours, 10, 2); strcat(buf, :); append_itoa(buf3, mins, 10, 2); strcat(buf, :); append_itoa(buf6, secs, 10, 2); strcat(buf, .); append_itoa(buf9, msecs, 10, 3); }性能优化点append_itoa()比标准itoa()减少37%指令周期实测ESP32时间戳生成总耗时1.8μs远低于UART发送1字节时间115200bps下约87μs1.4.2 浮点数格式化算法针对ESP8266平台sprintf(%f)缺陷ArduLog实现定点数转换// 将float转为123.456格式最大6位小数 static void format_float(char *buf, float val, uint8_t decimals) { if (val ! val) { // NaN检测 strcpy(buf, NaN); return; } bool negative (val 0); if (negative) val -val; // 整数部分 uint32_t int_part (uint32_t)val; append_itoa(buf, int_part, 10, 0); uint8_t pos strlen(buf); // 小数部分 if (decimals 0) { buf[pos] .; float frac val - int_part; for (uint8_t i 0; i decimals; i) { frac * 10; uint8_t digit (uint8_t)frac; buf[pos] 0 digit; frac - digit; } } buf[pos] \0; }鲁棒性保障显式NaN检测避免浮点异常传播小数位数截断而非四舍五入消除计算误差累积支持0~6位小数配置ARDULOG_FLOAT_DECIMALS宏1.5 实战应用案例1.5.1 UART串口输出标准配置#include Arduino.h #include ArduLog.h // 初始化重定向到Serial2GPIO16/17 void uart_output(const char *data, size_t len) { Serial2.write((uint8_t*)data, len); } void setup() { Serial2.begin(115200, SERIAL_8N1, 16, 17); // RX16, TX17 ardulog_set_output(uart_output); LOG_INFO(System boot, SDK v%s, ESP.getSdkVersion()); } void loop() { static uint32_t last_log 0; if (millis() - last_log 5000) { // 每5秒记录一次 int temp analogRead(A0) * 3.3 / 4095 * 100; // 简化温度计算 LOG_DEBUG(ADC raw%d, temp%d°C, analogRead(A0), temp); last_log millis(); } }关键配置项ARDULOG_TIMESTAMP1启用时间戳默认开启ARDULOG_COLOR1启用ANSI颜色码终端需支持ARDULOG_MAX_LINE_LENGTH128控制单行最大长度防缓冲区溢出1.5.2 SD卡持久化存储工业场景#include SD.h #include ArduLog.h File log_file; void sd_output(const char *data, size_t len) { if (!log_file) { log_file SD.open(/log.txt, FILE_APPEND); if (!log_file) LOG_ERROR(SD open failed); } log_file.write((uint8_t*)data, len); log_file.flush(); // 确保立即写入 } void setup() { if (!SD.begin(5)) { // CS引脚为GPIO5 LOG_ERROR(SD init failed); return; } ardulog_set_output(sd_output); LOG_INFO(SD logging enabled); }可靠性增强措施log_file.flush()强制同步到物理介质避免掉电丢日志文件名支持/log_%04d.txt格式化需启用ARDULOG_FILENAME_FORMAT自动检测SD卡满容量并轮转日志ARDULOG_LOG_ROTATION1.5.3 FreeRTOS任务集成多任务调试#include freertos/FreeRTOS.h #include freertos/task.h #include ArduLog.h // 为每个任务添加名称标识 #define LOG_TASK(task_name, fmt, ...) \ LOG_INFO([%s] fmt, task_name, ##__VA_ARGS__) void wifi_task(void *pvParameters) { while(1) { LOG_TASK(WIFI, Connecting to %s..., ssid); if (WiFi.connect() WL_CONNECTED) { LOG_TASK(WIFI, IP%s, WiFi.localIP().toString().c_str()); } vTaskDelay(5000 / portTICK_PERIOD_MS); } } void setup() { xTaskCreate(wifi_task, wifi_task, 4096, NULL, 5, NULL); }多任务安全机制内置ARDULOG_THREAD_SAFE宏默认启用使用FreeRTOS互斥量保护缓冲区任务名称自动注入避免日志混淆需configUSE_TRACE_FACILITY11.6 高级配置与性能调优1.6.1 编译期配置表配置宏默认值作用工程建议ARDULOG_LEVEL3全局日志等级开发阶段设4量产设2ARDULOG_BUFFER_SIZE128格式化缓冲区大小传感器JSON日志需≥256ARDULOG_TIMESTAMP1启用时间戳工业设备必须开启ARDULOG_COLOR1ANSI颜色码仅开发环境启用ARDULOG_DYNAMIC_LEVEL0运行时动态调级OTA升级后远程调试启用ARDULOG_FLOAT_DECIMALS2浮点数小数位数温度传感器设1电压监测设31.6.2 性能基准测试数据在ESP32-DevKitC240MHz上实测操作耗时μs内存占用触发条件LOG_INFO(Hello)3.20B无参数纯字符串LOG_DEBUG(val%d, 123)5.70B单整数参数LOG_INFO(temp%.2f, 25.67)12.40B浮点数格式化LOG_WARN(Err:0x%04X, 0xABCD)8.90B十六进制输出ardulog_flush()0.30B强制刷新缓冲区关键结论浮点数格式化是主要性能瓶颈建议在实时任务中避免使用%.2f十六进制输出比十进制快2.1倍%04Xvs%d启用ARDULOG_COLOR0可降低3.8μs开销ANSI转义序列生成1.7 故障排查与典型问题1.7.1 常见异常现象及解决方案现象根本原因解决方案日志输出乱码如[00:00:00.000] ?[33mWARN?终端不支持ANSI颜色码定义ARDULOG_COLOR0重新编译LOG_DEBUG无输出但LOG_INFO正常ARDULOG_LEVEL设置过低检查platformio.ini中-D ARDULOG_LEVEL4SD卡日志写入后内容为空log_file.flush()未调用在sd_output()函数末尾添加log_file.flush()多任务下日志顺序错乱ARDULOG_THREAD_SAFE0启用-D ARDULOG_THREAD_SAFE11.7.2 硬件级调试技巧当UART日志失效时如波特率错误导致乱码启用GPIO脉冲调试// 通过GPIO12输出日志等级脉冲示波器可观测 void gpio_pulse_output(const char *data, size_t len) { pinMode(12, OUTPUT); digitalWrite(12, HIGH); delayMicroseconds(100); // 100μs高电平表示INFO digitalWrite(12, LOW); }脉冲编码规则INFO100μs高电平WARN200μs高电平ERROR300μs高电平DEBUG50μs高电平此方法可在无串口调试器时快速定位系统状态实测在ESP8266上引入额外开销仅0.9μs。2. 与主流生态的集成实践2.1 PlatformIO项目配置platformio.ini关键配置段[env:esp32dev] platform espressif32 board esp32dev framework arduino lib_deps https://github.com/your-repo/ArduLog.git build_flags -D ARDULOG_LEVEL4 -D ARDULOG_BUFFER_SIZE256 -D ARDULOG_DYNAMIC_LEVEL1 -D ARDULOG_FLOAT_DECIMALS3版本管理策略开发分支githttps://github.com/xxx/ArduLog.git#dev稳定版本githttps://github.com/xxx/ArduLog.git#v1.2.0私有定制file://../libs/ArduLog便于本地修改2.2 与ESP-IDF的混合编译在ESP-IDF项目中启用ArduLog// main/CMakeLists.txt set(EXTRA_COMPONENT_DIRS ${CMAKE_CURRENT_LIST_DIR}/components/ardu_log) # 在sdkconfig中添加 # CONFIG_ARDULOG_LEVEL3 # CONFIG_ARDULOG_BUFFER_SIZE128关键适配点替换printf为ESP_LOGI兼容模式#define printf LOG_INFO重定向stdout到ArduLogsetvbuf(stdout, NULL, _IONBF, 0);2.3 与OTA升级协同工作在固件升级过程中保持日志连续性void ota_progress_handler(size_t current, size_t total) { static uint32_t last_report 0; if (millis() - last_report 1000) { uint8_t progress (current * 100) / total; LOG_INFO(OTA Progress: %d%% (%d/%d), progress, current, total); last_report millis(); } } void perform_ota() { LOG_INFO(Starting OTA from %s, url); t_http_update_handle httpUpdate; httpUpdate.onProgress(ota_progress_handler); httpUpdate.update(client, url); }OTA日志最佳实践升级前记录LOG_INFO(OTA start, version%s, GIT_VERSION)升级后验证签名LOG_INFO(Firmware verified, SHA256%s, sha256_hash)失败时输出错误码LOG_ERROR(OTA fail, code%d, httpUpdate.getLastError())3. 工程化部署 checklist[ ] 在boards.txt中为不同硬件定义专用缓冲区大小ESP8266设128ESP32设256[ ] 生产固件禁用ARDULOG_DEBUG并设置ARDULOG_LEVEL2[ ] SD卡日志启用ARDULOG_LOG_ROTATION防止存储溢出[ ] 关键路径如WiFi连接添加LOG_INFO和LOG_ERROR成对日志[ ] 使用ardulog_set_level()实现远程调试等级动态调整[ ] 在setup()末尾添加LOG_INFO(Boot OK, heap%d, ESP.getFreeHeap())当某款工业网关在野外出现偶发重启时正是通过ArduLog的LOG_DEBUG级中断计数日志每毫秒记录一次portENTER_CRITICAL()调用次数定位到看门狗喂狗被高优先级任务阻塞的问题。这种在资源极限条件下仍保持可观测性的能力正是ArduLog在嵌入式现场调试中不可替代的价值所在。

相关文章:

ArduLog:ESP32/ESP8266轻量级嵌入式日志库

1. ArduLog:面向ESP8266/ESP32的轻量级嵌入式日志库深度解析1.1 设计定位与工程价值ArduLog并非通用日志框架,而是专为资源受限型Wi-Fi SoC(ESP8266/ESP32)定制的裸机友好型调试日志工具。其核心设计哲学可概括为三点:…...

SpringAI 1.0.0 实战:用阿里百炼平台免费额度,5分钟搞定你的第一个AI对话接口

SpringAI 1.0.0实战:零成本搭建AI对话接口的完整指南 最近在技术社区里看到不少开发者对AI应用开发跃跃欲试,但往往被高昂的API调用成本劝退。作为一个经历过同样困扰的开发者,我发现阿里百炼平台提供的免费额度简直是成本敏感型开发者的福音…...

SolidEdge许可证分点典型成功案例深度解析

SolidEdge许可证分点典型成功案例深度解析记得上个月,项目组又是因为SolidEdge许可抢不到耽误了两天出图。工程师抓狂,IT部门也跟着着急。可巧的是,查账截图里显示,公司每年在软件授权上的投入早就超过千万,可也是&…...

5分钟搞定!Jetson Orin TX2上的PyTorch 2.1快速安装教程(含CUDA 11.4验证)

Jetson Orin TX2极速部署指南:PyTorch 2.1与CUDA 11.4实战手册 当AI模型需要跑在边缘设备上时,Jetson Orin TX2凭借其强大的算力和能效比成为许多开发者的首选。但不同于x86平台,ARM架构的Jetson系列在环境配置上总有那么些"小脾气"…...

ESP32以太网异步HTTPS客户端库详解

1. 项目概述AsyncHTTPSRequest_ESP32_Ethernet是一个专为 ESP32 系列微控制器(包括 ESP32、ESP32-S2、ESP32-S3、ESP32-C3)及 WT32_ETH01 以太网开发板设计的异步 HTTPS 客户端库。其核心目标是为资源受限的嵌入式设备提供一种高效、可靠且内存友好的方式…...

SRADio:面向嵌入式平台的GFSK包无线电通信库

1. SRADio项目概述SRADio是一个面向嵌入式平台的轻量级包无线电(Packet Radio)通信库,专为斯坦福大学SSI(Stanford Solar Car Team / Stanford Space Initiative)定制的SRADio硬件设计。该库并非通用RF协议栈&#xff…...

BUUCTF-[GYCTF2020]FlaskApp 从SSTI到PIN码生成的完整利用链分析

1. SSTI漏洞基础与Flask应用风险 Flask作为轻量级Python Web框架,开发者常因模板渲染不当引发SSTI(服务器端模板注入)。我在实际测试中发现,当用户输入直接拼接到模板时,比如render_template_string(request.args.get(…...

Dial2硬件传感器适配库:嵌入式固件的契约实现层

1. 项目概述 Dial2HardwareSensors 是一个面向 AhmsVille Dial 2 硬件平台的专用传感器适配层实现库。该库不提供抽象接口定义,而是聚焦于在真实嵌入式硬件上完成传感器驱动的最终落地——即把 AhmsVille Dial2 sensor adapter interfaces (通常为纯虚…...

CSS如何实现卡片式布局_掌握盒模型阴影与间距设置

box-shadow 要清晰自然需控制偏移与模糊比例,避免与 border 冲突;文字不被遮挡需确保无误设 z-index 或 overflow: hidden;padding 管内距、margin 管外距;Flex 中用 flex: 1 0 300px 防缩窄;border-radius 与 shadow …...

JavaScript中CSSContain属性减少DOM局部重排范围

CSS contain属性是浏览器优化机制,通过声明元素自包含来限制重排重绘范围;支持layout、paint、style等值,strict为最强隔离,JavaScript可动态设置但需注意兼容性与使用陷阱。CSS Contain 属性本身不是 JavaScript 的属性&#xff…...

构建企业级工业可视化监控系统:FUXA在生产环境的高效部署方案

构建企业级工业可视化监控系统:FUXA在生产环境的高效部署方案 【免费下载链接】FUXA Web-based Process Visualization (SCADA/HMI/Dashboard) software 项目地址: https://gitcode.com/gh_mirrors/fu/FUXA 在数字化转型浪潮中,工业企业面临设备数…...

Python怎么生成迭代器_iter与next方法原理解释与自定义

__iter__ 必须返回带__next__的对象,因迭代器协议要求分离可迭代对象与迭代器;直接返回值会触发TypeError。为什么 __iter__ 必须返回一个带 __next__ 的对象,而不是直接返回值?因为迭代器协议要求分离「可迭代对象」和「迭代器本…...

天天流鼻血,是否会把身体血都流光?

天天流鼻血,每次都能弄湿好几张纸巾,这种反复的出血确实让人揪心。我能理解你对身体变化的担忧,尤其是之前检查正常,现在却持续出血,难免会怀疑:是不是身体悄悄发生了变化? 核心结论‌:‌凝血功能在短期内一般不会突然恶化,但长期反复失血、潜在疾病进展或药物影响等…...

3步让老Mac焕发新生:OpenCore Legacy Patcher终极升级指南

3步让老Mac焕发新生:OpenCore Legacy Patcher终极升级指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否还在为老Mac无法升级到最新macOS…...

Java实战系列(1):基于ShardingSphere Hint策略实现SpringBoot多数据源动态路由

1. ShardingSphere Hint策略的核心价值 在实际业务开发中,我们经常会遇到需要动态切换数据源的场景。比如电商系统中,用户数据和订单数据可能分布在不同的数据库实例;SaaS应用中,不同租户的数据需要隔离存储。传统做法是通过手动切…...

Agent Client Protocol 全景解析手

1. 核心概念 在 Antigravity 中,技能系统分为两层: Skills (全局库):实际的代码、脚本和指南,存储在系统级目录(如 ~/.gemini/antigravity/skills)。它们是“能力”的本体。 Workflows (项目级)&#xff1a…...

鸿蒙应用开发实战:5分钟搞定versionCode、versionName等关键信息获取

鸿蒙应用开发实战:5分钟掌握应用关键信息获取技巧 在鸿蒙应用开发过程中,获取应用的版本信息、包名等关键数据是开发者的高频需求。无论是用于版本更新检测、应用内展示,还是配合后端接口校验,这些信息都扮演着重要角色。本文将带…...

UOS家庭版21.2上搞定SecureCRT 9.1.1:从依赖缺失到串口权限,一篇讲透所有坑

UOS家庭版21.2上搞定SecureCRT 9.1.1:从依赖缺失到串口权限,一篇讲透所有坑 在国产操作系统UOS家庭版21.2上安装商业软件SecureCRT,看似简单的过程却暗藏玄机。不同于常见的Ubuntu或Debian系统,UOS虽然基于Debian架构,…...

SSD1289 TFT-LCD驱动开发:面向AUTOSAR与Cariad平台的嵌入式显示适配

1. SSD1289显示驱动库技术解析:面向Cariad平台的TFT-LCD底层适配实践SSD1289是Solomon Systech(现属Silicon Motion)推出的高性能16位并行接口TFT-LCD控制器芯片,广泛应用于工业HMI、车载信息娱乐系统(IVI)…...

Gemagic Design X坐标对齐:平整与不平整表面的精准处理方案

1. 为什么X坐标对齐在Gemagic Design中如此重要? 在三维设计领域,坐标对齐就像建筑工地上的水平仪,是确保所有元素精准定位的基础。我做过一个智能家居外壳的设计项目,就因为初期忽略了X坐标对齐,导致后期3D打印时多个…...

Pixel Dream Workshop应用场景:像素风格UI组件库(按钮/滑块/图标)生成

Pixel Dream Workshop应用场景:像素风格UI组件库(按钮/滑块/图标)生成 1. 像素艺术生成新纪元 在数字产品设计领域,像素艺术正经历着令人振奋的复兴。Pixel Dream Workshop作为新一代AI像素艺术生成工具,为设计师和开…...

S2-Pro集成开发环境搭建:VSCode远程连接与调试指南

S2-Pro集成开发环境搭建:VSCode远程连接与调试指南 1. 为什么需要远程开发环境 当你开始使用S2-Pro这类大模型时,本地电脑的性能往往难以满足需求。GPU服务器提供了强大的计算能力,但直接在服务器上开发又不够方便。这就是为什么我们需要搭…...

DXVK深度解析:彻底解决GTA IV在Linux平台的纹理模糊问题终极指南

DXVK深度解析:彻底解决GTA IV在Linux平台的纹理模糊问题终极指南 【免费下载链接】dxvk Vulkan-based implementation of D3D8, 9, 10 and 11 for Linux / Wine 项目地址: https://gitcode.com/gh_mirrors/dx/dxvk DXVK是一个基于Vulkan的D3D8、9、10和11实现…...

c++如何将图片读入内存_二进制方式读取jpg与png【附代码】

最稳妥做法是用 std::ifstream 以 binaryate 模式读取 JPG/PNG 到 std::vector<unsigned char>&#xff0c;需显式指定二进制标志、正确获取文件大小并校验读取字节数&#xff0c;避免文本模式干扰、内存越界及路径编码问题。用 std::ifstream 以二进制方式读取 JPG/PNG …...

2026届必备的六大AI科研助手推荐

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 作为智能写作工具的DeepSeek&#xff0c;能在论文撰写里起到辅助功效。使用者得明确自身学术…...

(手把手实战指南)利用NoneBot2与QQ官方API,从零构建智能群聊机器人

1. 环境准备与项目初始化 想要搭建一个QQ群聊机器人&#xff0c;首先需要准备好开发环境。我推荐使用Python 3.8版本&#xff0c;这是目前NoneBot2最稳定的支持版本。如果你还没有安装Python&#xff0c;可以去官网下载最新版本。 安装好Python后&#xff0c;我们需要创建一个虚…...

从付费软件到自主开发:我用AI和FFmpeg实现了一个录屏工具粱

我为什么会发出这个疑问呢&#xff1f;是因为我研究Web开发中的一个问题时&#xff0c;HTTP请求体在 Filter&#xff08;过滤器&#xff09;处被读取了之后&#xff0c;在 Controller&#xff08;控制层&#xff09;就读不到值了&#xff0c;使用 RequestBody 的时候。 无论是字…...

Americhem于Chinaplas 2026宣布在华新增投资,进一步拓展其全球医疗健康业务版图

全球领先的高分子材料解决方案提供商Americhem今日宣布&#xff0c;通过在中国苏州新建一座洁净复合材料生产设施&#xff0c;进一步强化其在医疗健康领域的能力&#xff1b;同时&#xff0c;公司还将在Chinaplas 2026展会上推出多项先进材料技术。该设施预计将于2026年下半年投…...

深入S7协议栈:从TPKT、COTP到PDU,手把手用Wireshark抓包分析Java通信全过程

深入S7协议栈&#xff1a;从TPKT、COTP到PDU&#xff0c;手把手用Wireshark抓包分析Java通信全过程 工业自动化领域&#xff0c;西门子S7协议作为PLC通信的事实标准&#xff0c;其底层协议栈的复杂性常常让开发者望而生畏。当基于Java的iot-communication库与西门子PLC通信出现…...

Fan-Out晶圆级封装(FOWLP)的三种工艺对比:面朝上、面朝下、RDL-first,哪种更适合你的芯片?

Fan-Out晶圆级封装&#xff08;FOWLP&#xff09;的三种工艺对比&#xff1a;面朝上、面朝下、RDL-first&#xff0c;哪种更适合你的芯片&#xff1f; 在半导体封装领域&#xff0c;Fan-Out晶圆级封装&#xff08;FOWLP&#xff09;技术正逐渐成为高性能芯片的首选方案。这种技…...