【仓颉】二、一个仓颉的Modbus库-2. Modbus基础类:abstract class ModbusBase

首先定义基础Modbus类的数据为BaseData。var baseData= Array<Byte>()。baseData暂时不在意链路层CRC与ModbusTCP的头包,只考虑Modbus应用部分。

出现第一个考虑:链路层需要最终给数组装配外壳。baseData需要由链路层决定最终的数组长度与内容。因此,baseData设计为链路管理。并采用ILinkLayer接口类型的私有变量linkLayer作为链路层,后续链路层中细节设计。

var linkLayer : ILinkLayer

Modbus由基本信息:Command和ID,其中ID占baseData的第0与第1个byte,特别适合用属性实现:

    //Modbus报文帧的地址ID
    public mut prop Id: UInt8 {
        get() {
            linkLayer.BaseData.getUInt8(0)
        }
        set(value) {
            linkLayer.BaseData.setUInt8(0,value)
        }
    }
    //Modbus报文帧的命令字
    public mut prop Command: UInt8 {
        get() {
            linkLayer.BaseData.getUInt8(1)
        }
        set(value) {
            linkLayer.BaseData.setUInt8(1,value)
        }
    }

此处看到仓颉的get、set方法与C#有很大的相似,但写的方式相比于C#更严格(死板)一些。缺失:get和set无法分别设置方位级别。

需要set时,属性需要定义mut。这里的关键字有些rust的影子。

GetUInt8与SetUInt8为自定义的数组扩展方法,作用为:1:判断数组是否满足长度要求。2:存取一个指定类型数据到数组的指定位置。

继续设计当前类。

后续的子类不再管数组的前两个字节。因此截取好后续的内容给各子类使用。我们发现,数组的切片也是引用方式,对切片的修改会影响原数组的元素。

    //取出内容部分。仅在继承子类中可用
    protected prop Content : Array<UInt8>{
        get(){          
            @LenCheckThrow(linkLayer.BaseData.size <= 3)
            linkLayer.BaseData[2..]
        }
    }

@LenCheckThrow(linkLayer.BaseData.size <= 3)是我们自定义的一个宏,用于检测数组长度并判断是否需要抛出异常(也是测试宏的使用)

这里数组使用了类似切片的方法。仓颉目前的数组切片采用[起始索引:终点索引]的方式。其中索引的截取方案参考文档的区间类型。格式是 start..end : step,它表示一个从 start 开始,以 step 为步长,到 end(不包含 end)为止的区间;“左闭右闭”区间的格式是 start..=end : step,它表示一个从 start 开始,以 step 为步长,到 end(包含 end)为止的区间。

例:

let n = 10

let r1 = 0..10 : 1   // r1 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

let r2 = 0..=n : 1   // r2 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

let r3 = n..0 : -2   // r3 contains 10, 8, 6, 4, 2

let r4 = 10..=0 : -2 // r4 contains 10, 8, 6, 4, 2, 0

本类需要一个ToArray函数,用于输出最终数组。但最终数组将由链路层提供:

    public func toArray() : Array<UInt8>{
        linkLayer.getFrameData()
    }

最后定义两个构造函数,分别从命令创建,以及从数组创建:

    init(id:UInt8,command:UInt8,initLen:UInt8,linkLayer:ILinkLayer) {
        this.linkLayer = linkLayer
        this.linkLayer.initLen(initLen)
        linkLayer.BaseData.setUInt8(0,id)
        linkLayer.BaseData.setUInt8(1,command)
    }
    init(buffer : Array<Byte>,linkLayer:ILinkLayer) {
        this.linkLayer = linkLayer
        this.linkLayer.setBuffer(buffer)
    }

构造函数使用init方式,看起来由python的影子,感觉上比go强制没有构造函数的方式,在设计类的时候舒服多了。

好了,本届遗留两个问题:1:对数组扩展方法。2:宏的使用。

使用了以后会设计制作的一个重要的类:ILinkLayer

下一节我们介绍数组的扩展方法。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值