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

佳能镜头EOS系统EF协议逆向工程(三)解码算法

目录

数据结构

解码算法

解码效果


这篇文章基于上两篇文章继续,

佳能镜头EOS系统EF协议逆向工程(一)转接环电路设计_佳能ef自动对焦协议_岬淢箫声的博客-CSDN博客本文属于专栏——工业相机。此专栏首先提供我人工翻译的法语文档部分,然后通过STM32F103C8T6控制佳能镜头,最后协同上位机或者NVIDIA Xavier实现自动对焦。还有一个用处不大的River文档,它知道如何让相机和镜头通信,也许对当前的摄影实践几乎没有帮助。尽管如此,一些应用程序可能需要独立订购物镜的主要功能。撇开工业世界及其特殊机器不谈,在另一个品牌的图像采集系统上安装佳能光学元件是不可能的,而且是有罪的,无论是出于经济原因还是纯粹的技术原因,获得的组合提供了其他不可用的功能。https://blog.csdn.net/caoshiying/article/details/127609884?spm=1001.2014.3001.5502佳能镜头EOS系统EF协议逆向工程(二)逻辑分析仪测试_岬淢箫声的博客-CSDN博客本章描述了用于解密EF协议函数的思想和分析,如果其读数是可选的,则所获得结果的摘要将在专用章节中进行汇编,这仍然是正确理解EF协议函数的必要来源。随着函数的测试和逐步解码,它们的描述和列表中使用的注释将在过程中变得越来越精确,因为以前的分析或推理错误不会被强制纠正。所使用的逻辑分析仪是一个小型号的低成本8输入TTL USBEE AX Pro,所使用的软件是制造商的标准套件,可免费下载。软件不允许编辑或删除部分结果,某些读数或时钟意外激活,因为通电会导致SPI字解码不同步。https://blog.csdn.net/caoshiying/article/details/129057004?spm=1001.2014.3001.5502

数据结构

逻辑分析仪没有特别要求,某宝上的大部分逻辑分析仪可以用。数据格式要求很简单,举便如下:

; CSV, generated by libsigrok4DSL 0.2.0 on Fri Jul 29 10:17:48 2022
; Channels (3/16)
; Sample rate: 10 MHz
; Sample count: 50.896 M Samples
Time(s), CLK, DLC, DCL
0,1,1,1
0.0498275,1,1,0
0.0498285,1,1,1
0.0498697,1,1,0
0.049876,1,1,1
0.0499793,1,1,0
0.0499986,0,1,0
0.050005,1,1,0

分号开头表示注释,第一列是时间,这个时间是相对开始捕获的时间,用单词elapse表示列标题更合适。这款逻辑分析仪软件导出数据的表头就是这么写的,无所谓了。第二列是CLK信号,CLK是时钟的简写,搞硬件的同学是不是很熟悉呢?第三列是DLC信号。DLC是Data Lens to Camera的首字母缩写。第四列是DCL,DCL是Data Camera to Lens首字母缩写。所有信号用1表示高电平,0表示低电平。佳能相机的电平为3.3V。

我使用Qt写的解码工具,CMake工程代码如下:

cmake_minimum_required(VERSION 3.20)
project(TAMRON VERSION 1.0)find_package(Qt5 COMPONENTS Widgets REQUIRED PATHS $ENV{Qt515_DIR})
link_libraries(Qt5::Widgets)
add_link_options(/SUBSYSTEM:CONSOLE)
file(GLOB TAMRON_SRCS *.cpp *.h *.ui *.qrc *.rc)
add_executable(${PROJECT_NAME} ${TAMRON_SRCS})
target_compile_definitions(${PROJECT_NAME} PRIVATE $<IF:$<CONFIG:DEBUG>,CWDEBUG,CWNDEBUG>)

Qt515_DIR环境变量是必须的。

解码算法

算法是关键是解决ACK干扰。核心思路是寻找U型特征的连续信号。源代码只有一个main.cpp,代码如下:

#include <QApplication>
#include <QMainWindow>
#include <QFileDialog>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QDebug>
#include <QFileInfo>
#include <QMetaEnum>typedef struct _spi_signal_t
{uint32_t line_no;//行号double elapse;//消耗的时间,6位小数,单位为秒,存储化为usbool clk;//时钟是否高位bool dcl;//主机信号是否高位bool dlc;//从机信号是否高位
} spi_signal_t;typedef struct _spi_data_t
{uint32_t order;//序号uint32_t start_line;//信号起始行号uint32_t end_line;//信号结束行号uint8_t dcl;//主机命令uint8_t dlc;//从机返回int frame_no;//字节所属帧号bool bad;//是否发生丢失bit的情况double elapse;//消耗的时间double frequency;//实际通讯频率,存储为KHz
} spi_data_t;//信号数据中的U型结构,全部为引用指针,不管理内存
typedef struct _u_shape_t
{spi_signal_t *high_left;//U槽左端spi_signal_t *low_left;//U槽底左边spi_signal_t *low_right;//U槽底右边spi_signal_t *high_right;//U槽右端spi_signal_t *forward;//遍历前进到达的位置bool ok;//此U型结构是否能用int index_cursor;//信号列表遍历时当前的位置
} u_shape_t;typedef QSharedPointer<spi_signal_t> pspi_signal_t;
typedef QSharedPointer<spi_data_t> pspi_data_t;
typedef QSharedPointer<u_shape_t> pu_shape_t;
#define ZERR_CAPTION u8"系统错误"
#define ZOK_CAPTION u8"系统提示"//CSV文件文件转换为信号数据
QList<pspi_signal_t> resolve_csv(const QString &zcsv_path);
//信号数据转换为真实的主机与从机之间交换的信息
QList<pspi_data_t> resolve_signal(const QList<pspi_signal_t> &ps);
//保存信息
void save_spi_data(const QString &zcsv_path, const QList<pspi_data_t> &ds);
//寻找信号中的U形,返回下一个U形右端索引+1,返回值index_cursor与istart_cursor相等表示结束,ok为false表示出错
pu_shape_t find_u_shape(const QList<pspi_signal_t> &ps, int istart_cursor, int ilen);
//保存程序日志
void save_log(QtMsgType type, const QMessageLogContext &cxt, const QString &zlog);
//解析帧
void resolve_frame(QList<pspi_data_t> &ds);//入口函数
int main(int argc, char **argv)
{qInstallMessageHandler(save_log);QApplication app(argc, argv);auto zcsv_path = QFileDialog::getOpenFileName(nullptr,u8"选择一个CSV文件","D:/tamron");if (zcsv_path.isEmpty())return 1;auto ps = resolve_csv(zcsv_path);if (ps.isEmpty())return 2;auto ds = resolve_signal(ps);if (ds.isEmpty())return 3;resolve_frame(ds);save_spi_data(zcsv_path, ds);return 0;
}//CSV文件文件转换为信号数据
QList<pspi_signal_t> resolve_csv(const QString &zcsv_path)
{QFile f(zcsv_path);QList<pspi_signal_t> ps;if (!f.open(QFile::ReadOnly | QFile::Text)){QMessageBox::warning(nullptr, ZERR_CAPTION, f.errorString());return ps;}QTextStream ts(&f);ts.skipWhiteSpace();//DSView导出数据有5行注释和1行标头,应当跳过。for (short i = 0; i < 4; i++){auto zline = ts.readLine();if (ts.atEnd() || !zline.startsWith(";")){QMessageBox::warning(nullptr, ZERR_CAPTION, u8"无效的CSV文件。");break;}}ts.readLine();if (ts.atEnd())return ps;uint32_t iline = 6;while (!ts.atEnd()){QString zline = ts.readLine();if (zline.isEmpty())continue;QStringList cols = zline.split(u8",");if (cols.length() < 4){QMessageBox::critical(nullptr, ZERR_CAPTION, QString(u8"第%1行无效数据").arg(iline));return ps;}spi_signal_t r;r.line_no = iline++;if (iline >= UINT32_MAX){QMessageBox::warning(nullptr,ZERR_CAPTION,u8"input data amount exceed system capacity.");break;}r.elapse = cols[0].toDouble() * 1000000;r.clk = cols[1].toInt() != 0;r.dlc = cols[2].toInt() != 0;r.dcl = cols[3].toInt() != 0;pspi_signal_t p = QSharedPointer<spi_signal_t>::create(r);ps.append(p);}qInfo() << u8"合计" << ps.length() << u8"个信号\n";return ps;
}//寻找信号中的U形,返回下一个U形右端索引+1,返回值index_cursor与istart_cursor相等表示结束,ok为false表示出错
pu_shape_t find_u_shape(const QList<pspi_signal_t> &ps, int istart_cursor, int ilen)
{pu_shape_t pu(new u_shape_t{0,});u_shape_t *u = pu.data();u->index_cursor = istart_cursor;//1.寻找U槽//1.1.寻找下降沿,定位U槽左端while (u->index_cursor < ilen && ps[u->index_cursor]->clk)u->index_cursor++;u->forward = ps[u->index_cursor].data();if (u->index_cursor - 1 < 0){u->ok = false;u->index_cursor++;return pu;}if (u->index_cursor + 1 >= ilen){qWarning() << "data end on finding u->high_left and u->low_left";u->ok = false;return pu;}u->high_left = ps[u->index_cursor - 1].data();u->low_left = ps[u->index_cursor].data();u->forward = u->low_left;
#ifdef DEBUGqInfo() << "u begin: " << u->high_left->line_no;
#endifu->index_cursor++;if (u->index_cursor >= ilen){qWarning() << "data end on finding u->low_right";u->ok = false;return pu;}//1.2.寻找上升沿,定位U槽底有多长while (u->index_cursor < ilen && !ps[u->index_cursor]->clk)u->index_cursor++;u->low_right = ps[u->index_cursor - 1].data();u->forward = u->low_right;if (u->index_cursor >= ilen){qWarning() << "data end on finding u->high_right";u->ok = false;return pu;}//1.3.寻找下降沿,定位U槽右端//while (u->index_cursor < ilen && ps[u->index_cursor]->clk)//    u->index_cursor++;u->high_right = ps[u->index_cursor].data();u->forward = u->high_right;//1.4.如果U槽的时间跨度大于28us则不是数据传输,暂不处理佳能中的拱门double fuspan1 = u->high_right->elapse - u->low_right->elapse;double fuspan2 = u->low_right->elapse - u->low_left->elapse;if (fuspan1 > 28 || fuspan1 < 0 || fuspan2 > 28 || fuspan2 < 0){qWarning() << "elapse time out: " << fuspan2 << ", " << fuspan1;u->ok = false;}elseu->ok = true;
#ifdef DEBUGif (u->ok)qInfo() << "u end: " << u->forward->line_no;
#endifreturn pu;
}//信号数据转换为真实的主机与从机之间交换的信息
QList<pspi_data_t> resolve_signal(const QList<pspi_signal_t> &ps)
{int icursor = 0;//遍历ps列表的索引int ilen = ps.length(); //总长度减2,双指针遍历int iorder = 1;QList<pspi_data_t> ds;if (ilen < 17){QMessageBox::critical(nullptr, ZERR_CAPTION, u8"数据量太少。");return ds;}while (icursor < ilen - 17){int ifor_cursor = icursor;//发现问题则回到U槽右端int iu_cursor = 0;pspi_data_t byte(new spi_data_t);pu_shape_t pu;byte->order = iorder;byte->frame_no = 0;byte->dcl = 0;byte->dlc = 0;byte->bad = false;byte->start_line = 0;byte->end_line = 0;byte->elapse = 0;byte->frequency = 0;qInfo() << "byte " << iorder << " begin: " << ps[icursor]->line_no;for (short i = 0; i < 8; i++){pu = find_u_shape(ps, ifor_cursor, ilen);ifor_cursor = pu->index_cursor;if (iu_cursor == 0)iu_cursor = ifor_cursor;if (pu->ok){
#ifdef DEBUGqInfo() << "byte " << iorder << " bit " << i << " at " << pu->low_left->line_no;
#endifif (byte->start_line == 0){byte->start_line = pu->low_left->line_no;byte->elapse = pu->low_left->elapse;}if (pu->high_right->dcl)byte->dcl |= 1 << (7 - i);if (pu->high_right->dlc)byte->dlc |= 1 << (7 - i);}else{byte->bad = true;break;}}if (byte->bad){icursor = iu_cursor;qWarning() << "byte " << iorder << " break: " << pu->forward->line_no;}else{icursor = ifor_cursor;byte->end_line = pu->forward->line_no;byte->elapse =  pu->forward->elapse - byte->elapse;byte->frequency = 8000 / byte->elapse;qInfo() << "byte " << iorder << " end: " << pu->high_right->line_no;icursor++;//跳过第9个下降沿while (ps[icursor]->clk && icursor < ilen)icursor++;while (!ps[icursor]->clk && icursor < ilen)icursor++;iorder++;//80KHz下每个bit用时约为13us,1个byte不超过120usif (byte->elapse > 120)byte->bad = true;ds.append(byte);}}return ds;
}//保存信息
void save_spi_data(const QString &zcsv_path, const QList<pspi_data_t> &ds)
{//避免多次执行QChar的构造函数和析构函数static const QChar cfill('0');QFileInfo fi(zcsv_path);QString zresolve_path = fi.dir().absoluteFilePath(fi.baseName() + "resolve.csv");QFile f(zresolve_path);if (!f.open(QFile::ReadWrite | QFile::Text | QFile::Truncate)){QMessageBox::warning(nullptr, ZERR_CAPTION, f.errorString());return;}QTextStream ts(&f);ts << u8" command,sequence,   start,     end,   dcl,   dlc,elapse(us),frequency(KHz),bad\n";for (const pspi_data_t &d : ds){// char c = ' ';// if (d->dlc >= 0x20 && d->dlc <= 0x7E && d->dcl == 0)//     c = (char)d->dlc;// if (c == ',')//     c = ' ';QString zline = QString("%1,%2,%8,%9,    %3,    %4,%5,%6,%7\n").arg(d->frame_no, 8).arg(d->order, 8).arg(d->dcl, 2, 16, cfill).arg(d->dlc, 2, 16, cfill).arg(d->elapse, 10, 'f', 0).arg(d->frequency, 14, 'f', 0).arg(d->bad, 3).arg(d->start_line, 8).arg(d->end_line, 8);// .arg(c, 4);zline = zline.toUpper();ts << zline;}ts.flush();f.close();QMessageBox::information(nullptr, ZOK_CAPTION, u8"数据转换完成。");qInfo() << u8"数据转换完成。";
}void save_log(QtMsgType type, const QMessageLogContext &cxt, const QString &zlog)
{static QFile f;static QTextStream output(stdout);static QTextStream ts;if (!f.isOpen()){QDir d(QApplication::applicationDirPath());f.setFileName(d.absoluteFilePath("main.log"));if (!f.open(QFile::Append | QFile::Text | QFile::ReadWrite)){QMessageBox::warning(nullptr, ZERR_CAPTION, u8"无法打开日志文件。");return;}ts.setDevice(&f);ts.setAutoDetectUnicode(true);}QString ztype;switch (type){case QtDebugMsg:ztype = u8"DEBG";break;case QtWarningMsg:ztype = u8"WARN";break;case QtCriticalMsg:ztype = u8"CRIT";break;case QtFatalMsg:ztype = u8"FATA";break;case QtInfoMsg:ztype = u8"INFO";break;default:Q_ASSERT(false);break;}ts << ztype << ", " << zlog.toUtf8() << "\n";ts.flush();output << ztype << " " << zlog.toUtf8() << "\n";output.flush();
}//解析帧
void resolve_frame(QList<pspi_data_t> &ds)
{if (ds.length() < 2)return;int ilen = ds.length();int iframe = 0;for (int i = 0; i < ilen; i++){if (ds[i]->dcl > 0)iframe++;ds[i]->frame_no = iframe;}
}

解码效果

如下图所示

 解码结果中通信频率、0A与AA应答信号、0x06与0x05的转动信号与实际匹配,说明解码成功。如果想要更多的通信规律,请与我私聊。下一篇讲解常见的指令。

相关文章:

佳能镜头EOS系统EF协议逆向工程(三)解码算法

目录 数据结构 解码算法 解码效果 这篇文章基于上两篇文章继续&#xff0c; 佳能镜头EOS系统EF协议逆向工程&#xff08;一&#xff09;转接环电路设计_佳能ef自动对焦协议_岬淢箫声的博客-CSDN博客本文属于专栏——工业相机。此专栏首先提供我人工翻译的法语文档部分&…...

搞互联网吧,线下生意真不是人干的

搞互联网吧&#xff0c;线下生意真不是人干的 应该是正月初几里吧&#xff0c;好巧不巧的被迫去参加了一下我们初中同学的聚会。其实毕业这么多年&#xff0c;无论大学&#xff0c;高中还是中学&#xff0c;类似的聚会我都是能躲则躲&#xff0c;有特别想见的同学也都是私下单…...

MySQL性能调优与设计——MySQL中的索引

MySQL中的索引 InnoDB存储引擎支持以下几种常见索引&#xff1a;B树索引、全文索引、哈希索引&#xff0c;其中比较关键的是B树索引。 B树索引 InnoDB中的索引自然也是按照B树来组织的&#xff0c;B树的叶子节点用来存放数据。 聚集索引/聚簇索引 InnoDB中使用了聚集索引&…...

这5个代码技巧,让我的 Python 加速了很多倍

Python作为一种功能强大的编程语言&#xff0c;因其简单易学而受到很多初学者的青睐。它的应用领域又非常广泛&#xff1a;科学计算、游戏开发、爬虫、人工智能、自动化办公、Web应用开发等等。 而在数据科学领域中&#xff0c;Python 是使用最广泛的编程语言&#xff0c;并且…...

Sphinx+Scws 搭建千万级准实时搜索应用场景详解

目标&#xff1a; 一、搭建准确的千万级数据库的准实时搜索&#xff08;见详情&#xff09; 二、实现词语高亮&#xff08;客户端JS渲染&#xff0c;服务器端渲染&#xff0c;详见7.3&#xff09; 三、实现搜索联想&#xff08;输入框onchange,ajax请求搜索&#xff0c;取10条在…...

kafka缩容后,使用tcpdump抓包找到还在连接的用户

1、使用tcpdump抓包监控端口9092 tcpdump src port 9092 16:23:27.680835 IP host01.XmlIpcRegSvc > 192.168.168.1.36199: Flags [R.], seq 0, ack 1493547965, win 0, length 0 16:23:27.681877 IP host01.XmlIpcRegSvc > 192.168.168.2.50416: Flags [R.], seq 0, ac…...

Spring

Spring Spring 是什么? Spring 是于 2003 年兴起的一个轻量级的,IOC 和 AOP 的 Java 开发框架&#xff0c;它 是为了简化企业级应用开发而生的。 Spring有几大特点如下 轻量级的 Spring 框架使用的 jar 都比较小&#xff0c;一般在 1M 以下或者几百 kb。Spring 核 心功能…...

vue2版本《后台管理模式》(中)

文章目录前言一、创建一个文件夹 utils 里面新增一个 setToken.js 文件(设置token验证&#xff09;二 、创建一个api文件夹 新增 service.js &#xff08;axios拦截器&#xff09;三、在api文件夹里 新增一个 api.js 来接收数据&#xff08;把api封装哪里需要某项数据直接引入就…...

网络游戏开发-服务器篇

1.网络 网络分为弱联网和强联网。 1.弱联网 弱联网是客户端连接到服务端发送一个请求,然后由服务端回应一个内容,这是单向传输的方式,服务端是无法主动给客户端发送消息的,服务端相应请求之后会自动关闭连接。 缺点:传输采用明文,通过抓包可以看到明文信息,安全性不太…...

智慧校园源码:电子班牌,支持手机移动端以及web端对班牌设备的管控

▶ 智慧校园系统有源码&#xff0c;有演示&#xff01; (电子班牌&#xff09;设备管理&#xff1a; 1、 管理员查看全校电子班牌设备信息&#xff1a;含有&#xff08;班级信息、软件版本、设备型号、开关机信息、班牌截屏信息、教室编号、设备ID、设备描述、在线状态、离线状…...

研报精选230216

目录 【行业230216东吴证券】环保行业月报&#xff1a;2023M1环卫新能源渗透率大增至11.91%&#xff0c;上海地区渗透率高达77%【行业230216国元证券】国元新食饮&#xff1a;一图君&#xff1a;22年白酒产量&#xff1a;同降6.2%【行业230216浙商证券】农林牧渔点评报告&#…...

在华为MateBook Ego的arm windows 11上安装hyper-V虚拟机

入手一台华为matebook Ego的笔记本&#xff0c;由于想要测试一些arm的驱动功能&#xff0c;经常会把系统搞蓝屏&#xff0c;于是想安装一个虚拟机&#xff0c;于是试了vmware ,visual-box&#xff0c;由于本机是arm架构上面两个软件都无法进行正常安装&#xff0c;可能是由于有…...

OpenCV Canny边缘检测

本文是OpenCV图像视觉入门之路的第13篇文章&#xff0c;本文详细的介绍了Canny边缘检测算子的各种操作&#xff0c;例如&#xff1a;Canny算子进行边缘检测等操作。 Canny函数是OpenCV中用于执行边缘检测的函数之一&#xff0c;其参数包括&#xff1a; threshold1&#xff1a;…...

C#.Net正则表达式学习笔记

C#.Net正则表达式学习笔记 在处理字符串时&#xff0c;你会经常有查找符合特定条件的字符串的需求&#xff0c;比如判断一串电话号码是否符合格式、一个邮箱是否符合格式、一个密码是否包含了字母大小写等等。 正则表达式(Regular expressions)用于匹配文本&#xff0c;使用一…...

矩阵理论复习(十二)

已知方阵A的不变因子&#xff1a; 求谱半径求矩阵级数判断矩阵幂级数的收敛性 若矩阵B的某个算子范数小于1&#xff0c;则I-B可逆。 矩阵分析 任何相容矩阵范数都存在与之相容的向量范数。 盖尔圆盘定理一的证明 椭圆范数的证明 若||.||是Cm上的向量范数&#xff0c;A为…...

大数据框架之Hadoop:HDFS(七)HDFS 2.X新特性

7.1集群间数据拷贝 scp实现两个远程主机之间的文件复制 ​ scp -r hello.txt roothadoop103:/root/hello.txt // 推 push ​ scp -r roothadoop103:/root/hello.txt hello.txt // 拉 pull ​ scp -r roothadoop103:/root/hello.txt roothadoop104:/root //是通过本地主机中…...

Fluent工作目录

1 工作目录定义工作目录&#xff08;working directory&#xff09;是一种文件存储路径设置方式。基于工作目录的方法&#xff0c;写文件时只需要指定文件名&#xff0c;而不需要指定完全的文件路径&#xff0c;从而简化程序编写&#xff0c;对不同操作系统环境有更好的适应性。…...

Learning C++ No.10【STL No.2】

引言&#xff1a; 北京时间&#xff1a;2023/2/14/23:18&#xff0c;放假两个月&#xff0c;没有锻炼&#xff0c;今天去跑了几圈&#xff0c;一个字&#xff0c;累&#xff0c;感觉人都要原地升天了&#xff0c;所以各位小伙伴&#xff0c;准确的说是各位卷王&#xff0c;一定…...

【java 高并发编程之JUC】2w字带你JUC从入门到精通

点击查看脑图目录地址,实时更新 1 什么是 JUC 1.1 JUC 简介 在 Java 中&#xff0c;线程部分是一个重点&#xff0c;本篇文章说的 JUC 也是关于线程的。JUC 就是 java.util .concurrent 工具包的简称。这是一个处理线程的工具包&#xff0c;JDK 1.5 开始出现的。 1.2 进程与…...

QCon演讲实录(下):多云管理关键能力实现与解析-AppManager

在上篇中&#xff0c;我们已经基本了解了多云管理。现在&#xff0c;我们将深入探讨多云管理关键能力实现&#xff1a;AppManager。 什么是AppManager&#xff1f; 上面我们讲了理论、我们自己使用的交付流程和整体架构&#xff0c;下面我们进入关键能力实现与解析的环节&…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中&#xff0c;网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时&#xff0c;开发者迫切需要一套高效、可靠且跨平台的调试方案。过去&#xff0c;我们或多或少使用过 Chrome DevTools、Remote Debug…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁

赛门铁克威胁猎手团队最新报告披露&#xff0c;数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据&#xff0c;严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能&#xff0c;但SEMR…...

高分辨率图像合成归一化流扩展

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 1 摘要 我们提出了STARFlow&#xff0c;一种基于归一化流的可扩展生成模型&#xff0c;它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流&#xff08;TARFlow&am…...