modbusrtu.go 37 KB

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