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
}