github.com/simpleiot/simpleiot@v0.18.3/modbus/pdu_test.go (about) 1 package modbus 2 3 import ( 4 "testing" 5 6 "github.com/google/go-cmp/cmp" 7 ) 8 9 func TestPduReadCoils(t *testing.T) { 10 regs := Regs{} 11 regs.AddCoil(128) // add register 8 for coil 128 12 _ = regs.WriteCoil(128, true) 13 14 pdu := ReadCoils(128, 1) 15 16 _, resp, err := pdu.ProcessRequest(®s) 17 18 if err != nil { 19 t.Errorf("Error processing request: %v", err) 20 } 21 22 bits, err := resp.RespReadBits() 23 24 if err != nil { 25 t.Errorf("Error getting bits: %v", err) 26 } 27 28 if len(bits) != 1 { 29 t.Errorf("expected 1 bit, got %v", len(bits)) 30 } 31 32 if !bits[0] { 33 t.Error("Expected high bit") 34 } 35 } 36 37 func TestPduWriteSingleCoil(t *testing.T) { 38 regs := Regs{} 39 regs.AddCoil(128) // add register 8 for coil 128 40 _ = regs.WriteCoil(128, true) 41 42 pdu := WriteSingleCoil(128, false) 43 44 _, resp, err := pdu.ProcessRequest(®s) 45 46 if err != nil { 47 t.Errorf("Error processing request: %v", err) 48 } 49 50 if got, want := resp.FunctionCode, FuncCodeWriteSingleCoil; got != want { 51 t.Errorf("got function code %x, want %x", got, want) 52 } 53 54 data := Uint16Array(resp.Data) 55 if got, want := data[0], uint16(128); got != want { 56 t.Errorf("got address %d, want %d", got, want) 57 } 58 if got, want := data[1], uint16(0); got != want { 59 t.Errorf("got value %d, want %d", got, want) 60 } 61 } 62 63 func TestPduWriteSingleCoilError(t *testing.T) { 64 regs := Regs{} 65 regs.AddCoil(128) // add register 8 for coil 128 66 _ = regs.WriteCoil(128, true) 67 68 pdu := WriteSingleCoil(64, false) 69 70 _, resp, err := pdu.ProcessRequest(®s) 71 72 if err != nil { 73 t.Errorf("Error processing request: %v", err) 74 } 75 76 if got, want := resp.FunctionCode, 0x80|FuncCodeWriteSingleCoil; got != want { 77 t.Errorf("got function code %x, want %x", got, want) 78 } 79 if len(resp.Data) != 1 || resp.Data[0] != byte(ExcIllegalAddress) { 80 t.Errorf("got exception code %x, want %x", resp.Data[0], byte(ExcIllegalAddress)) 81 } 82 } 83 84 func TestPduReadHoldingRegs(t *testing.T) { 85 regs := Regs{} 86 regs.AddReg(8, 1) 87 _ = regs.WriteReg(8, 0x1234) 88 89 pdu := ReadHoldingRegs(8, 1) 90 91 _, resp, err := pdu.ProcessRequest(®s) 92 93 if err != nil { 94 t.Fatal("Error processing request: ", err) 95 } 96 97 if resp.Data[0] != 2 { 98 t.Fatal("expected byte count to be 2") 99 } 100 101 values := Uint16Array(resp.Data[1:]) 102 if len(values) != 1 { 103 t.Fatal("Expected 1 values in response") 104 } 105 106 if values[0] != 0x1234 { 107 t.Fatal("wrong value") 108 } 109 } 110 111 func TestProcessRequest(t *testing.T) { 112 regs := Regs{} 113 regs.AddCoil(128) // add register 8 for coil 128 114 _ = regs.WriteCoil(128, true) 115 _ = regs.WriteCoil(130, true) 116 _ = regs.WriteCoil(132, true) 117 regs.AddCoil(144) // add register 9 for coil 144 118 119 for _, test := range []struct { 120 name string 121 in []byte 122 out []byte 123 }{ 124 {"ReadCoils/one", []byte{1, 0, 128, 0, 1}, []byte{1, 1, 1}}, 125 {"ReadCoils/multiple", []byte{1, 0, 128, 0, 3}, []byte{1, 1, 5}}, 126 {"ReadCoils/missing", []byte{1, 0, 16, 0, 1}, []byte{0x81, 2}}, 127 {"ReadDiscreteInputs/one", []byte{2, 0, 128, 0, 1}, []byte{2, 1, 1}}, 128 {"ReadDiscreteInputs/multiple", []byte{2, 0, 128, 0, 1}, []byte{2, 1, 1}}, 129 {"ReadDiscreteInputs/one", []byte{2, 0, 128, 0, 3}, []byte{2, 1, 5}}, 130 {"ReadDiscreteInputs/missing", []byte{2, 0, 16, 0, 1}, []byte{0x82, 2}}, 131 {"ReadHoldingRegisters/one", []byte{3, 0, 8, 0, 1}, []byte{3, 2, 0, 0x15}}, 132 {"ReadHoldingRegisters/multiple", []byte{3, 0, 8, 0, 2}, []byte{3, 4, 0, 0x15, 0, 0}}, 133 {"ReadHoldingRegisters/missing", []byte{3, 0, 7, 0, 2}, []byte{0x83, 2}}, 134 {"ReadInputRegisters/one", []byte{4, 0, 8, 0, 1}, []byte{4, 2, 0, 0x15}}, 135 {"ReadInputRegisters/multiple", []byte{4, 0, 8, 0, 2}, []byte{4, 4, 0, 0x15, 0, 0}}, 136 {"ReadInputRegisters/missing", []byte{4, 0, 7, 0, 2}, []byte{0x84, 2}}, 137 {"WriteSingleCoil/present", []byte{5, 0, 129, 0xFF, 0}, []byte{5, 0, 129, 0xFF, 0}}, 138 {"WriteSingleCoil/illegal", []byte{5, 0, 129, 10, 0}, []byte{0x85, 3}}, 139 {"WriteSingleCoil/missing", []byte{5, 0, 127, 0xFF, 0}, []byte{0x85, 2}}, 140 {"WriteSingleCoil/readback", []byte{1, 0, 128, 0, 3}, []byte{1, 1, 7}}, 141 {"WriteMultipleCoils/present", []byte{15, 0, 130, 0, 3, 1, 0x07}, []byte{15, 0, 130, 0, 3}}, 142 {"WriteMultipleCoils/missing", []byte{15, 0, 120, 0, 3, 1, 0x07}, []byte{0x8F, 2}}, 143 {"WriteMultipleCoils/readback", []byte{1, 0, 128, 0, 8}, []byte{1, 1, 0b00011111}}, 144 {"WriteSingleRegister/present", []byte{6, 0, 8, 0, 4}, []byte{6, 0, 8, 0, 4}}, 145 {"WriteSingleRegister/missing", []byte{6, 0, 6, 0, 4}, []byte{0x86, 2}}, 146 {"WriteSingleRegister/readback", []byte{3, 0, 8, 0, 1}, []byte{3, 2, 0, 4}}, 147 {"WriteMultipleRegisters/one", []byte{0x10, 0, 8, 0, 1, 2, 0, 8}, []byte{0x10, 0, 8, 0, 1}}, 148 {"WriteMultipleRegisters/multiple", []byte{0x10, 0, 8, 0, 2, 4, 0, 8, 10, 15}, []byte{0x10, 0, 8, 0, 2}}, 149 {"WriteMultipleRegisters/missing", []byte{0x10, 0, 7, 0, 2, 4, 9, 10, 11, 12}, []byte{0x90, 2}}, 150 {"WriteMultipleRegisters/wronglen", []byte{0x10, 0, 7, 0, 2, 4, 9, 10}, []byte{0x90, 3}}, 151 {"WriteMultipleRegisters/readback", []byte{3, 0, 8, 0, 2}, []byte{3, 4, 0, 8, 10, 15}}, 152 } { 153 t.Run(test.name, func(t *testing.T) { 154 pdu := &PDU{ 155 FunctionCode: FunctionCode(test.in[0]), 156 Data: test.in[1:], 157 } 158 _, resp, err := pdu.ProcessRequest(®s) 159 160 if err != nil { 161 t.Errorf("Error processing request: %v", err) 162 } 163 164 want := PDU{ 165 FunctionCode: FunctionCode(test.out[0]), 166 Data: test.out[1:], 167 } 168 169 if diff := cmp.Diff(resp, want); diff != "" { 170 t.Errorf("unexpected reply: got(-), want(+):\n%s", diff) 171 } 172 t.Logf("register state: %+v", ®s) 173 }) 174 } 175 }