长沙米拓建站,wordpress query_posts(),wordpress网站搬家图片路径,一般网站怎么做推广目录
数据结构
解码算法
解码效果 这篇文章基于上两篇文章继续#xff0c;
佳能镜头EOS系统EF协议逆向工程#xff08;一#xff09;转接环电路设计_佳能ef自动对焦协议_岬淢箫声的博客-CSDN博客本文属于专栏——工业相机。此专栏首先提供我人工翻译的法语文档部分…目录
数据结构
解码算法
解码效果 这篇文章基于上两篇文章继续
佳能镜头EOS系统EF协议逆向工程一转接环电路设计_佳能ef自动对焦协议_岬淢箫声的博客-CSDN博客本文属于专栏——工业相机。此专栏首先提供我人工翻译的法语文档部分然后通过STM32F103C8T6控制佳能镜头最后协同上位机或者NVIDIA Xavier实现自动对焦。还有一个用处不大的River文档它知道如何让相机和镜头通信也许对当前的摄影实践几乎没有帮助。尽管如此一些应用程序可能需要独立订购物镜的主要功能。撇开工业世界及其特殊机器不谈在另一个品牌的图像采集系统上安装佳能光学元件是不可能的而且是有罪的无论是出于经济原因还是纯粹的技术原因获得的组合提供了其他不可用的功能。https://blog.csdn.net/caoshiying/article/details/127609884?spm1001.2014.3001.5502佳能镜头EOS系统EF协议逆向工程二逻辑分析仪测试_岬淢箫声的博客-CSDN博客本章描述了用于解密EF协议函数的思想和分析如果其读数是可选的则所获得结果的摘要将在专用章节中进行汇编这仍然是正确理解EF协议函数的必要来源。随着函数的测试和逐步解码它们的描述和列表中使用的注释将在过程中变得越来越精确因为以前的分析或推理错误不会被强制纠正。所使用的逻辑分析仪是一个小型号的低成本8输入TTL USBEE AX Pro所使用的软件是制造商的标准套件可免费下载。软件不允许编辑或删除部分结果某些读数或时钟意外激活因为通电会导致SPI字解码不同步。https://blog.csdn.net/caoshiying/article/details/129057004?spm1001.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的首字母缩写。第四列是DCLDCL是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 QMetaEnumtypedef 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 QSharedPointerspi_signal_t pspi_signal_t;
typedef QSharedPointerspi_data_t pspi_data_t;
typedef QSharedPointeru_shape_t pu_shape_t;
#define ZERR_CAPTION u8系统错误
#define ZOK_CAPTION u8系统提示//CSV文件文件转换为信号数据
QListpspi_signal_t resolve_csv(const QString zcsv_path);
//信号数据转换为真实的主机与从机之间交换的信息
QListpspi_data_t resolve_signal(const QListpspi_signal_t ps);
//保存信息
void save_spi_data(const QString zcsv_path, const QListpspi_data_t ds);
//寻找信号中的U形返回下一个U形右端索引1返回值index_cursor与istart_cursor相等表示结束ok为false表示出错
pu_shape_t find_u_shape(const QListpspi_signal_t ps, int istart_cursor, int ilen);
//保存程序日志
void save_log(QtMsgType type, const QMessageLogContext cxt, const QString zlog);
//解析帧
void resolve_frame(QListpspi_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文件文件转换为信号数据
QListpspi_signal_t resolve_csv(const QString zcsv_path)
{QFile f(zcsv_path);QListpspi_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,u8input 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 QSharedPointerspi_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 QListpspi_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;
}//信号数据转换为真实的主机与从机之间交换的信息
QListpspi_data_t resolve_signal(const QListpspi_signal_t ps)
{int icursor 0;//遍历ps列表的索引int ilen ps.length(); //总长度减2双指针遍历int iorder 1;QListpspi_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用时约为13us1个byte不超过120usif (byte-elapse 120)byte-bad true;ds.append(byte);}}return ds;
}//保存信息
void save_spi_data(const QString zcsv_path, const QListpspi_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 u8DEBG;break;case QtWarningMsg:ztype u8WARN;break;case QtCriticalMsg:ztype u8CRIT;break;case QtFatalMsg:ztype u8FATA;break;case QtInfoMsg:ztype u8INFO;break;default:Q_ASSERT(false);break;}ts ztype , zlog.toUtf8() \n;ts.flush();output ztype zlog.toUtf8() \n;output.flush();
}//解析帧
void resolve_frame(QListpspi_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的转动信号与实际匹配说明解码成功。如果想要更多的通信规律请与我私聊。下一篇讲解常见的指令。