modbusrtu.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. package main
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "time"
  8. "github.com/thinkgos/timing/v3"
  9. "lc/common/mqtt"
  10. "lc/common/protocol"
  11. "lc/common/util"
  12. "lc/edge/ipole/modbus"
  13. )
  14. var ModbusRtuProtocol = "ModbusRTU"
  15. var ErrInvalidFunccode = errors.New("invalid function code")
  16. const (
  17. rtuExceptionSize = 5
  18. DefaultReadyQueuesLength = 256
  19. )
  20. type Request struct {
  21. Rtuinfo *protocol.DevInfo //RTU信息
  22. CID uint8 //cid->采集命令,下发给设备的命令
  23. FuncCode byte // 功能码
  24. Address uint16 // 请求数据用实际地址
  25. Quantity uint16 // 请求数量
  26. ScanRate time.Duration // 扫描速率scan rate
  27. TxCnt uint64 // 发送计数
  28. ErrCnt uint64 // 发送错误计数
  29. tmHandler func()
  30. }
  31. type ModbusRtu struct {
  32. reqList []*Request
  33. devInfo *protocol.DevInfo
  34. model *protocol.IotModel
  35. ready chan *Request
  36. ctx context.Context
  37. cancel context.CancelFunc
  38. chanDevInfo chan *protocol.DevInfo //设备管理更新
  39. chanModelInfo chan *ModelInfo //设备管理更新
  40. }
  41. func NewModbusRtu(info *protocol.DevInfo) Device {
  42. ctx, cancel := context.WithCancel(context.Background())
  43. rtu := &ModbusRtu{
  44. devInfo: info,
  45. ready: make(chan *Request, DefaultReadyQueuesLength),
  46. ctx: ctx,
  47. cancel: cancel,
  48. chanDevInfo: make(chan *protocol.DevInfo),
  49. chanModelInfo: make(chan *ModelInfo),
  50. }
  51. iot, err := loadModel(info.TID)
  52. if err != nil {
  53. return nil
  54. }
  55. if iot.Protocol == ModbusRtuProtocol {
  56. rtu.model = iot
  57. }
  58. mapRtuUploadManager.Store(info.DevCode, NewRtuUploadManager(info))
  59. return rtu
  60. }
  61. func (o *ModbusRtu) Start() {
  62. GetMQTTMgr().Subscribe(GetTopic(o.GetDevType(), o.devInfo.DevCode, protocol.TP_MODBUS_CONTROL), mqtt.ExactlyOnce, o.HandleTpWControl, ToAll)
  63. go o.HandleData()
  64. }
  65. func (o *ModbusRtu) Stop() {
  66. //停止采集和处理
  67. o.cancel()
  68. //停止上传
  69. if value, ok := mapRtuUploadManager.Load(o.devInfo.DevCode); ok {
  70. uploadManager := value.(*RtuUploadManager)
  71. if uploadManager != nil {
  72. uploadManager.Stop()
  73. }
  74. }
  75. }
  76. func (o *ModbusRtu) UpdateInfo(devInfo protocol.DevInfo) {
  77. o.chanDevInfo <- &devInfo
  78. }
  79. func (o *ModbusRtu) GetDevInfo() *protocol.DevInfo {
  80. return o.devInfo
  81. }
  82. func (o *ModbusRtu) UpdateModel(tid uint16, flag int) {
  83. if tid > 0 {
  84. mi := ModelInfo{
  85. TID: tid,
  86. Flag: flag,
  87. }
  88. o.chanModelInfo <- &mi
  89. }
  90. }
  91. func (o *ModbusRtu) UpdateModel2(mi *ModelInfo) {
  92. if o.devInfo.TID != mi.TID {
  93. return
  94. }
  95. if mi.Flag == 0 {
  96. return
  97. }
  98. iot, err := loadModel(mi.TID)
  99. if err != nil {
  100. return
  101. }
  102. if iot.Protocol == ModbusRtuProtocol { //合法的物模型
  103. o.model = iot
  104. o.clearRequest()
  105. o.updateRequest()
  106. }
  107. }
  108. func (o *ModbusRtu) GetDevType() string {
  109. if o.devInfo.DevType == 1 {
  110. return protocol.DT_CONCENTRATOR
  111. } else if o.devInfo.DevType == 2 {
  112. return protocol.DT_ENVIRONMENT
  113. } else if o.devInfo.DevType == 4 {
  114. return protocol.DT_LIQUID
  115. } else if o.devInfo.DevType == 5 {
  116. return protocol.DT_ROAD_COND
  117. }
  118. return "unknown"
  119. }
  120. // HandleData 数据处理协程
  121. func (o *ModbusRtu) HandleData() {
  122. defer func() {
  123. recover()
  124. go o.HandleData()
  125. }()
  126. o.updateRequest()
  127. var req *Request
  128. for {
  129. select {
  130. case <-o.ctx.Done():
  131. return
  132. case info := <-o.chanDevInfo:
  133. o.devInfo = info
  134. case mi := <-o.chanModelInfo:
  135. o.UpdateModel2(mi) //物模型配置文件更新
  136. case req = <-o.ready: //查看是否有准备好的请求
  137. o.procRequest(req)
  138. default:
  139. time.Sleep(time.Millisecond * 100)
  140. }
  141. }
  142. }
  143. func (o *ModbusRtu) clearRequest() {
  144. for _, v := range o.reqList {
  145. v.ScanRate = 0 //置为0,则不再执行新请求
  146. }
  147. o.reqList = nil
  148. }
  149. func (o *ModbusRtu) updateRequest() {
  150. for k, v := range o.model.Packet {
  151. r := Request{CID: k, Rtuinfo: o.devInfo, FuncCode: v.Code, Address: v.Addr,
  152. Quantity: v.Quantity, ScanRate: time.Duration(v.Cycle) * time.Millisecond,
  153. }
  154. if err := o.AddGatherJob(&r); err == nil {
  155. o.reqList = append(o.reqList, &r)
  156. }
  157. }
  158. }
  159. // AddGatherJob 增加采集任务
  160. func (o *ModbusRtu) AddGatherJob(r *Request) error {
  161. if err := o.ctx.Err(); err != nil {
  162. return err
  163. }
  164. if r.Rtuinfo.DevID < modbus.AddressMin || r.Rtuinfo.DevID > modbus.AddressMax {
  165. return fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  166. r.Rtuinfo.DevID, modbus.AddressMin, modbus.AddressMax)
  167. }
  168. if r.FuncCode == modbus.FuncCodeReadCoils || r.FuncCode == modbus.FuncCodeReadDiscreteInputs ||
  169. r.FuncCode == modbus.FuncCodeReadInputRegisters || r.FuncCode == modbus.FuncCodeReadHoldingRegisters {
  170. r.tmHandler = func() {
  171. select {
  172. case <-o.ctx.Done():
  173. return
  174. case o.ready <- r:
  175. default:
  176. timing.AddJobFunc(r.tmHandler, r.ScanRate*time.Millisecond)
  177. }
  178. }
  179. timing.AddJobFunc(r.tmHandler, r.ScanRate)
  180. } else {
  181. return ErrInvalidFunccode
  182. }
  183. return nil
  184. }
  185. func (o *ModbusRtu) ProcReadCoils(cid uint8, address, quality uint16, valBuf []byte) {
  186. }
  187. func (o *ModbusRtu) ReadDiscrete(cid uint8, address, quality uint16, valBuf []byte) {
  188. }
  189. func (o *ModbusRtu) ProcReadHoldingRegisters(cid uint8, address, quality uint16, valBuf []byte) {
  190. dataLen := len(valBuf)
  191. if o.model.Packet[cid].Resplen != uint(dataLen) {
  192. return
  193. }
  194. dataMap := make(map[uint16]float64)
  195. for _, v := range o.model.DataUp {
  196. if v.Cid != cid || v.Len == 0 {
  197. continue
  198. }
  199. if int(v.Start+v.Len) > dataLen { //索引超长,忽略该项目
  200. continue
  201. }
  202. var fVal float64
  203. strVal := valBuf[v.Start : v.Start+v.Len]
  204. if v.Len == 2 {
  205. var u16 uint16
  206. if v.Endian == 0 { //大端
  207. u16 = binary.BigEndian.Uint16(strVal)
  208. } else { //小端
  209. u16 = binary.LittleEndian.Uint16(strVal)
  210. }
  211. if v.Type == 0 { //处理符号
  212. fVal = float64(u16)
  213. } else {
  214. fVal = float64(int16(u16))
  215. }
  216. } else if v.Len == 4 {
  217. if v.Endian == 0 {
  218. fVal = float64(util.BEByteToFloat32(strVal))
  219. } else {
  220. fVal = float64(util.LEByteToFloat32(strVal))
  221. }
  222. } else if v.Len == 1 {
  223. if v.Type == 0 { //处理符号
  224. fVal = float64(strVal[0])
  225. } else {
  226. fVal = float64(int8(strVal[0]))
  227. }
  228. }
  229. if v.Ratio > 0 {
  230. fVal = fVal / float64(v.Ratio)
  231. }
  232. fVal = fVal - float64(v.Base)
  233. if v.Type == 0 || v.Type == 1 { //整数
  234. dataMap[v.SID] = Precision(fVal, 0, true)
  235. } else if v.Type == 2 || v.Type == 3 { //浮点数
  236. dataMap[v.SID] = Precision(fVal, 3, false)
  237. }
  238. }
  239. if value, ok := mapRtuUploadManager.Load(o.devInfo.DevCode); ok {
  240. uploadManager := value.(*RtuUploadManager)
  241. if uploadManager != nil {
  242. uploadManager.AddData(dataMap)
  243. }
  244. }
  245. }
  246. func (o *ModbusRtu) ProcReadInputRegisters(cid uint8, address, quality uint16, valBuf []byte) {
  247. dataLen := len(valBuf)
  248. if o.model.Packet[cid].Resplen != uint(dataLen) {
  249. return
  250. }
  251. dataMap := make(map[uint16]float64)
  252. for _, v := range o.model.DataUp {
  253. if v.Cid != cid || v.Len == 0 {
  254. continue
  255. }
  256. if int(v.Start+v.Len) > dataLen { //索引超长,忽略该项目
  257. continue
  258. }
  259. var fVal float64
  260. strVal := valBuf[v.Start : v.Start+v.Len]
  261. if v.Len == 2 {
  262. var u16 uint16
  263. if v.Endian == 0 { //大端
  264. u16 = binary.BigEndian.Uint16(strVal)
  265. } else { //小端
  266. u16 = binary.LittleEndian.Uint16(strVal)
  267. }
  268. if v.Type == 0 { //处理符号
  269. fVal = float64(u16)
  270. } else {
  271. fVal = float64(int16(u16))
  272. }
  273. } else if v.Len == 4 {
  274. if v.Endian == 0 {
  275. fVal = float64(util.BEByteToFloat32(strVal))
  276. } else {
  277. fVal = float64(util.LEByteToFloat32(strVal))
  278. }
  279. } else if v.Len == 1 {
  280. if v.Type == 0 { //处理符号
  281. fVal = float64(strVal[0])
  282. } else {
  283. fVal = float64(int8(strVal[0]))
  284. }
  285. }
  286. if v.Ratio > 0 {
  287. fVal = fVal / float64(v.Ratio)
  288. }
  289. fVal = fVal - float64(v.Base)
  290. if v.Type == 0 || v.Type == 1 { //整数
  291. dataMap[v.SID] = Precision(fVal, 0, true)
  292. } else if v.Type == 2 || v.Type == 3 { //浮点数
  293. dataMap[v.SID] = Precision(fVal, 3, false)
  294. }
  295. }
  296. if value, ok := mapRtuUploadManager.Load(o.devInfo.DevCode); ok {
  297. uploadManager := value.(*RtuUploadManager)
  298. if uploadManager != nil {
  299. uploadManager.AddData(dataMap)
  300. }
  301. }
  302. }
  303. func (o *ModbusRtu) ProcResult(err error, req *Request) {
  304. if err == nil {
  305. if req.ErrCnt > 0 {
  306. req.ErrCnt = 0
  307. }
  308. } else {
  309. //连续采集超过5次都错误,则报告设备离线
  310. if req.ErrCnt == 5 {
  311. //离线状态报告
  312. var obj protocol.Pack_UploadData
  313. if str, err := obj.EnCode(req.Rtuinfo.DevCode, appConfig.GID, GetNextUint64(), err, req.Rtuinfo.TID, nil); err == nil {
  314. topic := GetTopic(o.GetDevType(), req.Rtuinfo.DevCode, protocol.TP_MODBUS_DATA)
  315. GetMQTTMgr().Publish(topic, str, 0, ToAll)
  316. }
  317. }
  318. }
  319. }
  320. func (o *ModbusRtu) procRequest(req *Request) {
  321. var err error
  322. var result []byte
  323. defer func() {
  324. recover()
  325. }()
  326. req.TxCnt++
  327. switch req.FuncCode {
  328. // A bit of access read
  329. case modbus.FuncCodeReadCoils:
  330. result, err = o.ReadCoils(req.Rtuinfo.DevID, req.Address, req.Quantity)
  331. if err == nil {
  332. o.ProcReadCoils(req.CID, req.Address, req.Quantity, result)
  333. }
  334. case modbus.FuncCodeReadDiscreteInputs:
  335. result, err = o.ReadDiscreteInputs(req.Rtuinfo.DevID, req.Address, req.Quantity)
  336. if err == nil {
  337. o.ReadDiscrete(req.CID, req.Address, req.Quantity, result)
  338. }
  339. // 16-bit access read
  340. case modbus.FuncCodeReadHoldingRegisters: //03
  341. result, err = o.ReadHoldingRegistersBytes(req.Rtuinfo.DevID, req.Address, req.Quantity)
  342. if err == nil {
  343. o.ProcReadHoldingRegisters(req.CID, req.Address, req.Quantity, result)
  344. }
  345. case modbus.FuncCodeReadInputRegisters:
  346. result, err = o.ReadInputRegistersBytes(req.Rtuinfo.DevID, req.Address, req.Quantity)
  347. if err == nil {
  348. o.ProcReadInputRegisters(req.CID, req.Address, req.Quantity, result)
  349. }
  350. }
  351. if err != nil {
  352. req.ErrCnt++
  353. }
  354. o.ProcResult(err, req)
  355. if req.ScanRate > 0 {
  356. timing.AddJobFunc(req.tmHandler, req.ScanRate)
  357. }
  358. }
  359. func (o *ModbusRtu) HandleTpWControl(m mqtt.Message) {
  360. var obj protocol.Pack_ControlData
  361. var ret protocol.Pack_Ack
  362. var err error
  363. if err = obj.DeCode(m.PayloadString()); err == nil {
  364. if v, ok := o.model.DataDown[obj.Data.Sid]; ok {
  365. var data []byte
  366. if v.Vallen == 1 { //1个字节
  367. data = make([]byte, 1, 1)
  368. data = append(data, byte(obj.Data.Val))
  369. } else if v.Vallen == 2 { //2个字节
  370. data = make([]byte, 2, 2)
  371. binary.BigEndian.PutUint16(data, uint16(obj.Data.Val))
  372. } else if v.Vallen == 4 {
  373. data = make([]byte, 4, 4)
  374. binary.BigEndian.PutUint32(data, uint32(obj.Data.Val))
  375. }
  376. err = o.WriteData(o.devInfo.DevID, v.Code, v.Addr, v.Quantity, data)
  377. } else {
  378. err = errors.New(fmt.Sprintf("物模型[TID=%d]未配置该SID[sid=%d],请确保模型文件存在", obj.Data.Tid, obj.Data.Sid))
  379. }
  380. }
  381. if str, err := ret.EnCode(o.devInfo.DevCode, appConfig.GID, obj.Seq, err); err == nil {
  382. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.devInfo.DevCode, protocol.TP_MODBUS_CONTROL_ACK), str, 0, ToAll)
  383. }
  384. }
  385. func (o *ModbusRtu) WriteData(slaveID, funcCode byte, address, quantity uint16, value []byte) error {
  386. var err error
  387. defer func() {
  388. recover()
  389. }()
  390. switch funcCode {
  391. case modbus.FuncCodeWriteSingleCoil: //5
  392. var isOn = false
  393. if len(value) != 2 {
  394. return errors.New("数据长度不对")
  395. }
  396. if binary.BigEndian.Uint16(value) > 0 {
  397. isOn = true
  398. }
  399. err = o.WriteSingleCoil(slaveID, address, isOn)
  400. case modbus.FuncCodeWriteMultipleCoils: //15
  401. err = o.WriteMultipleCoils(slaveID, address, quantity, value)
  402. case modbus.FuncCodeWriteSingleRegister: //6
  403. err = o.WriteSingleRegister(slaveID, address, binary.BigEndian.Uint16(value))
  404. case modbus.FuncCodeWriteMultipleRegisters: //16
  405. err = o.WriteMultipleRegistersBytes(slaveID, address, quantity, value)
  406. default:
  407. err = errors.New("不支持的功能码")
  408. }
  409. return err
  410. }
  411. func (o *ModbusRtu) SendRecvData(aduRequest []byte) (aduResponse []byte, err error) {
  412. serial := GetSerialMgr().GetSerialPort(o.devInfo.Code)
  413. if serial == nil {
  414. return nil, ErrClosedConnection
  415. }
  416. return serial.SendRecvData(aduRequest, FlagModbusRtu, o.devInfo.WaitTime)
  417. }
  418. // Send request to the remote server, it implements on SendRawFrame
  419. func (o *ModbusRtu) Send(slaveID byte, request modbus.ProtocolDataUnit) (modbus.ProtocolDataUnit, error) {
  420. var response modbus.ProtocolDataUnit
  421. aduRequest, err := modbus.EncodeRTUFrame(slaveID, request)
  422. if err != nil {
  423. return response, err
  424. }
  425. aduResponse, err := o.SendRecvData(aduRequest)
  426. if err != nil {
  427. return response, err
  428. }
  429. rspSlaveID, pdu, err := modbus.DecodeRTUFrame(aduResponse)
  430. if err != nil {
  431. return response, err
  432. }
  433. response = modbus.ProtocolDataUnit{FuncCode: pdu[0], Data: pdu[1:]}
  434. return response, modbus.Verify(slaveID, rspSlaveID, request, response)
  435. }
  436. // SendPdu send pdu request to the remote server
  437. func (o *ModbusRtu) SendPdu(slaveID byte, pduRequest []byte) ([]byte, error) {
  438. if len(pduRequest) < modbus.PduMinSize || len(pduRequest) > modbus.PduMaxSize {
  439. return nil, fmt.Errorf("modbus: pdu size '%v' must not be between '%v' and '%v'", len(pduRequest), modbus.PduMinSize, modbus.PduMaxSize)
  440. }
  441. request := modbus.ProtocolDataUnit{FuncCode: pduRequest[0], Data: pduRequest[1:]}
  442. requestAdu, err := modbus.EncodeRTUFrame(slaveID, request)
  443. if err != nil {
  444. return nil, err
  445. }
  446. aduResponse, err := o.SendRecvData(requestAdu)
  447. if err != nil {
  448. return nil, err
  449. }
  450. rspSlaveID, pdu, err := modbus.DecodeRTUFrame(aduResponse)
  451. if err != nil {
  452. return nil, err
  453. }
  454. // PDU pass slaveID & crc
  455. return pdu, modbus.Verify(slaveID, rspSlaveID, request, modbus.ProtocolDataUnit{FuncCode: pdu[0], Data: pdu[1:]})
  456. }
  457. // ReadCoils Request:
  458. //
  459. // Slave ID : 1 byte
  460. // Function code : 1 byte (0x01)
  461. // Starting address : 2 bytes
  462. // Quantity of coils : 2 bytes
  463. //
  464. // Response:
  465. //
  466. // Function code : 1 byte (0x01)
  467. // Byte count : 1 byte
  468. // Coil status : N* bytes (=N or N+1)
  469. // return coils status
  470. func (o *ModbusRtu) ReadCoils(slaveID byte, address, quantity uint16) ([]byte, error) {
  471. if slaveID < modbus.AddressMin || slaveID > modbus.AddressMax {
  472. return nil, fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  473. slaveID, modbus.AddressMin, modbus.AddressMax)
  474. }
  475. if quantity < modbus.ReadBitsQuantityMin || quantity > modbus.ReadBitsQuantityMax {
  476. return nil, fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v'",
  477. quantity, modbus.ReadBitsQuantityMin, modbus.ReadBitsQuantityMax)
  478. }
  479. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{FuncCode: modbus.FuncCodeReadCoils, Data: uint162Bytes(address, quantity)})
  480. switch {
  481. case err != nil:
  482. return nil, err
  483. case len(response.Data)-1 != int(response.Data[0]):
  484. return nil, fmt.Errorf("modbus: response byte size '%v' does not match count '%v'",
  485. len(response.Data)-1, int(response.Data[0]))
  486. case uint16(response.Data[0]) != (quantity+7)/8:
  487. return nil, fmt.Errorf("modbus: response byte size '%v' does not match quantity to bytes '%v'",
  488. response.Data[0], (quantity+7)/8)
  489. }
  490. return response.Data[1:], nil
  491. }
  492. // ReadDiscreteInputs Request:
  493. //
  494. // Slave ID : 1 byte
  495. // Function code : 1 byte (0x02)
  496. // Starting address : 2 bytes
  497. // Quantity of inputs : 2 bytes
  498. //
  499. // Response:
  500. //
  501. // Function code : 1 byte (0x02)
  502. // Byte count : 1 byte
  503. // Input status : N* bytes (=N or N+1)
  504. // return result data
  505. func (o *ModbusRtu) ReadDiscreteInputs(slaveID byte, address, quantity uint16) ([]byte, error) {
  506. if slaveID < modbus.AddressMin || slaveID > modbus.AddressMax {
  507. return nil, fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  508. slaveID, modbus.AddressMin, modbus.AddressMax)
  509. }
  510. if quantity < modbus.ReadBitsQuantityMin || quantity > modbus.ReadBitsQuantityMax {
  511. return nil, fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v'",
  512. quantity, modbus.ReadBitsQuantityMin, modbus.ReadBitsQuantityMax)
  513. }
  514. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  515. FuncCode: modbus.FuncCodeReadDiscreteInputs,
  516. Data: uint162Bytes(address, quantity),
  517. })
  518. switch {
  519. case err != nil:
  520. return nil, err
  521. case len(response.Data)-1 != int(response.Data[0]):
  522. return nil, fmt.Errorf("modbus: response byte size '%v' does not match count '%v'",
  523. len(response.Data)-1, response.Data[0])
  524. case uint16(response.Data[0]) != (quantity+7)/8:
  525. return nil, fmt.Errorf("modbus: response byte size '%v' does not match quantity to bytes '%v'",
  526. response.Data[0], (quantity+7)/8)
  527. }
  528. return response.Data[1:], nil
  529. }
  530. // WriteSingleCoil Request:
  531. //
  532. // Slave Id : 1 byte
  533. // Function code : 1 byte (0x05)
  534. // Output address : 2 bytes
  535. // Output value : 2 bytes
  536. //
  537. // Response:
  538. //
  539. // Function code : 1 byte (0x05)
  540. // Output address : 2 bytes
  541. // Output value : 2 bytes
  542. func (o *ModbusRtu) WriteSingleCoil(slaveID byte, address uint16, isOn bool) error {
  543. if slaveID > modbus.AddressMax {
  544. return fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  545. slaveID, modbus.AddressBroadCast, modbus.AddressMax)
  546. }
  547. var value uint16
  548. if isOn { // The requested ON/OFF state can only be 0xFF00 and 0x0000
  549. value = 0xFF00
  550. }
  551. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  552. FuncCode: modbus.FuncCodeWriteSingleCoil,
  553. Data: uint162Bytes(address, value),
  554. })
  555. switch {
  556. case err != nil:
  557. return err
  558. case len(response.Data) != 4:
  559. // Fixed response length
  560. return fmt.Errorf("modbus: response data size '%v' does not match expected '%v'",
  561. len(response.Data), 4)
  562. case binary.BigEndian.Uint16(response.Data) != address:
  563. // check address
  564. return fmt.Errorf("modbus: response address '%v' does not match request '%v'",
  565. binary.BigEndian.Uint16(response.Data), address)
  566. case binary.BigEndian.Uint16(response.Data[2:]) != value:
  567. // check value
  568. return fmt.Errorf("modbus: response value '%v' does not match request '%v'",
  569. binary.BigEndian.Uint16(response.Data[2:]), value)
  570. }
  571. return nil
  572. }
  573. // WriteMultipleCoils Request:
  574. //
  575. // Slave ID : 1 byte
  576. // Function code : 1 byte (0x0F)
  577. // Starting address : 2 bytes
  578. // Quantity of outputs : 2 bytes
  579. // Byte count : 1 byte
  580. // Outputs value : N* bytes
  581. //
  582. // Response:
  583. //
  584. // Function code : 1 byte (0x0F)
  585. // Starting address : 2 bytes
  586. // Quantity of outputs : 2 bytes
  587. func (o *ModbusRtu) WriteMultipleCoils(slaveID byte, address, quantity uint16, value []byte) error {
  588. if slaveID > modbus.AddressMax {
  589. return fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  590. slaveID, modbus.AddressBroadCast, modbus.AddressMax)
  591. }
  592. if quantity < modbus.WriteBitsQuantityMin || quantity > modbus.WriteBitsQuantityMax {
  593. return fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v'",
  594. quantity, modbus.WriteBitsQuantityMin, modbus.WriteBitsQuantityMax)
  595. }
  596. if len(value)*8 < int(quantity) {
  597. return fmt.Errorf("modbus: value bits size '%v' does not greater or equal to quantity '%v'", len(value)*8, quantity)
  598. }
  599. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  600. FuncCode: modbus.FuncCodeWriteMultipleCoils,
  601. Data: pduDataBlockSuffix(value, address, quantity),
  602. })
  603. switch {
  604. case err != nil:
  605. return err
  606. case len(response.Data) != 4:
  607. // Fixed response length
  608. return fmt.Errorf("modbus: response data size '%v' does not match expected '%v'",
  609. len(response.Data), 4)
  610. case binary.BigEndian.Uint16(response.Data) != address:
  611. return fmt.Errorf("modbus: response address '%v' does not match request '%v'",
  612. binary.BigEndian.Uint16(response.Data), address)
  613. case binary.BigEndian.Uint16(response.Data[2:]) != quantity:
  614. return fmt.Errorf("modbus: response quantity '%v' does not match request '%v'",
  615. binary.BigEndian.Uint16(response.Data[2:]), quantity)
  616. }
  617. return nil
  618. }
  619. /*********************************16-bits**************************************/
  620. // ReadInputRegistersBytes Request:
  621. //
  622. // Slave ID : 1 byte
  623. // Function code : 1 byte (0x04)
  624. // Starting address : 2 bytes
  625. // Quantity of registers : 2 bytes
  626. //
  627. // Response:
  628. //
  629. // Function code : 1 byte (0x04)
  630. // Byte count : 1 byte
  631. // Input registers : Nx2 bytes
  632. func (o *ModbusRtu) ReadInputRegistersBytes(slaveID byte, address, quantity uint16) ([]byte, error) {
  633. if slaveID < modbus.AddressMin || slaveID > modbus.AddressMax {
  634. return nil, fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  635. slaveID, modbus.AddressMin, modbus.AddressMax)
  636. }
  637. if quantity < modbus.ReadRegQuantityMin || quantity > modbus.ReadRegQuantityMax {
  638. return nil, fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v'",
  639. quantity, modbus.ReadRegQuantityMin, modbus.ReadRegQuantityMax)
  640. }
  641. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  642. FuncCode: modbus.FuncCodeReadInputRegisters,
  643. Data: uint162Bytes(address, quantity),
  644. })
  645. switch {
  646. case err != nil:
  647. return nil, err
  648. case len(response.Data)-1 != int(response.Data[0]):
  649. return nil, fmt.Errorf("modbus: response data size '%v' does not match count '%v'",
  650. len(response.Data)-1, response.Data[0])
  651. case uint16(response.Data[0]) != quantity*2:
  652. return nil, fmt.Errorf("modbus: response data size '%v' does not match quantity to bytes '%v'",
  653. response.Data[0], quantity*2)
  654. }
  655. return response.Data[1:], nil
  656. }
  657. // ReadInputRegisters Request:
  658. //
  659. // Slave ID : 1 byte
  660. // Function code : 1 byte (0x04)
  661. // Starting address : 2 bytes
  662. // Quantity of registers : 2 bytes
  663. //
  664. // Response:
  665. //
  666. // Function code : 1 byte (0x04)
  667. // Byte count : 1 byte
  668. // Input registers : N 2-bytes
  669. func (o *ModbusRtu) ReadInputRegisters(slaveID byte, address, quantity uint16) ([]uint16, error) {
  670. b, err := o.ReadInputRegistersBytes(slaveID, address, quantity)
  671. if err != nil {
  672. return nil, err
  673. }
  674. return bytes2Uint16(b), nil
  675. }
  676. // ReadHoldingRegistersBytes Request:
  677. //
  678. // Slave ID : 1 byte
  679. // Function code : 1 byte (0x03)
  680. // Starting address : 2 bytes
  681. // Quantity of registers : 2 bytes
  682. //
  683. // Response:
  684. //
  685. // Function code : 1 byte (0x03)
  686. // Byte count : 1 byte
  687. // Register value : Nx2 bytes
  688. func (o *ModbusRtu) ReadHoldingRegistersBytes(slaveID byte, address, quantity uint16) ([]byte, error) {
  689. if slaveID < modbus.AddressMin || slaveID > modbus.AddressMax {
  690. return nil, fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  691. slaveID, modbus.AddressMin, modbus.AddressMax)
  692. }
  693. if quantity < modbus.ReadRegQuantityMin || quantity > modbus.ReadRegQuantityMax {
  694. return nil, fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v'",
  695. quantity, modbus.ReadRegQuantityMin, modbus.ReadRegQuantityMax)
  696. }
  697. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  698. FuncCode: modbus.FuncCodeReadHoldingRegisters,
  699. Data: uint162Bytes(address, quantity),
  700. })
  701. switch {
  702. case err != nil:
  703. return nil, err
  704. case len(response.Data)-1 != int(response.Data[0]):
  705. return nil, fmt.Errorf("modbus: response data size '%v' does not match count '%v'",
  706. len(response.Data)-1, response.Data[0])
  707. //case uint16(response.Data[0]) != quantity*2:
  708. // return nil, fmt.Errorf("modbus: response data size '%v' does not match quantity to bytes '%v'",
  709. // response.Data[0], quantity*2)
  710. }
  711. return response.Data[1:], nil
  712. }
  713. // ReadHoldingRegisters Request:
  714. //
  715. // Slave ID : 1 byte
  716. // Function code : 1 byte (0x03)
  717. // Starting address : 2 bytes
  718. // Quantity of registers : 2 bytes
  719. //
  720. // Response:
  721. //
  722. // Function code : 1 byte (0x03)
  723. // Byte count : 1 byte
  724. // Register value : N 2-bytes
  725. func (o *ModbusRtu) ReadHoldingRegisters(slaveID byte, address, quantity uint16) ([]uint16, error) {
  726. b, err := o.ReadHoldingRegistersBytes(slaveID, address, quantity)
  727. if err != nil {
  728. return nil, err
  729. }
  730. return bytes2Uint16(b), nil
  731. }
  732. // WriteSingleRegister Request:
  733. //
  734. // Slave ID : 1 byte
  735. // Function code : 1 byte (0x06)
  736. // Register address : 2 bytes
  737. // Register value : 2 bytes
  738. //
  739. // Response:
  740. //
  741. // Function code : 1 byte (0x06)
  742. // Register address : 2 bytes
  743. // Register value : 2 bytes
  744. func (o *ModbusRtu) WriteSingleRegister(slaveID byte, address, value uint16) error {
  745. if slaveID > modbus.AddressMax {
  746. return fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  747. slaveID, modbus.AddressBroadCast, modbus.AddressMax)
  748. }
  749. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  750. FuncCode: modbus.FuncCodeWriteSingleRegister,
  751. Data: uint162Bytes(address, value),
  752. })
  753. switch {
  754. case err != nil:
  755. return err
  756. case len(response.Data) != 4:
  757. // Fixed response length
  758. return fmt.Errorf("modbus: response data size '%v' does not match expected '%v'",
  759. len(response.Data), 4)
  760. case binary.BigEndian.Uint16(response.Data) != address:
  761. return fmt.Errorf("modbus: response address '%v' does not match request '%v'",
  762. binary.BigEndian.Uint16(response.Data), address)
  763. case binary.BigEndian.Uint16(response.Data[2:]) != value:
  764. return fmt.Errorf("modbus: response value '%v' does not match request '%v'",
  765. binary.BigEndian.Uint16(response.Data[2:]), value)
  766. }
  767. return nil
  768. }
  769. // WriteMultipleRegistersBytes Request:
  770. //
  771. // Slave ID : 1 byte
  772. // Function code : 1 byte (0x10)
  773. // Starting address : 2 bytes
  774. // Quantity of outputs : 2 bytes
  775. // Byte count : 1 byte
  776. // Registers value : N* bytes
  777. //
  778. // Response:
  779. //
  780. // Function code : 1 byte (0x10)
  781. // Starting address : 2 bytes
  782. // Quantity of registers : 2 bytes
  783. func (o *ModbusRtu) WriteMultipleRegistersBytes(slaveID byte, address, quantity uint16, value []byte) error {
  784. if slaveID > modbus.AddressMax {
  785. return fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  786. slaveID, modbus.AddressBroadCast, modbus.AddressMax)
  787. }
  788. if quantity < modbus.WriteRegQuantityMin || quantity > modbus.WriteRegQuantityMax {
  789. return fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v'",
  790. quantity, modbus.WriteRegQuantityMin, modbus.WriteRegQuantityMax)
  791. }
  792. if len(value) != int(quantity*2) {
  793. return fmt.Errorf("modbus: value length '%v' does not twice as quantity '%v'", len(value), quantity)
  794. }
  795. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  796. FuncCode: modbus.FuncCodeWriteMultipleRegisters,
  797. Data: pduDataBlockSuffix(value, address, quantity),
  798. })
  799. switch {
  800. case err != nil:
  801. return err
  802. case len(response.Data) != 4:
  803. // Fixed response length
  804. return fmt.Errorf("modbus: response data size '%v' does not match expected '%v'",
  805. len(response.Data), 4)
  806. case binary.BigEndian.Uint16(response.Data) != address:
  807. return fmt.Errorf("modbus: response address '%v' does not match request '%v'",
  808. binary.BigEndian.Uint16(response.Data), address)
  809. case binary.BigEndian.Uint16(response.Data[2:]) != quantity:
  810. return fmt.Errorf("modbus: response quantity '%v' does not match request '%v'",
  811. binary.BigEndian.Uint16(response.Data[2:]), quantity)
  812. }
  813. return nil
  814. }
  815. // WriteMultipleRegisters Request:
  816. //
  817. // Slave ID : 1 byte
  818. // Function code : 1 byte (0x10)
  819. // Starting address : 2 bytes
  820. // Quantity of outputs : 2 bytes
  821. // Byte count : 1 byte
  822. // Registers value : N* bytes
  823. //
  824. // Response:
  825. //
  826. // Function code : 1 byte (0x10)
  827. // Starting address : 2 bytes
  828. // Quantity of registers : 2 bytes
  829. func (o *ModbusRtu) WriteMultipleRegisters(slaveID byte, address, quantity uint16, value []uint16) error {
  830. return o.WriteMultipleRegistersBytes(slaveID, address, quantity, uint162Bytes(value...))
  831. }
  832. // MaskWriteRegister Request:
  833. //
  834. // Slave ID : 1 byte
  835. // Function code : 1 byte (0x16)
  836. // Reference address : 2 bytes
  837. // AND-mask : 2 bytes
  838. // OR-mask : 2 bytes
  839. //
  840. // Response:
  841. //
  842. // Function code : 1 byte (0x16)
  843. // Reference address : 2 bytes
  844. // AND-mask : 2 bytes
  845. // OR-mask : 2 bytes
  846. func (o *ModbusRtu) MaskWriteRegister(slaveID byte, address, andMask, orMask uint16) error {
  847. if slaveID > modbus.AddressMax {
  848. return fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  849. slaveID, modbus.AddressBroadCast, modbus.AddressMax)
  850. }
  851. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  852. FuncCode: modbus.FuncCodeMaskWriteRegister,
  853. Data: uint162Bytes(address, andMask, orMask),
  854. })
  855. switch {
  856. case err != nil:
  857. return err
  858. case len(response.Data) != 6:
  859. // Fixed response length
  860. return fmt.Errorf("modbus: response data size '%v' does not match expected '%v'",
  861. len(response.Data), 6)
  862. case binary.BigEndian.Uint16(response.Data) != address:
  863. return fmt.Errorf("modbus: response address '%v' does not match request '%v'",
  864. binary.BigEndian.Uint16(response.Data), address)
  865. case binary.BigEndian.Uint16(response.Data[2:]) != andMask:
  866. return fmt.Errorf("modbus: response AND-mask '%v' does not match request '%v'",
  867. binary.BigEndian.Uint16(response.Data[2:]), andMask)
  868. case binary.BigEndian.Uint16(response.Data[4:]) != orMask:
  869. return fmt.Errorf("modbus: response OR-mask '%v' does not match request '%v'",
  870. binary.BigEndian.Uint16(response.Data[4:]), orMask)
  871. }
  872. return nil
  873. }
  874. // ReadWriteMultipleRegistersBytes Request:
  875. //
  876. // Slave ID : 1 byte
  877. // Function code : 1 byte (0x17)
  878. // Read starting address : 2 bytes
  879. // Quantity to read : 2 bytes
  880. // Write starting address: 2 bytes
  881. // Quantity to write : 2 bytes
  882. // Write byte count : 1 byte
  883. // Write registers value : N* bytes
  884. //
  885. // Response:
  886. //
  887. // Function code : 1 byte (0x17)
  888. // Byte count : 1 byte
  889. // Read registers value : Nx2 bytes
  890. func (o *ModbusRtu) ReadWriteMultipleRegistersBytes(slaveID byte, readAddress, readQuantity,
  891. writeAddress, writeQuantity uint16, value []byte) ([]byte, error) {
  892. if slaveID < modbus.AddressMin || slaveID > modbus.AddressMax {
  893. return nil, fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  894. slaveID, modbus.AddressMin, modbus.AddressMax)
  895. }
  896. if readQuantity < modbus.ReadWriteOnReadRegQuantityMin || readQuantity > modbus.ReadWriteOnReadRegQuantityMax {
  897. return nil, fmt.Errorf("modbus: quantity to read '%v' must be between '%v' and '%v'",
  898. readQuantity, modbus.ReadWriteOnReadRegQuantityMin, modbus.ReadWriteOnReadRegQuantityMax)
  899. }
  900. if writeQuantity < modbus.ReadWriteOnWriteRegQuantityMin || writeQuantity > modbus.ReadWriteOnWriteRegQuantityMax {
  901. return nil, fmt.Errorf("modbus: quantity to write '%v' must be between '%v' and '%v'",
  902. writeQuantity, modbus.ReadWriteOnWriteRegQuantityMin, modbus.ReadWriteOnWriteRegQuantityMax)
  903. }
  904. if len(value) != int(writeQuantity*2) {
  905. return nil, fmt.Errorf("modbus: value length '%v' does not twice as write quantity '%v'",
  906. len(value), writeQuantity)
  907. }
  908. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  909. FuncCode: modbus.FuncCodeReadWriteMultipleRegisters,
  910. Data: pduDataBlockSuffix(value, readAddress, readQuantity, writeAddress, writeQuantity),
  911. })
  912. if err != nil {
  913. return nil, err
  914. }
  915. if int(response.Data[0]) != (len(response.Data) - 1) {
  916. return nil, fmt.Errorf("modbus: response data size '%v' does not match count '%v'",
  917. len(response.Data)-1, response.Data[0])
  918. }
  919. return response.Data[1:], nil
  920. }
  921. // ReadWriteMultipleRegisters Request:
  922. //
  923. // Slave ID : 1 byte
  924. // Function code : 1 byte (0x17)
  925. // Read starting address quantity: 2 bytes
  926. // Quantity to read : 2 bytes
  927. // Write starting address: 2 bytes
  928. // Quantity to write : 2 bytes
  929. // Write byte count : 1 byte
  930. // Write registers value : N* bytes
  931. //
  932. // Response:
  933. //
  934. // Function code : 1 byte (0x17)
  935. // Byte count : 1 byte
  936. // Read registers value : N 2-bytes
  937. func (o *ModbusRtu) ReadWriteMultipleRegisters(slaveID byte, readAddress, readQuantity,
  938. writeAddress, writeQuantity uint16, value []byte) ([]uint16, error) {
  939. b, err := o.ReadWriteMultipleRegistersBytes(slaveID, readAddress, readQuantity,
  940. writeAddress, writeQuantity, value)
  941. if err != nil {
  942. return nil, err
  943. }
  944. return bytes2Uint16(b), nil
  945. }
  946. // ReadFIFOQueue Request:
  947. //
  948. // Slave ID : 1 byte
  949. // Function code : 1 byte (0x18)
  950. // FIFO pointer address : 2 bytes
  951. //
  952. // Response:
  953. //
  954. // Function code : 1 byte (0x18)
  955. // Byte count : 2 bytes only include follow
  956. // FIFO count : 2 bytes (<=31)
  957. // FIFO value register : Nx2 bytes
  958. func (o *ModbusRtu) ReadFIFOQueue(slaveID byte, address uint16) ([]byte, error) {
  959. if slaveID < modbus.AddressMin || slaveID > modbus.AddressMax {
  960. return nil, fmt.Errorf("modbus: slaveID '%v' must be between '%v' and '%v'",
  961. slaveID, modbus.AddressMin, modbus.AddressMax)
  962. }
  963. response, err := o.Send(slaveID, modbus.ProtocolDataUnit{
  964. FuncCode: modbus.FuncCodeReadFIFOQueue,
  965. Data: uint162Bytes(address),
  966. })
  967. switch {
  968. case err != nil:
  969. return nil, err
  970. case len(response.Data) < 4:
  971. return nil, fmt.Errorf("modbus: response data size '%v' is less than expected '%v'",
  972. len(response.Data), 4)
  973. case len(response.Data)-2 != int(binary.BigEndian.Uint16(response.Data)):
  974. return nil, fmt.Errorf("modbus: response data size '%v' does not match count '%v'",
  975. len(response.Data)-2, binary.BigEndian.Uint16(response.Data))
  976. case int(binary.BigEndian.Uint16(response.Data[2:])) > 31:
  977. return nil, fmt.Errorf("modbus: fifo count '%v' is greater than expected '%v'",
  978. binary.BigEndian.Uint16(response.Data[2:]), 31)
  979. }
  980. return response.Data[4:], nil
  981. }
  982. // uint162Bytes creates a sequence of uint16 data.
  983. func uint162Bytes(value ...uint16) []byte {
  984. data := make([]byte, 2*len(value))
  985. for i, v := range value {
  986. binary.BigEndian.PutUint16(data[i*2:], v)
  987. }
  988. return data
  989. }
  990. // bytes2Uint16 bytes convert to uint16 for register
  991. func bytes2Uint16(buf []byte) []uint16 {
  992. data := make([]uint16, 0, len(buf)/2)
  993. for i := 0; i < len(buf)/2; i++ {
  994. data = append(data, binary.BigEndian.Uint16(buf[i*2:]))
  995. }
  996. return data
  997. }
  998. // pduDataBlockSuffix creates a sequence of uint16 data and append the suffix plus its length.
  999. func pduDataBlockSuffix(suffix []byte, value ...uint16) []byte {
  1000. length := 2 * len(value)
  1001. data := make([]byte, length+1+len(suffix))
  1002. for i, v := range value {
  1003. binary.BigEndian.PutUint16(data[i*2:], v)
  1004. }
  1005. data[length] = uint8(len(suffix))
  1006. copy(data[length+1:], suffix)
  1007. return data
  1008. }