Repository navigation
Expand file tree
/
Copy pathprocess_image.go
More file actions
90 lines (80 loc) · 3.53 KB
/
Copy pathprocess_image.go
File metadata and controls
90 lines (80 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package ads
import (
"context"
"encoding/binary"
"fmt"
"math"
)
// Process Image I/O — EXPERIMENTAL. Direct access to the PLC's process image,
// bypassing the symbol table to read and write raw I/O memory.
//
// WARNING: a wrong offset can change physical outputs (motors, valves, actuators).
// The runtime may overwrite your write on the next scan, or conflict with the
// running program. For diagnostics, commissioning and I/O testing; prefer
// symbol-based access for normal operation.
// EXPERIMENTAL: ReadProcessInput reads bytes from the input process image at the given byte offset.
func (c *Client) ReadProcessInput(ctx context.Context, byteOffset, length uint32) ([]byte, error) {
return c.Read(ctx, uint32(GroupIoImageRwib), byteOffset, length)
}
// EXPERIMENTAL: ReadProcessOutput reads bytes from the output process image at the given byte offset.
func (c *Client) ReadProcessOutput(ctx context.Context, byteOffset, length uint32) ([]byte, error) {
return c.Read(ctx, uint32(GroupIoImageRwob), byteOffset, length)
}
// EXPERIMENTAL: WriteProcessOutput writes bytes to the output process image at the given byte offset.
func (c *Client) WriteProcessOutput(ctx context.Context, byteOffset uint32, data []byte) error {
return c.Write(ctx, uint32(GroupIoImageRwob), byteOffset, data)
}
// EXPERIMENTAL: ReadProcessInputBit reads a single bit from the input process image.
// bitIndex must be 0-7 (bit within a single byte).
func (c *Client) ReadProcessInputBit(ctx context.Context, byteOffset uint32, bitIndex uint8) (bool, error) {
if bitIndex > 7 {
return false, fmt.Errorf("bitIndex must be 0-7, got %d", bitIndex)
}
bitOffset := uint64(byteOffset)*8 + uint64(bitIndex)
if bitOffset > math.MaxUint32 {
return false, fmt.Errorf("byteOffset %d overflow: bit address %d exceeds uint32 max", byteOffset, bitOffset)
}
data, err := c.Read(ctx, uint32(GroupIoImageRwix), uint32(bitOffset), 1)
if err != nil {
return false, err
}
if len(data) < 1 {
return false, fmt.Errorf("ReadProcessInputBit: response too short (%d bytes)", len(data))
}
return data[0] != 0, nil
}
// EXPERIMENTAL: WriteProcessOutputBit writes a single bit to the output process image.
// bitIndex must be 0-7 (bit within a single byte).
func (c *Client) WriteProcessOutputBit(ctx context.Context, byteOffset uint32, bitIndex uint8, value bool) error {
if bitIndex > 7 {
return fmt.Errorf("bitIndex must be 0-7, got %d", bitIndex)
}
v := byte(0)
if value {
v = 1
}
bitOffset := uint64(byteOffset)*8 + uint64(bitIndex)
if bitOffset > math.MaxUint32 {
return fmt.Errorf("byteOffset %d overflow: bit address %d exceeds uint32 max", byteOffset, bitOffset)
}
return c.Write(ctx, uint32(GroupIoImageRwox), uint32(bitOffset), []byte{v})
}
// EXPERIMENTAL: ReadProcessInputSize returns the size of the input process image in bytes.
func (c *Client) ReadProcessInputSize(ctx context.Context) (uint32, error) {
data, err := c.Read(ctx, uint32(GroupIoImageRisize), 0, 4)
if err != nil {
return 0, err
}
if len(data) < 4 {
return 0, fmt.Errorf("ReadProcessInputSize: response too short (%d bytes)", len(data))
}
return binary.LittleEndian.Uint32(data), nil
}
// EXPERIMENTAL: ClearProcessInputs writes all input process image bytes to zero.
func (c *Client) ClearProcessInputs(ctx context.Context) error {
return c.Write(ctx, uint32(GroupIoImageCleari), 0, []byte{0})
}
// EXPERIMENTAL: ClearProcessOutputs writes all output process image bytes to zero.
func (c *Client) ClearProcessOutputs(ctx context.Context) error {
return c.Write(ctx, uint32(GroupIoImageClearo), 0, []byte{0})
}