Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implementation of Function Code FC23 (0x17) - Read/Write Multiple Registers #132

Open
wants to merge 125 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
2723204
feat: implement send/receive custom buffer
thr2240 Dec 6, 2023
30463e6
Merge pull request #1 from thr2240/boris/custom-buffer
biancode Dec 6, 2023
3a07ec1
chore: fix client and server ports for Unix-based architectures with …
dkoehler-dev Jan 17, 2024
c9c7923
chore: Implement placeholder commands for read/write custom function …
dkoehler-dev Jan 18, 2024
ad140d6
feat: Implement request building for custom function code
dkoehler-dev Jan 18, 2024
bc84c5e
feat: Declare custom function code module
dkoehler-dev Jan 18, 2024
e42d375
feat: Add 'write custom function code' as function code
dkoehler-dev Jan 18, 2024
6288b90
feat: Implement 'write custom function code' functionality into the m…
dkoehler-dev Jan 18, 2024
284e8d9
feat: Implement 'write custom function code' in channel handler
dkoehler-dev Jan 18, 2024
d0b381f
feat: Implement 'write custom function code' in client example
dkoehler-dev Jan 18, 2024
fc3d8b4
feat: Implement 'write custom function code' in server request handler
dkoehler-dev Jan 18, 2024
10c81d9
feat: Implement 'write custom function code' in server handler & serv…
dkoehler-dev Jan 18, 2024
a232ef3
feat: Implement 'write custom function code' in frame handler
dkoehler-dev Jan 18, 2024
d6c7a31
feat: Add CustomFC type; Implement client request for CustomFC type
dkoehler-dev Jan 19, 2024
6d6d916
feat: Implement CustomFC Display trait
dkoehler-dev Jan 19, 2024
90744c1
feat: Implement CustomFC type in client-side request
dkoehler-dev Jan 19, 2024
38b3404
fix: Implement UnitId Display trait
dkoehler-dev Jan 22, 2024
fa71af4
chore: Replace write custom FC client request parameter
dkoehler-dev Jan 22, 2024
788be9f
fix: Implement BitIterator parse_all fn
dkoehler-dev Jan 22, 2024
1934f3d
fix: Implement missing documentation for CustomFunctionCode fn
dkoehler-dev Jan 22, 2024
476e5ea
chore: Set tracing level to DEBUG
dkoehler-dev Jan 22, 2024
ea4f641
fix: Implement customFC type in server-side request
dkoehler-dev Jan 22, 2024
debeaa1
feat: Implement custom function code parser
dkoehler-dev Jan 22, 2024
9a9eaf4
feat: Implement Serialize & Loggable traits for CustomFunctionCode
dkoehler-dev Jan 22, 2024
c1d5e68
fix: Replace Vec<u16> with a fixed-size array for now, to work around…
dkoehler-dev Jan 23, 2024
d71bf86
fix: Implement missing customFC request in server-side request handling
dkoehler-dev Jan 23, 2024
5bd36f1
fix: Implement correct CustomFunctionCode value parsing
dkoehler-dev Jan 24, 2024
bff9685
fix: Implement customFC length attribute
dkoehler-dev Jan 24, 2024
8954e36
feat: Improved server and client examples for custom function code fe…
dkoehler-dev Jan 24, 2024
2719e74
chore: Improve type naming of the custom function code feature
dkoehler-dev Jan 24, 2024
be8eba7
chore: Improve server and client examples for write custom function c…
dkoehler-dev Jan 24, 2024
6438e99
chore: Set server and client port in examples >1024 for non-root linu…
dkoehler-dev Jan 25, 2024
8ae0812
fix: Authorize Write Custom Function Code Request in server handler (…
dkoehler-dev Jan 25, 2024
3504b1d
fix: Correct logged offset server PDU TX values for the Custom Functi…
dkoehler-dev Jan 25, 2024
21413af
test: Add Custom Function Code feature parsing unit test
dkoehler-dev Jan 25, 2024
570aefb
test: Add Custom Function Code parsing unit test for invalid values
dkoehler-dev Jan 25, 2024
7479461
test: Add Custom Function Code serializing unit test
dkoehler-dev Jan 25, 2024
7248688
test: Add Custom Function Code integration test
dkoehler-dev Jan 25, 2024
116c97b
refactor: Improve client example script for the Custom Function Code …
dkoehler-dev Jan 26, 2024
51cd999
test: Add integration test for the Custom Function Code feature
dkoehler-dev Jan 26, 2024
e2c80ce
fix: Resolve immutable server handler value for the Custom Function C…
dkoehler-dev Jan 26, 2024
15dd7e6
refactor(client): code cleanup
dkoehler-dev Jan 26, 2024
6e4f068
refactor(server): code cleanup
dkoehler-dev Jan 26, 2024
28d4381
refactor(parse): code cleanup
dkoehler-dev Jan 26, 2024
81f6188
docs(write_custom_function_code): Add documentation for write custom …
dkoehler-dev Jan 26, 2024
4a9ce9b
Merge pull request #3 from dkoehler-dev/development
biancode Jan 27, 2024
1926d68
chore(send_cfc): Rename CFC README.me
dkoehler-dev Jan 29, 2024
cf2a350
fix(examples): Adjust TCP & TLS port for non-root Unix users
dkoehler-dev Jan 29, 2024
fcb4beb
refactor(custom_fc): Rename WriteCustomFC to SendCustomFC
dkoehler-dev Jan 29, 2024
7054730
refactor(custom_fc): Remove SendCustomBuffer functionality (PR 2 on I…
dkoehler-dev Jan 29, 2024
699c3d4
Revert "refactor(custom_fc): Remove SendCustomBuffer functionality (P…
dkoehler-dev Jan 30, 2024
a74d50f
Revert "refactor(custom_fc): Rename WriteCustomFC to SendCustomFC"
dkoehler-dev Jan 30, 2024
07e0703
Revert "fix(examples): Adjust TCP & TLS port for non-root Unix users"
dkoehler-dev Jan 30, 2024
3a4715f
Revert "chore(send_cfc): Rename CFC README.me"
dkoehler-dev Jan 30, 2024
068b7af
refactor(send_custom_buffer): Remove Send Custom Buffer functionality
dkoehler-dev Jan 30, 2024
112face
feat(function): add FC23 to FunctionCode enum
dkoehler-dev Jan 30, 2024
ec9b803
feat(client): add FC23 feature to client example
dkoehler-dev Jan 30, 2024
684229a
feat(message): add FC23 request to client message handler
dkoehler-dev Jan 30, 2024
47ffc89
feat(mod): add FC23 to client requests mod file
dkoehler-dev Jan 30, 2024
82537ba
feat(channel): add FC23 feature to channel request
dkoehler-dev Jan 30, 2024
47d3aff
feat(read_write_multiple): add FC23 requests file
dkoehler-dev Jan 30, 2024
8a071b8
feat(serialize): add serialize trait for FC23
dkoehler-dev Jan 30, 2024
3aa288a
refactor(channel): correct FC23 channel request parameters
dkoehler-dev Jan 30, 2024
99f9e09
fix(message): resolve client message request error (iter() not defined)
dkoehler-dev Jan 30, 2024
6c5abc2
chore(serialize): Remove serialization logic for ReadWriteMultiple<Re…
dkoehler-dev Jan 30, 2024
611d872
feat(types): add ReadWriteMultipleRegistersRange type
dkoehler-dev Jan 31, 2024
c192005
refactor(message): refactor read_write_multiple imports
dkoehler-dev Jan 31, 2024
6c8ac0a
fix(read_write_multiple): fix read_write_multiple client request types
dkoehler-dev Jan 31, 2024
bc32138
fix(channel): fix channel input parameters for read_write_multiple re…
dkoehler-dev Jan 31, 2024
c52d33c
fix(serialize): resolve wrong variable call when serializing read_wri…
dkoehler-dev Jan 31, 2024
1c44640
fix(message): resolve type mismatch in ReadWriteMultipleRegisters req…
dkoehler-dev Jan 31, 2024
69a0af7
fix(read_write_multiple): Fix incorrect ReadWriteMultiple initialization
dkoehler-dev Jan 31, 2024
3cb58e5
fix(channel): fix read_write_multiple channel request parameters
dkoehler-dev Jan 31, 2024
cc76e50
fix(serial frame): Implement serial request/response lengthmode for R…
dkoehler-dev Jan 31, 2024
9d4139e
feat(request): add ReadWriteMultipleRegisters FC to server request ha…
dkoehler-dev Jan 31, 2024
049f321
fix(types): remove ReadWriteMultipleRegistersRange from types (new fn…
dkoehler-dev Jan 31, 2024
0295bca
fix(read_write_multiple): remove ReadWriteMultipleIterator implementa…
dkoehler-dev Jan 31, 2024
545a393
fix(client): fix incorrect request parameters for ReadWriteMultipleRe…
dkoehler-dev Jan 31, 2024
1bcec6f
fix(read_write_multiple): fix return type and struct access for ReadW…
dkoehler-dev Jan 31, 2024
1f61df7
fix(client): correct channel request parameters and return values for…
dkoehler-dev Jan 31, 2024
451c64f
refactor(channel): change channel Result type from Indexed<u16> to Ve…
dkoehler-dev Feb 1, 2024
020ae45
refactor(read_write_multiple): change Promise and Result type from In…
dkoehler-dev Feb 1, 2024
ab2daf0
feat(handler): add FC23 request authorization to server handler
dkoehler-dev Feb 1, 2024
0d15398
feat(server types): add ReadWriteRegisters struct to server-side type…
dkoehler-dev Feb 1, 2024
7994ed2
feat(server types): add ReadWriteRegisters type to server handler (FC23)
dkoehler-dev Feb 1, 2024
b8f21e3
feat(server types): add ReadWriteRegisters type to server-side reques…
dkoehler-dev Feb 1, 2024
b77d5dc
fix(client): fix missing ReadWriteMultiple import in client mod
dkoehler-dev Feb 2, 2024
10dd7f8
feat(examples): set TCP port to 10502 and TLS port to 10802 for non-r…
dkoehler-dev Feb 2, 2024
a6e1e5b
fix(read_write_multiple): fix invalid ReadWriteMultiple request initi…
dkoehler-dev Feb 2, 2024
5bff927
fix(message): reference the correct Iterator for the ReadWriteMultipl…
dkoehler-dev Feb 2, 2024
028bb37
fix(client example): supply correct input parameters for the ReadWrit…
dkoehler-dev Feb 2, 2024
723bd77
fix(message): add proper PDU TX formatting for the ReadWriteMultipleR…
dkoehler-dev Feb 2, 2024
c0ba984
chore(client example): expand log output decoding
dkoehler-dev Feb 2, 2024
610b779
chore(message): correct PDU TX log output for the ReadWriteMultipleRe…
dkoehler-dev Feb 2, 2024
5eaf82d
chore(server example): expand log output decoding
dkoehler-dev Feb 2, 2024
841391e
fix(server handler): authorize read_write_multiple_registers request …
dkoehler-dev Feb 2, 2024
03bb731
fix(server request): add correct parsing for the server-side ReadWrit…
dkoehler-dev Feb 2, 2024
03bda0d
refactor(server request): correct ReadWriteMultipleRequest
dkoehler-dev Feb 2, 2024
a27c66b
chore(client example): set response timeout to 15min for debugging pu…
dkoehler-dev Feb 2, 2024
f304fbe
chore(client example): adjusted FC23 example request parameters
dkoehler-dev Feb 5, 2024
95b333d
refactor(channel): change Result type of FC23 request to AddressRange
dkoehler-dev Feb 5, 2024
87f2903
refactor(server request): modify FC23 server request handler for easi…
dkoehler-dev Feb 5, 2024
483637a
refactor(read_write_multiple): change Promise type of FC23 request to…
dkoehler-dev Feb 5, 2024
25e0c6a
test(client example): adjust test parameters for FC23 request (ReadWr…
dkoehler-dev Feb 5, 2024
8ab0da9
fix(server request): fix incorrect FC23 (ReadWriteMultiple) server re…
dkoehler-dev Feb 5, 2024
93c6d8b
refactor(read_write_multiple request): remove unnecessary write respo…
dkoehler-dev Feb 6, 2024
ee93153
fix(read_write_multiple): implement correct response parsing for FC23…
dkoehler-dev Feb 6, 2024
eac7e6a
fix(channel): add correct Result type for FC23 request type
dkoehler-dev Feb 6, 2024
5fa8c8b
refactor(request): ignore write result from FC23 (ReadWriteMultiple)
dkoehler-dev Feb 6, 2024
c88fafa
test(client example): adjust example parameters for FC23 request
dkoehler-dev Feb 6, 2024
3235826
fix(client example): fix invalid input parameter `count`
dkoehler-dev Feb 7, 2024
d3f18a1
feat(server example): add a separate read_write_multiple server handl…
dkoehler-dev Feb 7, 2024
ce640f6
fix(server request): add read_write_multiple_registers server request…
dkoehler-dev Feb 7, 2024
bad8533
fix(request): fix incorrect read_write_multiple server request handle…
dkoehler-dev Feb 7, 2024
4beabe2
refactor(read_write_multiple): change InvalidRequest Result to Reques…
dkoehler-dev Feb 7, 2024
7208b18
feat(parse): implement parsing for FC23 request and add unit test for…
dkoehler-dev Feb 7, 2024
653d598
test(serialize): add FC23 (ReadWriteMultipleRegisters) unit tests for…
dkoehler-dev Feb 8, 2024
355537a
refactor(serialize): improve naming of unit tests for FC23
dkoehler-dev Feb 8, 2024
76dfc66
test(parse): add FC23 (ReadWriteMultipleRegisters) unit tests for suc…
dkoehler-dev Feb 8, 2024
50881ab
test(integration_test): add integration test for the FC23 (ReadWriteM…
dkoehler-dev Feb 9, 2024
c0337b3
chore: clean up code, improve code documentation
dkoehler-dev Feb 9, 2024
e29a69c
doc(read_write_multiple): add request documentation for FC23 (ReadWri…
dkoehler-dev Feb 9, 2024
aa3e323
test(request): add read_write_multiple request parsing unit test cases
dkoehler-dev Feb 13, 2024
b6d913f
test(read_write_multiple): fix integration test for FC23 read_write_m…
dkoehler-dev Feb 14, 2024
2b00be8
Merge pull request #5 from dkoehler-dev/feature-fc23-read-write-multi…
grewek Feb 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions rodbus/RWMR_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 23 (0x17) Read/Write Multiple registers

This document provides an overview of the Function Code 23 (0x17) (Read & Write Multiple Registers) request as specified in the MODBUS Application Protocol.


## Description
This function code performs a combination of one read operation and one write operation in a single MODBUS transaction. The write operation is performed before the read.

The request specifies the starting address and number of holding registers to be read as well as the starting address, number of holding registers, and the data to be written. The byte count specifies the number of bytes to follow in the write data field.

The normal response contains the data from the group of registers that were read. The byte count field specifies the quantity of bytes to follow in the read data field.


## Request Structure
| Parameter | Size | Range / Value |
|------------------------|--------------|--------------------------|
| Function code | 1 Byte | 0x17 |
| Read Starting Address | 2 Bytes | 0x0000 to 0xFFFF |
| Quantity to Read | 2 Bytes | 0x0001 to 0x007D |
| Write Starting Address | 2 Bytes | 0x0000 to 0xFFFF |
| Quantity to Write | 2 Bytes | 0x0001 to 0x0079 |
| Write Byte Count | 1 Byte | 2 x N* |
| Write Registers Value | N* x 2 Bytes | |
( N* = Quantity to Write )

## Response Structure
| Parameter | Size | Value / Description |
|----------------------|--------------|------------------------|
| Function code | 1 Byte | 0x17 |
| Byte Count | 1 Byte | 2 x N* |
| Read Registers value | N* x 2 Bytes | |
( N* = Quantity to Read )

## Error Handling
| Parameter | Size | Description |
|----------------|---------|-----------------------------------|
| Error code | 1 Byte | Function code + 0x80 = 0x97 (151) |
| Exception code | 1 Byte | 01 or 02 or 03 or 04 |

### Error Codes:
- **01**: Illegal Function
- **02**: Illegal Data Address
- **03**: Illegal Data Value
- **04**: Server Device Failure


## Example
Here is an example of a request to read six registers starting at register 4, and to write three
registers starting at register 15:

| Request Field | Hex | Response Field | Hex |
|--------------------------------|-----|----------------------------|-----|
| Function | 17 | Function | 17 |
| Read Starting Address Hi | 00 | Byte Count | 0C |
| Read Starting Address Lo | 03 | Read Registers value Hi | 00 |
| Quantity to Read Hi | 00 | Read Registers value Lo | FE |
| Quantity to Read Lo | 06 | Read Registers value Hi | 0A |
| Write Starting Address Hi | 00 | Read Registers value Lo | CD |
| Write Starting Address Lo | 0E | Read Registers value Hi | 00 |
| Quantity to Write Hi | 00 | Read Registers value Lo | 01 |
| Quantity to Write Lo | 03 | Read Registers value Hi | 00 |
| Write Byte Count | 06 | Read Registers value Lo | 03 |
| Write Registers Value Hi (1st) | 00 | Read Registers value Hi | 00 |
| Write Registers Value Lo (1st) | FF | Read Registers value Lo | 0D |
| Write Registers Value Hi (2nd) | 00 | Read Registers value Hi | 00 |
| Write Registers Value Lo (2nd) | FF | Read Registers value Lo | FF |
| Write Registers Value Hi (3rd) | 00 | | |
| Write Registers Value Lo (3rd) | FF | | |


## Troubleshooting Tips
- Ensure the server and client are using the same communication method and are connected to each other
- Check for any returned error code in the response and refer to the error handling section for resolution


## Additional Resources
- For more information on the MODBUS protocol and function codes, refer to the [MODBUS Application Protocol Specification V1.1b3](https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf), Page 38 (Read/Write Multiple registers).
64 changes: 64 additions & 0 deletions rodbus/WCFC_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 69 (0x45) Write Custom Function Code

This document provides a detailed overview of the custom function code (0x45) used in the MODBUS Application Protocol. This function code is user-defined and falls within the range of 65 to 72, as specified in the MODBUS Application Protocol Specification V1.1b3 (Page 10, Section 5: Function Code Categories).


## Introduction
The 0x45 function code enables the implementation of user-defined logic on a remote server device. It facilitates the transmission, reception, and processing of a custom function code with a fixed-size data buffer. This buffer currently supports 4 arguments, each 2 bytes (u16) in size, allowing for the execution of custom logic remotely.

**Note:** To increase flexibility, support for a variable-length data buffer will be included in a future update.


## Request Structure
| Parameter | Size | Range / Value |
|--------------------|----------|-----------------------|
| Function code | 1 Byte | 0x45 |
| Length | 2 Bytes | 0x0004 |
| Data | 8 Bytes | 0x0000 to 0xFFFF |


## Response Structure
| Parameter | Size | Value/Description |
|---------------|---------|----------------------|
| Function code | 1 Byte | 0x45 |
| Length | 2 Bytes | 0x0004 |
| Data | 8 Bytes | 0x0000 to 0xFFFF |


## Error Handling
| Parameter | Size | Description |
|----------------|---------|-----------------------------------|
| Function code | 1 Byte | Function code + 0x80 = 0xC5 (197) |
| Exception code | 1 Byte | 01 or 02 or 03 or 04 |

### Error Codes:
- **01**: Illegal Function
- **02**: Illegal Data Address
- **03**: Illegal Data Value
- **04**: Server Device Failure


## Usage Example
### Request to send the custom buffer [0xC0, 0xDE, 0xCA, 0xFE]:

| Request Field | Hex | Response Field | Hex |
|---------------------------|-----|------------------------|-----|
| Function | 45 | Function | 45 |
| Length | 04 | Byte Count | 04 |
| Arg1 | C0 | Arg1 | C0 |
| Arg2 | DE | Arg2 | DE |
| Arg3 | CA | Arg3 | CA |
| Arg4 | FE | Arg4 | FE |


## Modify and Test Server-Side Buffer Handling
The server currently forwards the Custom Function Code buffer to the client again without alteration. To test modifying or processing the buffer on the remote server device, edit the `write_custom_function_code()` function in `src/examples/client.rs` and `src/examples/server.rs` as needed.


## Troubleshooting Tips
- Ensure the server and client are using the same communication and are connected to each other.
- Check for any error codes in the response and refer to the error handling section for resolution.


## Additional Resources
- For more information on the MODBUS protocol and function codes, refer to the [MODBUS Application Protocol Specification V1.1b3](https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf).
39 changes: 34 additions & 5 deletions rodbus/examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ where
async fn run_tcp() -> Result<(), Box<dyn std::error::Error>> {
// ANCHOR: create_tcp_channel
let channel = spawn_tcp_client_task(
HostAddr::ip(IpAddr::V4(Ipv4Addr::LOCALHOST), 502),
HostAddr::ip(IpAddr::V4(Ipv4Addr::LOCALHOST), 10502),
1,
default_retry_strategy(),
DecodeLevel::default(),
Expand Down Expand Up @@ -96,7 +96,7 @@ async fn run_rtu() -> Result<(), Box<dyn std::error::Error>> {
async fn run_tls(tls_config: TlsClientConfig) -> Result<(), Box<dyn std::error::Error>> {
// ANCHOR: create_tls_channel
let channel = spawn_tls_client_task(
HostAddr::ip(IpAddr::V4(Ipv4Addr::LOCALHOST), 802),
HostAddr::ip(IpAddr::V4(Ipv4Addr::LOCALHOST), 10802),
1,
default_retry_strategy(),
tls_config,
Expand Down Expand Up @@ -178,7 +178,7 @@ async fn run_channel(mut channel: Channel) -> Result<(), Box<dyn std::error::Err
channel.enable().await?;

// ANCHOR: request_param
let params = RequestParam::new(UnitId::new(1), Duration::from_secs(1));
let params = RequestParam::new(UnitId::new(1), Duration::from_secs(900));
// ANCHOR_END: request_param

let mut reader = FramedRead::new(tokio::io::stdin(), LinesCodec::new());
Expand All @@ -198,8 +198,8 @@ async fn run_channel(mut channel: Channel) -> Result<(), Box<dyn std::error::Err
channel
.set_decode_level(DecodeLevel::new(
AppDecodeLevel::DataValues,
FrameDecodeLevel::Header,
PhysDecodeLevel::Length,
FrameDecodeLevel::Payload,
PhysDecodeLevel::Data,
))
.await?;
}
Expand Down Expand Up @@ -267,6 +267,35 @@ async fn run_channel(mut channel: Channel) -> Result<(), Box<dyn std::error::Err
print_write_result(result);
// ANCHOR_END: write_multiple_registers
}
"rwmr" => {
// ANCHOR: read_write_multiple_registers
let read_range = AddressRange::try_from(0x01, 0x04).unwrap();
let write_range = AddressRange::try_from(0x01, 0x04).unwrap();
let write_values = vec![0xC0DE, 0xCAFE, 0xC0DE, 0xCAFE];

let result = channel
.read_write_multiple_registers(
params,
ReadWriteMultiple::new(read_range, write_range, write_values).unwrap(),
)
.await;
print_write_result(result);
// ANCHOR_END: read_write_multiple_registers
}
"wcfc" => {
// ANCHOR: write_custom_function_code
let length = 0x04 as usize;
let values = [0xC0, 0xDE, 0xCA, 0xFE]; // i.e.: Voltage Hi = 0xC0 / Voltage Lo = 0xDE / Current Hi = 0xCA / Current Lo = 0xFE

let result = channel
.write_custom_function_code(
params,
CustomFunctionCode::new(length, values)
)
.await;
print_write_result(result);
// ANCHOR_END: write_custom_function_code
}
_ => println!("unknown command"),
}
}
Expand Down
18 changes: 14 additions & 4 deletions rodbus/examples/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ impl RequestHandler for SimpleHandler {
}
}

fn write_custom_function_code(&mut self, values: CustomFunctionCode) -> Result<(), ExceptionCode> {
let mut custom_fc_args = [0_u16; 4]; // i.e.: Voltage Hi = 0x02, Voltage Lo = 0x03, Current Hi = 0x04, Current Lo = 0x05
for (i, &value) in values.iter().enumerate() {
custom_fc_args[i] = value;
}
tracing::info!("processing custom function code arguments: {:?}", custom_fc_args);

Ok(())
}

fn write_single_register(&mut self, value: Indexed<u16>) -> Result<(), ExceptionCode> {
tracing::info!(
"write single register, index: {} value: {}",
Expand Down Expand Up @@ -167,7 +177,7 @@ async fn run_tcp() -> Result<(), Box<dyn std::error::Error>> {
// ANCHOR: tcp_server_create
let server = rodbus::server::spawn_tcp_server_task(
1,
"127.0.0.1:502".parse()?,
"127.0.0.1:10502".parse()?,
map,
AddressFilter::Any,
DecodeLevel::default(),
Expand Down Expand Up @@ -206,7 +216,7 @@ async fn run_tls(tls_config: TlsServerConfig) -> Result<(), Box<dyn std::error::
// ANCHOR: tls_server_create
let server = rodbus::server::spawn_tls_server_task_with_authz(
1,
"127.0.0.1:802".parse()?,
"127.0.0.1:10802".parse()?,
map,
ReadOnlyAuthorizationHandler::create(),
tls_config,
Expand Down Expand Up @@ -281,8 +291,8 @@ async fn run_server(
server
.set_decode_level(DecodeLevel::new(
AppDecodeLevel::DataValues,
FrameDecodeLevel::Header,
PhysDecodeLevel::Length,
FrameDecodeLevel::Payload,
PhysDecodeLevel::Data,
))
.await?;
}
Expand Down
38 changes: 37 additions & 1 deletion rodbus/src/client/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ use crate::client::requests::read_bits::ReadBits;
use crate::client::requests::read_registers::ReadRegisters;
use crate::client::requests::write_multiple::{MultipleWriteRequest, WriteMultiple};
use crate::client::requests::write_single::SingleWrite;
use crate::client::requests::read_write_multiple::{MultipleReadWriteRequest, ReadWriteMultiple};
use crate::client::requests::write_custom_fc::WriteCustomFunctionCode;
use crate::error::*;
use crate::types::{AddressRange, BitIterator, Indexed, RegisterIterator, UnitId};
use crate::types::{AddressRange, BitIterator, Indexed, RegisterIterator, UnitId, CustomFunctionCode};
use crate::DecodeLevel;


/// Async channel used to make requests
#[derive(Debug, Clone)]
pub struct Channel {
Expand Down Expand Up @@ -163,6 +166,21 @@ impl Channel {
rx.await?
}

/// Write a Custom Function Code to the server
pub async fn write_custom_function_code(
&mut self,
param: RequestParam,
request: CustomFunctionCode,
) -> Result<CustomFunctionCode, RequestError> {
let (tx, rx) = tokio::sync::oneshot::channel::<Result<CustomFunctionCode, RequestError>>();
let request = wrap(
param,
RequestDetails::WriteCustomFunctionCode(WriteCustomFunctionCode::new(request, Promise::channel(tx))),
);
self.tx.send(request).await?;
rx.await?
}

/// Write a single coil on the server
pub async fn write_single_coil(
&mut self,
Expand Down Expand Up @@ -229,6 +247,24 @@ impl Channel {
rx.await?
}

/// Read & Write multiple contiguous registers on the server
pub async fn read_write_multiple_registers(
&mut self,
param: RequestParam,
request: ReadWriteMultiple<u16>,
) -> Result<Vec<Indexed<u16>>, RequestError> {
let (tx, rx) = tokio::sync::oneshot::channel::<Result<Vec<Indexed<u16>>, RequestError>>();
let request = wrap(
param,
RequestDetails::ReadWriteMultipleRegisters(MultipleReadWriteRequest::new(
request,
Promise::channel(tx)
)),
);
self.tx.send(request).await?;
rx.await?
}

/// Dynamically change the protocol decoding level of the channel
pub async fn set_decode_level(&mut self, level: DecodeLevel) -> Result<(), Shutdown> {
self.tx
Expand Down
Loading