func (this ModbusRTUConnection) ReadInputRegisters(slave int8, startAddr int, nb int) ([]uint16, error) { if C.modbus_set_slave(this.ctx, C.int(slave)) != 0 { return nil, errors.New(fmt.Sprintf("Invalid slave id %d", slave)) } var space [65535]C.uint16_t this.ProcessHook(RTU_03_LEN) if ressived := C.modbus_read_input_registers(this.ctx, C.int(startAddr), C.int(nb), &(space[0])); int(ressived) != nb { if ressived == -1 { errno := C.getErrno() if errno == C.EMBMDATA { return nil, errors.New(C.GoString(C.modbus_strerror(errno))) } return nil, errors.New(fmt.Sprintf("Unknown modbus error errno=%d", errno)) } else if ressived == 0 { return nil, errors.New("No ansver ressived") } } else { result := make([]uint16, ressived) for i := 0; i < int(ressived); i++ { result[i] = uint16(space[i]) } return result, nil } return nil, nil }
func modbus_strerror(errno error) string { if val, ok := errno.(syscall.Errno); ok { return C.GoString(C.modbus_strerror(C.int(val))) } else { return "UNKNOWN ERROR while processing errno" } }
func (this ModbusRTUConnection) WriteHolding(slave int8, addr int, value uint16) error { if C.modbus_set_slave(this.ctx, C.int(slave)) != 0 { return errors.New(fmt.Sprintf("Invalid slave id %d", slave)) } this.ProcessHook(RTU_06_LEN) if C.modbus_write_register(this.ctx, C.int(addr), C.int(value)) != 1 { return errors.New(C.GoString(C.modbus_strerror(C.getErrno()))) } return nil }
func (this ModbusRTUConnection) WriteHoldings(slave int8, startAddr int, values []uint16) error { if C.modbus_set_slave(this.ctx, C.int(slave)) != 0 { return errors.New(fmt.Sprintf("Invalid slave id %d", slave)) } vals := make([]C.uint16_t, len(values)) for i, v := range values { vals[i] = C.uint16_t(v) } this.ProcessHook(RTU_10_LEN + len(values)*int(unsafe.Sizeof(vals[0]))) if C.modbus_write_registers(this.ctx, C.int(startAddr), C.int(len(values)), &vals[0]) < 0 { return errors.New(C.GoString(C.modbus_strerror(C.getErrno()))) } return nil }
func (this ModbusRTUConnection) WriteSingleCoil(slave int8, addr int, value bool) error { if C.modbus_set_slave(this.ctx, C.int(slave)) != 0 { return errors.New(fmt.Sprintf("Invalid slave id %d", slave)) } var v C.int if value { v = C.TRUE } this.ProcessHook(RTU_05_LEN) if C.modbus_write_bit(this.ctx, C.int(addr), v) != 1 { return errors.New(C.GoString(C.modbus_strerror(C.getErrno()))) } return nil }
func (this ModbusRTUConnection) WriteCoils(slave int8, startAddr int, values []bool) error { if C.modbus_set_slave(this.ctx, C.int(slave)) != 0 { return errors.New(fmt.Sprintf("Invalid slave id %d", slave)) } vals := make([]C.uint8_t, len(values)) for i, v := range values { if v { vals[i] = C.TRUE } } this.ProcessHook(RTU_0F_LEN + int(math.Ceil(float64(len(values))/8.0))) if C.modbus_write_bits(this.ctx, C.int(startAddr), C.int(len(values)), &vals[0]) < 0 { return errors.New(C.GoString(C.modbus_strerror(C.getErrno()))) } return nil }
func NewModbusRTUConnection(DeviceName string, Speed int, SerialMode string, Hook ioCtlHook) (*ModbusRTUConnection, error) { // is allready opened? for _, connection := range ModbusRTUConnections { if connection.Device() == DeviceName { if connection.serialMode == SerialMode { return connection, nil } else { return nil, errors.New( fmt.Sprintf("Device '%s' used by connection %d, mode '%s'", DeviceName, connection.ID(), connection.serialMode)) } } } result := &ModbusRTUConnection{deviceName: DeviceName, speed: Speed, serialMode: SerialMode, hook: Hook} if Hook != nil { result.rwCtlChan = make(chan int) go func(oneByteTime time.Duration) { for v := range result.rwCtlChan { if v < 0 { break } result.hook.OnStartTransmitting() time.Sleep(oneByteTime * time.Duration(v)) result.hook.OnEndTransmitting() } }(time.Duration(math.Ceil(float64(time.Second*(1+8+0+1)) / float64(result.speed)))) } // try open match := parser.FindStringSubmatch(result.serialMode) if len(match) != (1 + 3) { result.ctx = C.modbus_new_rtu(C.CString(result.deviceName), C.int(result.speed), C.char('N'), C.int(8), C.int(1)) } else { databits, _ := strconv.ParseInt(match[1+0], 10, 32) stopbits, _ := strconv.ParseInt(match[1+2], 10, 32) result.ctx = C.modbus_new_rtu(C.CString(result.deviceName), C.int(result.speed), C.char(match[1+1][0]), C.int(databits), C.int(stopbits)) } if result.ctx == nil { return nil, errors.New(fmt.Sprintf("Unable to create the libmodbus context\n%s", C.GoString(C.modbus_strerror(C.getErrno())))) } runtime.SetFinalizer(result, finaliserModbusRTUConnection) result.id = index index++ if len(ModbusRTUConnections) != 0 && ModbusRTUConnections[len(ModbusRTUConnections)-1] == nil { for i := len(ModbusRTUConnections) - 1; i > -1; i-- { if ModbusRTUConnections[i] != nil { ModbusRTUConnections[i+1] = result break } } } else { ModbusRTUConnections = append(ModbusRTUConnections, result) } return result, nil }