信息化 频道

<连载>Protel二次开发从入门到精通

  6. PCB机器人和消息系统
  6.1 原理

在PCB编辑器中,机器人是软件代理,它们被通过特定的PCB消息时序激活和取消。机器人的工作是保持PCB编辑器环境在一个有效的状态,如果在PCB编辑器内的事件改变了PCB编辑器的环境状态,机器人通过突跳来恢复环境。

为了更好地理解机器人,我们可以设想一个未来的家庭保姆由机器人组成,有不同的机器人,如厨房机器人、车库机器人和地毯清洗机器人等等。丈夫已经把厨房搞的一团乱,厨房的传感器已经广播了有关厨房状态的一个消息,妻子已经把车库搞的一团乱,车库的传感器已经广播了有关车库状态的一个消息,机器人监听到在这环境中所发生事件,但是它们必须等候家庭中成员离开他们所在的区域,当这些家庭中成员白天外出时,厨房机器人和车库机器人被派遣一个信息,来清洁已发生变化的区域,其他机器人也已经收到消息,但是这些机器人的知道他们的职责,它们不参加清洁工作,一旦这些任务被完成, 机器人被取消激活,且等候下一个事件。

此此类推,我们能看到与环境有影响的两个实体组(用户组和机器人组),此两组从不在相同时间被激活,用户组发送消息到所有机器人。一个消息描述了一个发生在环境中的特殊的事件,每一个机器人接受此消息并且按它自己的方式起作用。举个例子,从事园艺的机器人当得到一个由花园中所产生的“MessHappened”消息时,就写下花园需要被重新排列任务,当它收到“EveryoneLeftTheHouse”(成员离开家)消息时,此机器人执行重新排列花园的任务。

 

 


图4-14 机器人在一个操作中的时序

在图4-14中,一个周期表示一个活动的主要目标或目的时间,并且一个进程描述了或俘获了这个活动的本质(这里在一个顺序的序列中可为多进程),机器人通过PCB编辑器监听到所有消息广播,在周期结束前,YieldToRobots消息是广播,在周期结束前,机器人有必须的数据来做它们的处理,整个周期是重复的。

PCB编辑器函数按相同的方式:机器人监听到消息广播并按它自己的方式响应。一般地,一个最终用户对PCB产生影响,他开始一个进程,执行少量动作并且停止进程,因而,消息发送到机器人一般有相同的式样:

·消息表示一个进程已开始。

·消息组描述用户活动(编辑,增一个图元等等)。

·消息表示要被停止的进程(意味着用户将不执行任何改变,,如果需要的话,让机器人有一些时间来执行它们的活动。)

·消息表示一个进程已结束。

我们将在明细中得到消息序列和稍后如何来利用和控制它们。

    为了使第三方开发者能够使用此系统,对它的结构进行一些理解是必需的,所有的机器人被在一个分类的列表中注册,它们被分类的指令决定它们将会收到一个特定的的消息指令,这个指令通过机器人“优先级(priority)”决定,因而,当一个消息被广播的时候,它被沿着列表向前传递,而且每个机器人都有机会对它产生响应,响应按它们的“优先级(priority)进行。


图4-15 机器人和消息

  6.2 PCB编辑器消息

一个PCB消息描述了在PCB编辑器中的当前事件,一个PCB消息表示发生在PCB编辑器内的内部事件,并且这些消息将携带有关当前内部事件的信息,PCB消息被沿着一个机器人会响应或会不响应的特定消息的链传递,一个PCB消息包含一个源对象、一个目标对象、一个消息标识符和一个可选项消息数据(消息数据能为一个数据结构指针),一个PCB消息标识符和它们的意义将被下表中简短地描述。

PCB消息标识符

描述

PCBM_NullMessage

表示消息是空的。

PCBM_BeginModify

表示一个PCB对象将要被修改。

PCBM_BoardRegisteration

表示一个PCB对象将要被增加到数据库中或从数据库中删除。

PCBM_EndModify

表示一个PCB对象已被修改。

PCBM_CancelModify

表示一个PCB对象的修改被取消。

PCBM_Create

创建,N/A

PCBM_Destroy

销毁,N/A

PCBM_ProcessStart

表示一个进程的开始。

PCBM_ProcessEnd

表示一个进程的结束。

PCBM_ProcessCancel

表示一个进程取消。

PCBM_YieldToRobots

表示机器人是被激活。

PCBM_CycleEnd

表示一个周期的结束。

PCBM_CycleStart

表示一个周期的开始。

PCBM_SystemInvalid

表示机器人/消息系统是无效的。

PCBM_SystemValid

表示机器人/消息系统是有效的。

PCBM_ViewUpdate

N/A

PCBM_UnDoRegister

表示带有Undo/Redo系统的指定对象的注册。

表 1: PCB 消息

  6.3 内部的PCB机器人

在PCB编辑器内,有十一个内部的机器人,虽然所有的机器人将通过PCB编辑器监听到相同的在内部发送的PCB消息,但它们不响应所有的PCB消息。PCB编辑器提供了可创建自定义机器人的能力,自定义的机器人将被增加到机器人系统,自定义的机器人不仅能响应PCB消息,也能响应用户定义的消息,每一个内部的PCB编辑器机器人将被与它们能反应的特定PCB消息相关,描述如下:

·Component Pattern Robot元件式样机器人

元件式样机器人是负责当一个封装形式(Footprints)被改变时,执行适当的步骤,当下列消息被收到时,从印制板中删除旧的封装形式,增加新的封装形式,分配适当的网络到新的封装形式焊盘。

PCB消息

描述

ProcessStart

此消息发信号到机器人,来在内部的元件列表中删除所有的元件。

EndModify

此消息包含当前元件、图案信息,它监视元件式样的改变,并且如果它已改变,此机器人存储在封装形式已被更新的元件内部列表中。

YieldToRobots

此消息发信号到机器人,来从库中更新元件,封装形式被更新,如果需要重新分配,网络分配被选中。

元件式样机器人优先级设置是2130。

·Net Connectivity Robot网络连接机器人

当下列消息被收到时,网络连接机器人监视印制板连接/连线表的完整性。

PCB消息

描述

ProcessStart

一个无效网络的内部列表被清除。

EndModify

无效的网络增加到内部无效的网络列表中。

BoardRegisteration

刷新并且增加更新的网络到印制板数据库系统中。

YieldToRobots

如果任何无效的网络被发现,无效的网络被选中,这样它们被修正和更新。

网络连接机器人优先级设置是1120。

·Board data structure robot印制板数据结构机器人

当下列消息被收到时,印制板数据结构机器人维护数据库的内部操作。

PCB消息

描述

EndModify

如果空间数据结构有一个修改,检查并且如果必要话,纠正空间数据结构的有效性。

BoardRegisteration

通知PCB编辑器,PCB文档已修改。

印制板数据结构机器人优先级设置是3000。

·Engineering Change Order robot工程更改指令机器人

当下列消息被收到时,当PCB印制板的网络列表被修改后,工程更改指令机器人将写一个ECO文件。

PCB消息

描述

ProcessStart

机器人内部列表被初始化。

BeginModify

源对象被准备好,来被ECO机器人使用。

EndModify

修改的对象被分析,ECO文件开始从此被写出。

BoardRegisteration

对象被增加到被存放在机器人内部列表的印制板中,或从被存放在机器人内部列表的印制板中删除。

YieldToRobots

处理机器人内部列表,并且写出此ECO文件的剩余。

工程更改指令机器人优先级设置是1140。

·Design Rule Checking robot设计规则检测机器人

当下列消息被收到时,设计规则检测机器人检测PCB印制板规则是否是有效的。

PCB消息

描述

ProcessStart

一个机器人内部列表被初始化。

EndModify

相应的对象被存储在机器人内部列表中。

BoardRegisteration

相应的对象被存储在机器人内部列表中。

YieldToRobots

DRC被在包含在一个机器从内部列表的对象上执行。

设计规则检测机器人优先级设置是1105。

·UndoRedo robot UndoRedo机器人

当下列消息被收到时,当PCB印制板被修改后,UndoRedo机器人更新UndoRedo设施。

PCB消息

描述

CycleStart

一个机器人被初始化。

BeginModify

在机器人内部列表中存储可能的修改对象。

EndModify

增加修改对象到PCB UndoRedo结构。

CancelModify

从更新的PCB UndoRedo结构中停止受影响的对象。

UnDoRegister

增加最新的注册到PCB UndoRedo结构中或从PCB UndoRedo结构中删除对象。

ProcessEnd

在PCB UndoRedo结构末端区域包含最后的修改。

YieldToRobots

在PCB UndoRedo结构末端区域包含最后的修改。

UndoRedo机器人优先级设置是1110。

·Polygon robot平面多边形机器人

当下列消息被收到时,平面多边形机器人在PCB印制板上更新平面多边形,这些平面多边形设置已被修改。

PCB消息

描述

ProcessStart

机器人内部列表初始化。

EndModify

修改的平面多边形对象被放入到机器人内部列表中。

BoardRegisteration

新的平面多边形被增加到机器人内部列表中。

YieldToRobots

重灌相关的平面多边形对象。

平面多边形机器人优先级设置是2110。

·Updating robot更新机器人

当下列消息被收到时,更新机器人维护名称引用的完整性,很多实体通过它们的名称引用到其它实体(例如一个FromTo参考到一个网络,和到2个焊盘,一个焊盘名称引用到一个元件和一个焊盘号码),如果引用的对象名称改变,引用到它的同样地必须改变。

PCB消息

描述

ProcessStart

一个机器人内部列表被初始化。

BeginModify

可能地修改对象被准备好。

EndModify

所有必须的修改被计算出来。

YieldToRobots

所有与修改对象有关的对象被通过它的名称更新。

规则更新机器人优先级设置是2120。

·Internal Plane Robot内部平板机器人

当下列消息被收到时,内部平板机器人更新内部电源层连接。

PCB消息

描述

ProcessStart

一个机器人内部列表被更新。

EndModify

内部的平面连接焊盘风格必须修改来存储在一个机器人内部列表中。

BoardRegisteration

内部的平面连接焊盘风格必须修改来存储在一个机器人内部列表中。

YieldToRobots

为相关的焊盘更新电源平面连接内部平面。

内部平板机器人优先级设置是2100。

·Panel Robot平面机器人

当下列消息被收到时,当PCB对象和PCB印制板被改变后,平面机器人更新PCB平面内容。

PCB消息

描述

ProcessStart

初始化一个机器人。

EndModify

平面要求的所有的修改被计算出来,并且存储在一个机器人内部列表中。

BoardRegisteration

平面要求的所有的修改被计算出来,并且存储在一个机器人内部列表中。

YieldToRobots

存储在机器人内部列表中的修改被应用到平面。

平面机器人优先级设置是1100。

  6.4 如何扩展机器人/扩展为外部使用的消息系统?

PCB消息和机器人是独立的实体但它们对PCB编辑器环境有影响。机器人当收到消息时响应,然而,为开发者来定义新的外部的机器人识别而内部的机器人将不识别的PCB消息是可能的。

  6.4.1如何从外部发送消息到PCB编辑器内

在外部的服务器可许改变了PCB编辑器的环境状态,并且需要通知内部的机器人来恢复环境情况下,从外部服务器发送消息到PCB编辑器是特别有用的,用户定义PCB消息的目的是为外部服务器发送消息到PCB编辑器提供能力,这样为外部服务器设计的外部机器人就能响应。

发送消息到PCB编辑器,来通知机器人,PCB编辑器环境已经发生了改变,发送信息,您需要调用带有四个参数的PcbApi_EventRouter_SendMessage函数。

PcbApi_EventRouter_SendMessage

参数

描述

SourceObjectHandle

表示一个源对象的句柄。

DestinationObjectHandle

表示一个目标对象的句柄。

MessageID

表示消息的ID号。

MessageData

表示消息数据,能为一个指向到一个数据结构的指针或仅维持一些值的变量。

注意,DestinationObjecthandle参数总是一个c_BroadCast常量,此参数被随PCBApi_EventRouter_SendMessage函数调用一起传递,函数PCBApi_EventRouter_SendMessage在下表中描述。

描述

目标

消息ID号

消息数据

NullMessage

Nil

Nil

PCBM_NullMessage

Any

BeginModify

Object handle

c_Broadcast

PCBM_BeginModify

c_NoEventData

BoardRegisteration

Board handle

c_Broadcast

PCBM_BoardRegisteration

Object handle

EndModify

Object handle

c_Broadcast

PCBM_EndModify

c_NoEventData

CancelModify

Object handle

c_Broadcast

PCBM_CancelModify

c_NoEventData

Create

N/A

N/A

PCBM_Create

N/A

Destroy

N/A

N/A

PCBM_Destroy

N/A

ProcessStart

Object handle

c_Broadcast

PCBM_ProcessStart

c_NoEventData

ProcessEnd

c_FromSystem

c_Broadcast

PCBM_ProcessEnd

c_NoEventData

ProcessCancel

c_FromSystem

c_Broadcast

PCBM_ProcessCancel

c_NoEventData

YieldToRobots

c_FromSystem

c_Broadcast

PCBM_YieldToRobots

c_NoEventData

CycleEnd

c_FromSystem

c_Broadcast

PCBM_CycleEnd

c_NoEventData

CycleStart

c_FromSystem

c_Broadcast

PCBM_CycleStart

Board object

SystemInvalid

c_FromSystem

c_Broadcast

PCBM_SystemInvalid

c_NoEventData

SystemValid

c_FromSystem

c_Broadcast

PCBM_SystemValid

c_NoEventData

ViewUpdate

N/A

N/A

PCBM_ViewUpdate

N/A

UnDoRegister

Objecthandle

c_Broadcast

PCBM_UnDoRegister

UndoRegisterData structure

表 2: PCBApi_EventRouter_SendMessage过程参数

如果没有数据需要被传送,消息数据要么是一个指向一个数据结构的指针或一个c_NoEventData常量。软件开发者发送自定义的消息到PCB编辑器是可能的,然而内部机器将不响应自定义的消息,因为它们被设计为在PCB编辑器中仅响应预定义的PCB消息。一个消息ID号是Word类型,您必须声明一个自定义的Word类型消息,在当前PCB消息ID中,确保消息ID号不冲突,是您必须的责任,您能在PCBTypes单元中检测到已分配到PCB消息的常量值。

  6.4.2如何扩展机器人链?

再说上面提到的模拟大家庭厦,这里有内部保姆机器人(厨房机器人、轻便小床机器人、车库机器人和地毯清洗机器人),现在此家庭想要雇用一个外部的监控机器人来在晚上保护住宅,那么,监控机器人仅响应 “我们离开此位置”的消息,并启动来监控住宅,一旦家庭在晚上外出,监控机器人则倾听指定的消息并且执行监控住宅任务。其它协助机器人完成不知道此任务,并且仅仅执行它们自己的任务。外部的记录监控机器人如其它内部机器人一样,监听所有的内部消息。

下图表示外部的监控机器人所连接到机器人的建造链表,外部机器人仅响应确定的消息。



图4-16 增加一个外部的机器人到PCB编辑器

外部机器人通过PCB API被连接到机器人系统。从图4-16中,外部机器人的优先级被设置为比所有已存在的内部机器人低,外部机器人通过回调机器人进程得到所有PCB消息。

为了创建一个外部的机器人,这里有您必须遵循的步骤,来创建并注册您的机器人到PCB编辑器中,首先,您必须在PCB内创建一个指定的机器人,以插件方式加入到消息系统,并且在相同时间连通您的机器人,通过调用函数PCBAPI_CreateRobot来完成,PCBAPI_CreateRobot返回机器人句柄,创建在PCB内。您必须提供一个机器人的名称、一个优先级和“机器人进程”地址,“机器人进程”将传送PCB消息到您的机器人,一个机器人进程必须有类型过程(Source, Destination : Pointer; MessageID : Word; Parameter : Pointer),它通过给定的消息传送所有携带的信息。下面例子显示了一般的机器人进程的例子。

然后您必须利用先前函数返回的句柄来创建您自己的机器人。这将连接您的机器人、在PCB内的机器人和进程内机器人。最后,通过注册机器人到系统中(调用RegisterWithSystem 和UnRegisterFromSystem),机器人被增到加到到机器人列表中。

PCBAPI_CreateRobot

参数

描述

Name

表示一个外部机器人的名称。

ArobotProcedure

ArobotProcedure是类型过程Procedure(Source, Destination : Pointer; MessageID : Word; Parameter : Pointer);

Apriority

设置一个在PCB编辑器的机器人系统中的机器人的优先级。

TPCBRobot 类

字段

描述

ObjectHandle

表示一个机器人的句柄。

Name

表示一个机器人的名称。

RobotProcedure

表示PCB消息被传递到消息句柄的过程,这是一个回调函数。

方法

描述

RegisterWithSystem

在PCB编辑器的机器人系统中注册一个机器人。

DeRegisterFromSystem

在PCB编辑器的机器人系统中取消一个机器人的注册。

在下面见到代码片段中,我们看到了创造一个外部机器人的基本轮廓,外部机器人将会“钩”住PCB编辑器的机器人链。这个外部的机器人的优先级将会被设置来与在机器人列表中的所有机器人的优先级进行比较。

Implementation

Type

{................................................................................}

TMessageRobot = Class(TPCBRobot)//消息机器人从对象TPCBRobot(机器人)继承。

Procedure _OnBoardRego(Source : Pointer);

End;

{................................................................................}

Var

MessageRobot : TMessageRobot;//定义消息机器人变量。

{................................................................................}

Procedure TMessageRobot._OnBoardRego(Source : Pointer);

Begin

ShowInfo('做一些有趣的处理…(Doing something interesting...)');

//当图元被注册时做一些处理。

End;

{................................................................................}

Procedure RobotProcedure(Source, Destination : Pointer; MessageID : Word; Parameter : Pointer);

Begin

Case MessageID of

PCBM_BoardRegistration : MessageRobot._OnBoardRego(Source);

End;

End;

{................................................................................}

Procedure Command_RunRobotExample(Window : TServerWindow; Parameters : PChar);

Begin

End;

Initialization

MessageRobot := TMessageRobot.Create(

PCBApi_CreateRobot('Robot Example',RobotProcedure, 1000));

//PcbApi_CreateRobot函数使用给定的名称创建一个机器人,机器人过程抓取消息并且它的优先级设置被与在PCB编辑器机器人列表中的其它机器人的优先级比较。如果调用成功,则新的机器人的句柄被返回。

//TMessageRobot.Create创建一个消息机器人。

MessageRobot.RegisterWithSystem;

//注册机器人到在PCB编辑器的机器人列表中。

Finalization

MessageRobot.DeRegisterFromSystem;

//从PCB编辑器的机器人列表中删除此机器人。

MessageRobot.Free;//对象释放

End.

从此代码片段中,印制板图元消息处理被声明在TmessageRobot类中。此是独立的局部过程,RobotProcedure为回调过程,它捕捉所有PCB消息,然而,这里仅有一个消息处理者,印制板注册消息处理者,仅PCBM_BoardRegisteration消息将被此自定义的机器人“Robot Example”处理,此机器人的优先级为1000,因而任何优先级大于1000级别的机器人将被优先激活。

  6.5 例子

此例子SwapLayers说明需要使用机器人来在当对象的层属性发生改变时,通知PCB编辑器的数据结构。在此代码例子中,当例子服务器运行时线对象被使用,一个光标提示用户来点击一个线对象,不管此线对象是在顶层或底层,将被分别地改变到底层或顶层。

请见SDK例子\SAMPLES\NO4\API\PCB\SwapLayerRobot。

{................................................................................}

Procedure ReDrawCurrentBoard;

Var

P : PChar;

Begin

GetMem(P, 255);//创建一个动态的内存变量并且指针到内存块的地址,大小为255。

StrPCopy(P,'');//复制一个空字符到一个空值终止的字符串,即用空值初始化内存块。

SetState_Parameter(P,'Action','All');

//SetState_Parameter过程插入一个参数到指定的参数文本块中,为动作,参数为All。

MessageRouter_SendCommandToModule('PCB:Zoom',P,255,0);

//MessageRouter_SendCommandToModule函数运行指定的过程在指定的模块内,如果成功则返回True,否则返回Flase.此函数允许一个服务器来运行一个在其它服务器中的进程。即调用PCB服务器中的Zoom缩放进程。

FreeMem(P,255);//释放变量

End;

{................................................................................}

Procedure SwapLayersForTracks;

Var

BoardHandle : TObjectHandle;//印制板对象句柄

TrackHandle : TObjectHandle;//线对象句柄

Layer : TLayer;//层

Begin

If MessageRouter_GetState_WindowKind(PCBAPI_GetCurrentEditorWindow) <> 'PCB' Then Exit;

//PcbApi_GetCurrentEditorWindow函数返回文档对象窗体句柄。

// MessageRouter_GetState_WindowKind函数使用编辑器窗体句柄返回表示编辑器窗体类型的字符串值。例如,Advanced PCB 编辑器返回“PCB”字符串,并且TextEdit服务器返回“TEXT” 字符串。

BoardHandle := PcbApi_GetCurrentBoardhandle;

//PcbApi_GetCurrentBoardHandle函数返回当前在设计资源管理器中的PCB文档的句柄,如果印制板没有找到则返回值是空(nil)。

TrackHandle := -1;

While TrackHandle <> 0 Do

Begin

Trackhandle := PcbApi_GetObjectAtCursor(BoardHandle,//印制板句柄

[eTrackObject],//线对象类型

Alllayers,//所有层

'选择线对象(Select Track)');//提示

//PcbApi_GetObjectAtCursor函数返回所点击的对象的句柄,当此函数调动激活时,一个光标出现在印制板上来提示用户点击任何PCB对象,所能点击的PCB对象依赖于参数提供,此函数调用将返回所选择的PCB对象句柄。此函数依赖于底层函数PcbApi_GetObjectAtXYAskUserIfAmbiguous支持来提取指定的PCB对象。

If(Trackhandle <> 0) Then

Begin

//PcbApi_EventRouter_SendMessage过程发送消息到PCB编辑器来通知机器人PCB编辑器环境已被改变。

PcbApi_EventRouter_SendMessage(c_FromSystem, c_Broadcast,

PCBM_CycleStart, BoardHandle);

//发送消息,一个周期的开始

PcbApi_EventRouter_SendMessage(TrackHandle ,c_Broadcast,

PCBM_ProcessStart, c_NoEventData);

//发送消息,一个进程的开始。

PcbApi_EventRouter_SendMessage(TrackHandle ,c_Broadcast,

PCBM_BeginModify , c_NoEventData);

//发送消息,一个PCB对象将要被修改。

//以下代码执行对一个PCB对象的修改

Layer := GetObjectlayer(TrackHandle);//得到当前线对象的所在的层。

If(Layer = eTopLayer) Then SetObjectLayer(Trackhandle,eBottomLayer)

//如果是顶层则改为底层

Else If(Layer = eBottomLayer) Then SetObjectLayer(Trackhandle,eTopLayer);

//如果底层则改为顶层

PcbApi_EventRouter_SendMessage(TrackHandle ,c_Broadcast,

PCBM_EndModify, c_NoEventData);

//发送消息,一个PCB对象已被修改。

PcbApi_EventRouter_SendMessage(c_FromSystem ,c_Broadcast,

PCBM_YieldToRobots, c_NoEventData);

//发送消息,机器人被激活。

PcbApi_EventRouter_SendMessage(c_FromSystem,c_Broadcast,

PCBM_ProcessEnd , c_NoEventData);

//发送消息,一个进程的结束。

PcbApi_EventRouter_SendMessage(c_FromSystem,c_Broadcast,

PCBM_CycleEnd, c_NoEventData);

//发送消息,一个周期的结束。

ReDrawCurrentBoard;//重绘当前印制板

End;

End;

End;

这段代码做什么?

PcbApi_GetObjectAtCursor函数通过用户使用光标来在线对象上点击线对象,返回其句柄。PcbApi_EventRouter_SendMessage函数发送消息到PCB编辑器,在PCB编辑器中内部的机器人能响应并且做它们自己的处理,当内部的机器人得到这些PCB消息,并且每次更新特定的线对象时,PCB编辑器数据被通知到。

当修改一个PCB对象的层时,不是必须使用PCB编辑器的QueryDatabase(eSetState)方法,改变一个PCB对象的层更多的涉及到交换,例如此对象的颜色,这就是使用机器人的原因。

在此代码例子中,两个PCB消息被发送到PCB编辑器,来指示周期和线对象进程交换已开始。一个带有当前线对象句柄的PCBM_BeginModify消息被发送到PCB编辑器,实际的线对象的层从顶层交换到底层或反过来,一个带有新分配层的线对象的句柄的PCBM_EndModify消息接着被发送到PCB编辑器,PCBM_YieldToRobots消息被发送到PCB编辑器来指示PCB环境需要更新,其包含更新线对象的层属性,最后的两个消息是停止此活动的过程和周期。(e-works)

0
相关文章