client.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. // Copyright 2014 Quoc-Viet Nguyen. All rights reserved.
  2. // This software may be modified and distributed under the terms
  3. // of the BSD license. See the LICENSE file for details.
  4. package modbus
  5. import (
  6. "encoding/binary"
  7. "fmt"
  8. )
  9. // ClientHandler is the interface that groups the Packager and Transporter methods.
  10. type ClientHandler interface {
  11. Packager
  12. Transporter
  13. }
  14. type client struct {
  15. packager Packager
  16. transporter Transporter
  17. //发送后存储的数据
  18. aduRequest []byte
  19. quantity uint16
  20. address uint16
  21. functionCode byte
  22. }
  23. // NewClient creates a new modbus client with given backend handler.
  24. func NewClient(handler ClientHandler) Client {
  25. return &client{packager: handler, transporter: handler}
  26. }
  27. // NewClient2 creates a new modbus client with given backend packager and transporter.
  28. func NewClient2(packager Packager, transporter Transporter) Client {
  29. return &client{packager: packager, transporter: transporter}
  30. }
  31. // Request:
  32. //
  33. // Function code : 1 byte (0x01)
  34. // Starting address : 2 bytes
  35. // Quantity of coils : 2 bytes
  36. //
  37. // Response:
  38. //
  39. // Function code : 1 byte (0x01)
  40. // Byte count : 1 byte
  41. // Coil status : N* bytes (=N or N+1)
  42. func (mb *client) ReadCoils(address, quantity uint16) (results []byte, err error) {
  43. if quantity < 1 || quantity > 2000 {
  44. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 2000)
  45. return
  46. }
  47. request := ProtocolDataUnit{
  48. FunctionCode: FuncCodeReadCoils,
  49. Data: dataBlock(address, quantity),
  50. }
  51. response, err := mb.send(&request)
  52. if err != nil {
  53. return
  54. }
  55. count := int(response.Data[0])
  56. length := len(response.Data) - 1
  57. if count != length {
  58. err = fmt.Errorf("modbus: response data size '%v' does not match count '%v'", length, count)
  59. return
  60. }
  61. results = response.Data[1:]
  62. return
  63. }
  64. // Request:
  65. //
  66. // Function code : 1 byte (0x02)
  67. // Starting address : 2 bytes
  68. // Quantity of inputs : 2 bytes
  69. //
  70. // Response:
  71. //
  72. // Function code : 1 byte (0x02)
  73. // Byte count : 1 byte
  74. // Input status : N* bytes (=N or N+1)
  75. func (mb *client) ReadDiscreteInputs(address, quantity uint16) (results []byte, err error) {
  76. if quantity < 1 || quantity > 2000 {
  77. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 2000)
  78. return
  79. }
  80. request := ProtocolDataUnit{
  81. FunctionCode: FuncCodeReadDiscreteInputs,
  82. Data: dataBlock(address, quantity),
  83. }
  84. response, err := mb.send(&request)
  85. if err != nil {
  86. return
  87. }
  88. count := int(response.Data[0])
  89. length := len(response.Data) - 1
  90. if count != length {
  91. err = fmt.Errorf("modbus: response data size '%v' does not match count '%v'", length, count)
  92. return
  93. }
  94. results = response.Data[1:]
  95. return
  96. }
  97. // Request:
  98. //
  99. // Function code : 1 byte (0x03)
  100. // Starting address : 2 bytes
  101. // Quantity of registers : 2 bytes
  102. //
  103. // Response:
  104. //
  105. // Function code : 1 byte (0x03)
  106. // Byte count : 1 byte
  107. // Register value : Nx2 bytes
  108. func (mb *client) PackReadHoldingRegisters(address, quantity uint16) (results []byte, err error) {
  109. if quantity < 1 || quantity > 125 {
  110. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 125)
  111. return
  112. }
  113. request := ProtocolDataUnit{
  114. FunctionCode: FuncCodeReadHoldingRegisters,
  115. Data: dataBlock(address, quantity),
  116. }
  117. response, err := mb.pack_post(&request)
  118. if err != nil {
  119. return
  120. }
  121. //存储要发送的字节数组,用于接收数据时验证
  122. mb.aduRequest = response
  123. mb.quantity = quantity
  124. mb.address = address
  125. mb.functionCode = request.FunctionCode
  126. results = response
  127. return
  128. }
  129. // Request:
  130. //
  131. // Function code : 1 byte (0x10)
  132. // Starting address : 2 bytes
  133. // Quantity of outputs : 2 bytes
  134. // Byte count : 1 byte
  135. // Registers value : N* bytes
  136. //
  137. // Response:
  138. //
  139. // Function code : 1 byte (0x10)
  140. // Starting address : 2 bytes
  141. // Quantity of registers : 2 bytes
  142. func (mb *client) PackWriteMultipleRegisters(address, quantity uint16, value []byte) (results []byte, err error) {
  143. if quantity < 1 || quantity > 123 {
  144. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 123)
  145. return
  146. }
  147. request := ProtocolDataUnit{
  148. FunctionCode: FuncCodeWriteMultipleRegisters,
  149. Data: dataBlockSuffix(value, address, quantity),
  150. }
  151. response, err := mb.pack_post(&request)
  152. if err != nil {
  153. return
  154. }
  155. //存储要发送的字节数组,用于接收数据时验证
  156. mb.aduRequest = response
  157. mb.quantity = quantity
  158. mb.address = address
  159. mb.functionCode = request.FunctionCode
  160. results = response
  161. return
  162. }
  163. func (mb *client) DePackSetRegs(aduResponse []byte) (results []byte, err error) {
  164. response, err := mb.depack_rcv(mb.aduRequest, aduResponse)
  165. if err != nil {
  166. return
  167. }
  168. // Fixed response length
  169. if len(response.Data) != 4 {
  170. err = fmt.Errorf("modbus: response data size '%v' does not match expected '%v'", len(response.Data), 4)
  171. return
  172. }
  173. respValue := binary.BigEndian.Uint16(response.Data)
  174. if mb.address != respValue {
  175. err = fmt.Errorf("modbus: response address '%v' does not match request '%v'", respValue, mb.address)
  176. return
  177. }
  178. results = response.Data[2:]
  179. respValue = binary.BigEndian.Uint16(results)
  180. if mb.quantity != respValue {
  181. err = fmt.Errorf("modbus: response quantity '%v' does not match request '%v'", respValue, mb.quantity)
  182. return
  183. }
  184. return
  185. }
  186. func (mb *client) DePackRegisters(aduResponse []byte) (results []byte, err error) {
  187. response, err := mb.depack_rcv(mb.aduRequest, aduResponse)
  188. if err != nil {
  189. return
  190. }
  191. count := int(response.Data[0])
  192. length := len(response.Data) - 1
  193. if count != length {
  194. err = fmt.Errorf("modbus: response data size '%v' does not match count '%v'", length, count)
  195. return
  196. }
  197. results = response.Data[1:]
  198. return
  199. }
  200. // Request:
  201. //
  202. // Function code : 1 byte (0x03)
  203. // Starting address : 2 bytes
  204. // Quantity of registers : 2 bytes
  205. //
  206. // Response:
  207. //
  208. // Function code : 1 byte (0x03)
  209. // Byte count : 1 byte
  210. // Register value : Nx2 bytes
  211. func (mb *client) ReadHoldingRegisters(address, quantity uint16) (results []byte, err error) {
  212. if quantity < 1 || quantity > 125 {
  213. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 125)
  214. return
  215. }
  216. request := ProtocolDataUnit{
  217. FunctionCode: FuncCodeReadHoldingRegisters,
  218. Data: dataBlock(address, quantity),
  219. }
  220. response, err := mb.send(&request)
  221. if err != nil {
  222. return
  223. }
  224. count := int(response.Data[0])
  225. length := len(response.Data) - 1
  226. if count != length {
  227. err = fmt.Errorf("modbus: response data size '%v' does not match count '%v'", length, count)
  228. return
  229. }
  230. results = response.Data[1:]
  231. return
  232. }
  233. // Request:
  234. //
  235. // Function code : 1 byte (0x04)
  236. // Starting address : 2 bytes
  237. // Quantity of registers : 2 bytes
  238. //
  239. // Response:
  240. //
  241. // Function code : 1 byte (0x04)
  242. // Byte count : 1 byte
  243. // Input registers : N bytes
  244. func (mb *client) ReadInputRegisters(address, quantity uint16) (results []byte, err error) {
  245. if quantity < 1 || quantity > 125 {
  246. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 125)
  247. return
  248. }
  249. request := ProtocolDataUnit{
  250. FunctionCode: FuncCodeReadInputRegisters,
  251. Data: dataBlock(address, quantity),
  252. }
  253. response, err := mb.send(&request)
  254. if err != nil {
  255. return
  256. }
  257. count := int(response.Data[0])
  258. length := len(response.Data) - 1
  259. if count != length {
  260. err = fmt.Errorf("modbus: response data size '%v' does not match count '%v'", length, count)
  261. return
  262. }
  263. results = response.Data[1:]
  264. return
  265. }
  266. // Request:
  267. //
  268. // Function code : 1 byte (0x05)
  269. // Output address : 2 bytes
  270. // Output value : 2 bytes
  271. //
  272. // Response:
  273. //
  274. // Function code : 1 byte (0x05)
  275. // Output address : 2 bytes
  276. // Output value : 2 bytes
  277. func (mb *client) WriteSingleCoil(address, value uint16) (results []byte, err error) {
  278. // The requested ON/OFF state can only be 0xFF00 and 0x0000
  279. if value != 0xFF00 && value != 0x0000 {
  280. err = fmt.Errorf("modbus: state '%v' must be either 0xFF00 (ON) or 0x0000 (OFF)", value)
  281. return
  282. }
  283. request := ProtocolDataUnit{
  284. FunctionCode: FuncCodeWriteSingleCoil,
  285. Data: dataBlock(address, value),
  286. }
  287. response, err := mb.send(&request)
  288. if err != nil {
  289. return
  290. }
  291. // Fixed response length
  292. if len(response.Data) != 4 {
  293. err = fmt.Errorf("modbus: response data size '%v' does not match expected '%v'", len(response.Data), 4)
  294. return
  295. }
  296. respValue := binary.BigEndian.Uint16(response.Data)
  297. if address != respValue {
  298. err = fmt.Errorf("modbus: response address '%v' does not match request '%v'", respValue, address)
  299. return
  300. }
  301. results = response.Data[2:]
  302. respValue = binary.BigEndian.Uint16(results)
  303. if value != respValue {
  304. err = fmt.Errorf("modbus: response value '%v' does not match request '%v'", respValue, value)
  305. return
  306. }
  307. return
  308. }
  309. // Request:
  310. //
  311. // Function code : 1 byte (0x06)
  312. // Register address : 2 bytes
  313. // Register value : 2 bytes
  314. //
  315. // Response:
  316. //
  317. // Function code : 1 byte (0x06)
  318. // Register address : 2 bytes
  319. // Register value : 2 bytes
  320. func (mb *client) WriteSingleRegister(address, value uint16) (results []byte, err error) {
  321. request := ProtocolDataUnit{
  322. FunctionCode: FuncCodeWriteSingleRegister,
  323. Data: dataBlock(address, value),
  324. }
  325. response, err := mb.send(&request)
  326. if err != nil {
  327. return
  328. }
  329. // Fixed response length
  330. if len(response.Data) != 4 {
  331. err = fmt.Errorf("modbus: response data size '%v' does not match expected '%v'", len(response.Data), 4)
  332. return
  333. }
  334. respValue := binary.BigEndian.Uint16(response.Data)
  335. if address != respValue {
  336. err = fmt.Errorf("modbus: response address '%v' does not match request '%v'", respValue, address)
  337. return
  338. }
  339. results = response.Data[2:]
  340. respValue = binary.BigEndian.Uint16(results)
  341. if value != respValue {
  342. err = fmt.Errorf("modbus: response value '%v' does not match request '%v'", respValue, value)
  343. return
  344. }
  345. return
  346. }
  347. // Request:
  348. //
  349. // Function code : 1 byte (0x0F)
  350. // Starting address : 2 bytes
  351. // Quantity of outputs : 2 bytes
  352. // Byte count : 1 byte
  353. // Outputs value : N* bytes
  354. //
  355. // Response:
  356. //
  357. // Function code : 1 byte (0x0F)
  358. // Starting address : 2 bytes
  359. // Quantity of outputs : 2 bytes
  360. func (mb *client) WriteMultipleCoils(address, quantity uint16, value []byte) (results []byte, err error) {
  361. if quantity < 1 || quantity > 1968 {
  362. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 1968)
  363. return
  364. }
  365. request := ProtocolDataUnit{
  366. FunctionCode: FuncCodeWriteMultipleCoils,
  367. Data: dataBlockSuffix(value, address, quantity),
  368. }
  369. response, err := mb.send(&request)
  370. if err != nil {
  371. return
  372. }
  373. // Fixed response length
  374. if len(response.Data) != 4 {
  375. err = fmt.Errorf("modbus: response data size '%v' does not match expected '%v'", len(response.Data), 4)
  376. return
  377. }
  378. respValue := binary.BigEndian.Uint16(response.Data)
  379. if address != respValue {
  380. err = fmt.Errorf("modbus: response address '%v' does not match request '%v'", respValue, address)
  381. return
  382. }
  383. results = response.Data[2:]
  384. respValue = binary.BigEndian.Uint16(results)
  385. if quantity != respValue {
  386. err = fmt.Errorf("modbus: response quantity '%v' does not match request '%v'", respValue, quantity)
  387. return
  388. }
  389. return
  390. }
  391. // Request:
  392. //
  393. // Function code : 1 byte (0x10)
  394. // Starting address : 2 bytes
  395. // Quantity of outputs : 2 bytes
  396. // Byte count : 1 byte
  397. // Registers value : N* bytes
  398. //
  399. // Response:
  400. //
  401. // Function code : 1 byte (0x10)
  402. // Starting address : 2 bytes
  403. // Quantity of registers : 2 bytes
  404. func (mb *client) WriteMultipleRegisters(address, quantity uint16, value []byte) (results []byte, err error) {
  405. if quantity < 1 || quantity > 123 {
  406. err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 123)
  407. return
  408. }
  409. request := ProtocolDataUnit{
  410. FunctionCode: FuncCodeWriteMultipleRegisters,
  411. Data: dataBlockSuffix(value, address, quantity),
  412. }
  413. response, err := mb.send(&request)
  414. if err != nil {
  415. return
  416. }
  417. // Fixed response length
  418. if len(response.Data) != 4 {
  419. err = fmt.Errorf("modbus: response data size '%v' does not match expected '%v'", len(response.Data), 4)
  420. return
  421. }
  422. respValue := binary.BigEndian.Uint16(response.Data)
  423. if address != respValue {
  424. err = fmt.Errorf("modbus: response address '%v' does not match request '%v'", respValue, address)
  425. return
  426. }
  427. results = response.Data[2:]
  428. respValue = binary.BigEndian.Uint16(results)
  429. if quantity != respValue {
  430. err = fmt.Errorf("modbus: response quantity '%v' does not match request '%v'", respValue, quantity)
  431. return
  432. }
  433. return
  434. }
  435. // Request:
  436. //
  437. // Function code : 1 byte (0x16)
  438. // Reference address : 2 bytes
  439. // AND-mask : 2 bytes
  440. // OR-mask : 2 bytes
  441. //
  442. // Response:
  443. //
  444. // Function code : 1 byte (0x16)
  445. // Reference address : 2 bytes
  446. // AND-mask : 2 bytes
  447. // OR-mask : 2 bytes
  448. func (mb *client) MaskWriteRegister(address, andMask, orMask uint16) (results []byte, err error) {
  449. request := ProtocolDataUnit{
  450. FunctionCode: FuncCodeMaskWriteRegister,
  451. Data: dataBlock(address, andMask, orMask),
  452. }
  453. response, err := mb.send(&request)
  454. if err != nil {
  455. return
  456. }
  457. // Fixed response length
  458. if len(response.Data) != 6 {
  459. err = fmt.Errorf("modbus: response data size '%v' does not match expected '%v'", len(response.Data), 6)
  460. return
  461. }
  462. respValue := binary.BigEndian.Uint16(response.Data)
  463. if address != respValue {
  464. err = fmt.Errorf("modbus: response address '%v' does not match request '%v'", respValue, address)
  465. return
  466. }
  467. respValue = binary.BigEndian.Uint16(response.Data[2:])
  468. if andMask != respValue {
  469. err = fmt.Errorf("modbus: response AND-mask '%v' does not match request '%v'", respValue, andMask)
  470. return
  471. }
  472. respValue = binary.BigEndian.Uint16(response.Data[4:])
  473. if orMask != respValue {
  474. err = fmt.Errorf("modbus: response OR-mask '%v' does not match request '%v'", respValue, orMask)
  475. return
  476. }
  477. results = response.Data[2:]
  478. return
  479. }
  480. // Request:
  481. //
  482. // Function code : 1 byte (0x17)
  483. // Read starting address : 2 bytes
  484. // Quantity to read : 2 bytes
  485. // Write starting address: 2 bytes
  486. // Quantity to write : 2 bytes
  487. // Write byte count : 1 byte
  488. // Write registers value : N* bytes
  489. //
  490. // Response:
  491. //
  492. // Function code : 1 byte (0x17)
  493. // Byte count : 1 byte
  494. // Read registers value : Nx2 bytes
  495. func (mb *client) ReadWriteMultipleRegisters(readAddress, readQuantity, writeAddress, writeQuantity uint16, value []byte) (results []byte, err error) {
  496. if readQuantity < 1 || readQuantity > 125 {
  497. err = fmt.Errorf("modbus: quantity to read '%v' must be between '%v' and '%v',", readQuantity, 1, 125)
  498. return
  499. }
  500. if writeQuantity < 1 || writeQuantity > 121 {
  501. err = fmt.Errorf("modbus: quantity to write '%v' must be between '%v' and '%v',", writeQuantity, 1, 121)
  502. return
  503. }
  504. request := ProtocolDataUnit{
  505. FunctionCode: FuncCodeReadWriteMultipleRegisters,
  506. Data: dataBlockSuffix(value, readAddress, readQuantity, writeAddress, writeQuantity),
  507. }
  508. response, err := mb.send(&request)
  509. if err != nil {
  510. return
  511. }
  512. count := int(response.Data[0])
  513. if count != (len(response.Data) - 1) {
  514. err = fmt.Errorf("modbus: response data size '%v' does not match count '%v'", len(response.Data)-1, count)
  515. return
  516. }
  517. results = response.Data[1:]
  518. return
  519. }
  520. // Request:
  521. //
  522. // Function code : 1 byte (0x18)
  523. // FIFO pointer address : 2 bytes
  524. //
  525. // Response:
  526. //
  527. // Function code : 1 byte (0x18)
  528. // Byte count : 2 bytes
  529. // FIFO count : 2 bytes
  530. // FIFO count : 2 bytes (<=31)
  531. // FIFO value register : Nx2 bytes
  532. func (mb *client) ReadFIFOQueue(address uint16) (results []byte, err error) {
  533. request := ProtocolDataUnit{
  534. FunctionCode: FuncCodeReadFIFOQueue,
  535. Data: dataBlock(address),
  536. }
  537. response, err := mb.send(&request)
  538. if err != nil {
  539. return
  540. }
  541. if len(response.Data) < 4 {
  542. err = fmt.Errorf("modbus: response data size '%v' is less than expected '%v'", len(response.Data), 4)
  543. return
  544. }
  545. count := int(binary.BigEndian.Uint16(response.Data))
  546. if count != (len(response.Data) - 1) {
  547. err = fmt.Errorf("modbus: response data size '%v' does not match count '%v'", len(response.Data)-1, count)
  548. return
  549. }
  550. count = int(binary.BigEndian.Uint16(response.Data[2:]))
  551. if count > 31 {
  552. err = fmt.Errorf("modbus: fifo count '%v' is greater than expected '%v'", count, 31)
  553. return
  554. }
  555. results = response.Data[4:]
  556. return
  557. }
  558. // Helpers
  559. func (mb *client) pack_post(request *ProtocolDataUnit) (aduRequest []byte, err error) {
  560. aduRequest, err = mb.packager.Encode(request)
  561. return
  562. }
  563. func (mb *client) depack_rcv(aduRequest, aduResponse []byte) (response *ProtocolDataUnit, err error) {
  564. //var functionCode byte
  565. if err = mb.packager.Verify(aduRequest, aduResponse); err != nil {
  566. return
  567. }
  568. //fmt.Println("depack_rcv:", aduResponse)
  569. response, err = mb.packager.Decode(aduResponse)
  570. if err != nil {
  571. return
  572. }
  573. //functionCode = aduRequest[1]
  574. // Check correct function code returned (exception)
  575. if response.FunctionCode != mb.functionCode {
  576. err = responseError(response)
  577. return
  578. }
  579. if response.Data == nil || len(response.Data) == 0 {
  580. // Empty response
  581. err = fmt.Errorf("modbus: response data is empty")
  582. return
  583. }
  584. return
  585. }
  586. // send sends request and checks possible exception in the response.
  587. func (mb *client) send(request *ProtocolDataUnit) (response *ProtocolDataUnit, err error) {
  588. aduRequest, err := mb.packager.Encode(request)
  589. if err != nil {
  590. return
  591. }
  592. aduResponse, err := mb.transporter.Send(aduRequest)
  593. if err != nil {
  594. return
  595. }
  596. if err = mb.packager.Verify(aduRequest, aduResponse); err != nil {
  597. return
  598. }
  599. response, err = mb.packager.Decode(aduResponse)
  600. if err != nil {
  601. return
  602. }
  603. // Check correct function code returned (exception)
  604. if response.FunctionCode != request.FunctionCode {
  605. err = responseError(response)
  606. return
  607. }
  608. if response.Data == nil || len(response.Data) == 0 {
  609. // Empty response
  610. err = fmt.Errorf("modbus: response data is empty")
  611. return
  612. }
  613. return
  614. }
  615. // dataBlock creates a sequence of uint16 data.
  616. func dataBlock(value ...uint16) []byte {
  617. data := make([]byte, 2*len(value))
  618. for i, v := range value {
  619. binary.BigEndian.PutUint16(data[i*2:], v)
  620. }
  621. return data
  622. }
  623. // dataBlockSuffix creates a sequence of uint16 data and append the suffix plus its length.
  624. func dataBlockSuffix(suffix []byte, value ...uint16) []byte {
  625. length := 2 * len(value)
  626. data := make([]byte, length+1+len(suffix))
  627. for i, v := range value {
  628. binary.BigEndian.PutUint16(data[i*2:], v)
  629. }
  630. data[length] = uint8(len(suffix))
  631. copy(data[length+1:], suffix)
  632. return data
  633. }
  634. func responseError(response *ProtocolDataUnit) error {
  635. mbError := &ModbusError{FunctionCode: response.FunctionCode}
  636. if response.Data != nil && len(response.Data) > 0 {
  637. mbError.ExceptionCode = response.Data[0]
  638. }
  639. return mbError
  640. }