接口的嵌入式实现

1.3层级建立

建立FB_Machine_HW_LOG使用ITF_Machine_HW_LOG自己的接口;

复制代码
FB_Machine_HW_LOG:


FUNCTION_BLOCK FB_Machine_HW_LOG IMPLEMENTS ITF_Machine_HW_LOG
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
		fbLogger	:	ITF_LoggerToDevLogAdapter	;//建立内部接口

内部:fbLogger : ITF_LoggerToDevLogAdapter ;//建立内部链接接口;

2.2层级的建立

以3层级构建类推:

建立FB_LoggerToDevLogAdapter 使用ITF_LoggerToDevLogAdapter 自己的接口

复制代码
FUNCTION_BLOCK FB_LoggerToDevLogAdapter IMPLEMENTS ITF_LoggerToDevLogAdapter
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
	ipSink				:	ITF_DevLogSink					;// 设备层 Log 下沉,由应用赋值为 FB_DevLogRouter 等
	

......
......
......
......
......
......
......
......
......
......

程序块:

(* 默认注入内部 Router,若未通过 M_SetSink 注入外部 Sink *)
IF NOT bSinkInjected THEN
    ipSink := fbDevLogRouter;
    bSinkInjected := TRUE;
END_IF

内部:ipSink : ITF_DevLogSink ;//建立内部链接接口;

3.1层级的建立

建立FB_DevLogRouter 使用ITF_DevLogSink自己的接口

复制代码
FUNCTION_BLOCK FB_DevLogRouter IMPLEMENTS ITF_DevLogSink
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
	iRingCount			:	UDINT							;// 缓存条数
	sPathWithOpt		:	WSTRING(96)						;// 设备路径 + 可选治具/载具/料盘
	sLineAssembled		:	WSTRING(255)						;// 组装后的单行 log
	fbLogRingBuffer		:	FB_StringRingBuffer				;// 环形缓存
	aRRsLogBuffer		:	ARRAY[1..100] OF WSTRING(255)	;// 缓存存储
	iLatesDisplayNum: DINT;
	
	//===========================================================================//
	itfLogger						:	ITF_Logger							;//日志	

内部: itfLogger : ITF_Logger ;//日志

4.0层级的建立

具体的的实现:

5.最终程序的实现

在最外部程序实现:

复制代码
FUNCTION_BLOCK FB_StationFoldDispensing
VAR_INPUT
......
......
VAR_OUTPUT
	
END_VAR
VAR
...........
...........				
	fbLog										:	FB_Logger										;//设备日志
	fbAoiHwLogAdapter							:	FB_LoggerToDevLogAdapter						;//AOI 模组-设备层日志适配
	fbAoiHwLogRouter							:	FB_DevLogRouter									;//AOI 设备日志下沉到 FB_Logger
	fbMachineHwLog								:	FB_Machine_HW_LOG								;//AOI 模组-硬件监视日志入口
	
	
//=============================================CommFB================================================//
......
......							
END_VAR

......
......
......
			
fbLog()																								;
fbLog.M_SaveFile(
				sFileName						:= 'Logs'											, 
				sRootDirPath					:= 'C:\UserRecord\DispensingStation'				);
				
//Aoi 硬件日志:适配器 Sink 用工站 Router,Router.pLogger 接本站 fbLog(勿用 ADR,接口直接赋实例)																		;
fbAoiHwLogRouter.pLogger							:=	fbLog										;
fbAoiHwLogAdapter.pDevLogSink						:=	fbAoiHwLogRouter							;
fbMachineHwLog.Prop_LoggerToDevLogAdapter				:=	fbAoiHwLogAdapter							;
fbModuleAoi.pMachine_HW_LOG							:=	fbMachineHwLog								;

参考三步法:

1.提供者->2.注入点->3.接收端本地缓存->4.最终调用落点

1.提供者:fbLog()

2.注入点:

fbAoiHwLogRouter.pLogger := fbLog ;

fbAoiHwLogAdapter.pDevLogSink := fbAoiHwLogRouter ;

fbMachineHwLog.Prop_LoggerToDevLogAdapter := fbAoiHwLogAdapter ;

fbModuleAoi.pMachine_HW_LOG := fbMachineHwLog ;

每个里面必须由属性传输出去:依次向下传输:

第一次:0层级给1层级注入:

fbAoiHwLogRouter.pLogger := fbLog ;//FB_Logger-0层级

第二次:1层级给2层级注入:

fbAoiHwLogAdapter.pDevLogSink := fbAoiHwLogRouter ;//FB_DevLogRouter-1层级

第三次:2层级给3层级注入:

fbMachineHwLog.Prop_LoggerToDevLogAdapter := fbAoiHwLogAdapter;//FB_LoggerToDevLogAdapter-2层级

第四次:3层级给最外部注入:

fbModuleAoi.pMachine_HW_LOG := fbMachineHwLog ;//FB_Machine_HW_LOG-3层级

3.接收本地缓存

外部调用:

4.最终落脚点

安全处理:

1) IF ipSink <> 0 THEN ... 是 Adapter 侧的"Sink 是否已注入"

FB_LoggerToDevLogAdapter.M_SubmitDevLog 里:

IF ipSink <> 0 THEN

ipSink.M_WriteDevLog(stLog);

END_IF

  • ipSink 的来源:要么你通过属性 pDevLogSink.Set 注入(ipSink := pDevLogSink;),要么(原设计)FB 本体那段默认注入把它指向内部 Router。
  • 理解:即使你"通常都会 set 属性",代码仍然要防御式写法,避免某个站点/某个时刻没注入就直接调用接口导致崩。

2) IF itfLogger <> 0 THEN ... 是 Router 侧的"最终 Logger 是否已注入"

FB_DevLogRouter.M_WriteDevLog 里:

IF itfLogger <> 0 THEN

itfLogger.M_LoggerWrite(wsToMsg:= sLineAssembled);

END_IF

  • itfLogger 的来源:你在工站里做的 fbAoiHwLogRouter.pLogger := fbLog;(这是 Router 的 pLogger.Set,内部是 itfLogger := pLogger;)。
  • 理解:即使 Adapter 已经把 ipSink 指到 Router 了,如果 Router 没接到底层 fbLog,同样也不能写。

3) 为什么"set 了就一定非 0"仍然要写判断?

因为 PLC 扫描周期里赋值、调用可能被别人改顺序/改条件,或者某些模式下不注入(比如某站点不需要落盘日志)。这两个 <>0 判断就是"链路上每一段都允许缺省为空,但为空就不做事、不报错"。

一句话总结

  • 属性 set 是"你主动接线";
  • IF ipSink <> 0 / IF itfLogger <> 0 是"就算你没接线,也不要崩溃,只是这条日志不输出"。
相关推荐
卷无止境几秒前
SigV4与HTTPS,两套完全不同维度的安全机制
后端·python·fastapi
青石路2 分钟前
好好的OceanBase官方驱动你不用,非要用第三方驱动,ArrayIndexOutOfBoundsException了吧
java·后端
长谷深风1114 分钟前
读懂 MCP:能力、传输与多 Server 连接
java·大数据·ai·ai agent·mcp·streamable http·agent设计
深念Y6 分钟前
Makefile vs go run:Go 项目构建方式对比
java·开发语言·golang·k8s·编译·流水线·cicd
我命由我1234516 分钟前
Android Camera - 获取当前设备屏幕的旋转角度、保存帧到外部存储的私有空间
android·java·开发语言·java-ee·android jetpack·android-studio·android runtime
深念Y17 分钟前
微服务抽取路线图:从胖单体到 ARM 集群
前端·arm开发·数据库·后端·微服务·云原生·架构
苏灿烤鱼18 分钟前
一个用 Nim 写的隐私优先 Twitter 替代前端,源码级技术剖析
后端·github·twitter
niuniudengdeng30 分钟前
从小程序到 WebView:一个理发店管理系统的全栈架构设计与落地实践
java·python
LccKyI37 分钟前
C#基础编程 面试题汇总(二)
java·面试·c#
灯澜忆梦38 分钟前
【基于GO的Web开发14】gin请求重定向
前端·后端·golang·gin