ODB++文件是由VALOR提出的一种ASCII码,双向传输文件。奥宝公司和康代公司的设备都是用的ODB++格式进行PCB的生产和检测。
对ODB++文件进行解析把数据栅格化很重要,查了网上找不到一个成熟能用的ODB++文件解析代码。自己上手写了一个。
当前解析一些载板,软硬结合板都没有问题。
解析思路:
文件注释:
代码思路:
Commom下只有两个文件,主要存放一些常用的算法,一些常量定义,一些枚举类型
Job目录下存放跟ODB++资料紧密相关的类
这部分内容需要了解ODB++资料才能理解。
实际上就是ODB+文件是一个JOB类,包含有step等等信息,一般整个板就是一个panel,panel是由set组合成的,set又是有一个pcs组合来的,pcs就是对应我们的PCB单板了。
odbGeometry 存放ODB++的图元,主要用到的pad(焊盘)segment(线)surface (铜皮)arc(弧线)
和其他的一些辅助类,所有图元类继承自图元基类odbBase.
就这几个解析我手上几个G的ODB资料都没问题。
需要解析奥宝康代等扫描机,曝光机资料的可私信我。
(二)用C++重写的odb++模块
支持C#和Python调用
C++函数接口
#pragma once
#include "ecam_global.h"
#include <QRectF>
#include <QString>
#include <QRectF>
#include <QImage>
#include <memory>
#include <vector>
class ICAM;
enum class eCamType
{
ODBPP, //奥宝康代普遍使用的AOI导入格式
AOIIMG, //奥宝特有的AOI格式
RLE, //行程编码
GERBER, //行业通用格式,精度问题导致在高端板逐渐被弃用
};
extern "C" {
class ECAM_EXPORT ECAM
{
public:
ECAM(eCamType type);
~ECAM();
/// <summary>
/// 设置文件路径,支持导入tgz格式文件 && 已解压出来的资料文件夹
/// </summary>
/// <param name="path"></param>
void SetFilePath(QString path);
/// <summary>
/// 预解析,解析资料的整体信息,包括Panel,Step,Layer,Matrix以获取层别等信息
/// </summary>
/// <returns></returns>
int PreAnalyze();
/// <summary>
/// 获取板子长宽信息,默认单位是um
/// </summary>
/// <returns></returns>
QRectF GetBoundingBox();
/// <summary>
/// 选择解析出来的层别,只支持一个信号层,可支持多个通孔层
/// </summary>
/// <param name="step">Step名称,如PNL,PCS</param>
/// <param name="signalLayer">信号层名称</param>
/// <param name="drillLayer">通孔层名称</param>
/// <returns></returns>
int Select(QString step, QString signalLayer, QStringList drillLayer);
/// <summary>
/// 解析资料,分析资料的特征信息
/// </summary>
/// <returns></returns>
int Analyze();
/// <summary>
/// 绘制图像
/// </summary>
/// <param name="imgWidth">图像宽</param>
/// <param name="imgHeight">图像高</param>
/// <param name="img">绘制出来的图像</param>
/// <param name="drawRect">绘制的区域大小</param>
/// <returns></returns>
int Draw(int imgWidth, int imgHeight, QImage& img, QRectF& drawRect);
/// <summary>
///
/// </summary>
/// <param name="pageScale"></param>
/// <param name="path"></param>
/// <returns></returns>
int DrawProfile(double pageScale, QString path);
int Draw(int imgWidth, int imgHeight, QString path, QRectF& drawRect);
int Draw(int imgWidth, int imgHeight, uchar** imgData, QRectF& drawRect);
std::vector<QString> GetSignalLayerNames();
std::vector<QString> GetStepNames() const;
void ClearJob();
void FreeMem();
private:
std::shared_ptr<ICAM> icam;
};
//#pragma region 以下接口为导出到C#使用的接口,接口使用同上一致
int ECAM_EXPORT InitEcam(int type);
int ECAM_EXPORT SetFilePath(const char* path);
int ECAM_EXPORT PreAnalyze();
int ECAM_EXPORT GetStepNames(char*& stepNames);
int ECAM_EXPORT GetSignalLayerNames(char*& signalLayerNames);
int ECAM_EXPORT Select(const char* step, const char* signalLayer, const char* drillLayer);
int ECAM_EXPORT Analyze();
int ECAM_EXPORT GetBoundingBox(double& x, double& y, double& width, double& height);
int ECAM_EXPORT DrawProfile(double pageScale, const char* path);
int ECAM_EXPORT DrawImageFile(int x, int y, int drawWidth, int drawHeight, int imgWidth, int imgHeight, const char* path);
int ECAM_EXPORT DrawImageData(int x, int y, int drawWidth, int drawHeight, int imgWidth, int imgHeight, uchar** imgData);
int ECAM_EXPORT ClearJob();
void ECAM_EXPORT FreeMem();
//int ECAM_EXPORT ExportImage(uchar** image, int& width, int& height, int& stride);
//#pragma endregion
}
C#调用接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace ECAMCSharp
{
public partial class ECAM
{
[DllImport("ECAMd.dll", EntryPoint = "InitEcam", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int InitEcam(int type);
[DllImport("ECAMd.dll", EntryPoint = "SetFilePath", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int SetFilePath(string path);
[DllImport("ECAMd.dll", EntryPoint = "PreAnalyze", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int PreAnalyze();
[DllImport("ECAMd.dll", EntryPoint = "GetStepNames", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int GetStepNames(out IntPtr stepNames);
[DllImport("ECAMd.dll", EntryPoint = "GetSignalLayerNames", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int GetSignalLayerNames(out IntPtr signalLayerNames);
[DllImport("ECAMd.dll", EntryPoint = "Select", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int Select(string step, string signalLayer, string drillLayer);
[DllImport("ECAMd.dll", EntryPoint = "Analyze", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int Analyze();
[DllImport("ECAMd.dll", EntryPoint = "GetBoundingBox", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int GetBoundingBox(ref double x, ref double y, ref double width, ref double height);
[DllImport("ECAMd.dll", EntryPoint = "DrawProfile", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int DrawProfile(double pageScale, string path);
[DllImport("ECAMd.dll", EntryPoint = "DrawImageFile", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int DrawImageFile(int x, int y, int drawWidth, int drawHeight, int imgWidth, int imgHeight, string path);
[DllImport("ECAMd.dll", EntryPoint = "DrawImageData", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int DrawImageData(int x, int y, int drawWidth, int drawHeight, int imgWidth, int imgHeight, out IntPtr imgData);
[DllImport("ECAMd.dll", EntryPoint = "ClearJob", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int ClearJob();
[DllImport("ECAMd.dll", EntryPoint = "FreeMem", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern void FreeMem();
}
}
ECAM测试程序
C#测试程序