Other requests
Besides reads and controls, an association can send these requests. In Rust
they're methods of the AssociationHandle; in the bindings they're MasterChannel methods that take the association id.
| Request | Why |
|---|---|
Time synchronization (synchronize_time) | Sets the outstation's clock now, rather than when it asks for the time. See Time Synchronization. |
Cold or warm restart (cold_restart, warm_restart) | Restarts the outstation, and returns its estimate of how long the restart takes. |
| Freeze counters | Captures the counters' values at the same moment, or on a schedule. |
Write deadbands (write_dead_bands) | Tunes analog event reporting remotely. |
Generic request (send_and_expect_empty_response) | Sends writes and freezes that have no dedicated method. It succeeds when the outstation answers with no objects and doesn't reject the request. |
Link status check (check_link_status) | Checks that the outstation's link layer answers. It's for testing: prefer the keep-alive, which the master sends on its own (see Scheduling). |
Freezing counters
Freeze counters with the generic request, giving it a freeze function code and the counters it applies to. The outstation copies each counter to its frozen counter, and can also clear the counter or freeze it on a schedule. The example freezes all the counters once a day:
- Rust
- C
- C++
- Java
- C#
let headers = Headers::new()
// freeze all the counters once per day relative to the beginning of the current hour
.add_freeze_interval(FreezeInterval::PeriodicallyFreezeRelative(86_400_000))
// apply this schedule to all counters
.add_all_objects(Variation::Group20Var0);
self.association
.send_and_expect_empty_response(FunctionCode::FreezeAtTime, headers)
.await?;
dnp3_request_t *request = dnp3_request_create();
// freeze all the counters once per day relative to the beginning of the current hour
dnp3_request_add_time_and_interval(request, 0, 86400000);
// apply this schedule to all counters
dnp3_request_add_all_objects_header(request, DNP3_VARIATION_GROUP20_VAR0);
dnp3_empty_response_callback_t cb = {
.on_complete = &on_empty_response_complete,
.on_failure = &on_empty_response_failure,
.on_destroy = NULL,
.ctx = "fat",
};
dnp3_param_error_t err =
dnp3_master_channel_send_and_expect_empty_response(channel, association_id, DNP3_FUNCTION_CODE_FREEZE_AT_TIME, request, cb);
dnp3_request_destroy(request);
dnp3::Request request;
// freeze all the counters once per day relative to the beginning of the current hour
request.add_time_and_interval(0, 86400000);
// apply this schedule to all counters
request.add_all_objects_header(dnp3::Variation::group20_var0);
channel.send_and_expect_empty_response(assoc, dnp3::FunctionCode::freeze_at_time, request, create_empty_response_callback("fat"));
Request request = new Request();
// freeze all the counters once per day relative to the beginning of the current hour
request.addTimeAndInterval(ulong(0), uint(86400000));
// apply this schedule to all counters
request.addAllObjectsHeader(Variation.GROUP20_VAR0);
channel.sendAndExpectEmptyResponse(association, FunctionCode.FREEZE_AT_TIME, request).toCompletableFuture().get();
var request = new Request();
// freeze all the counters once per day relative to the beginning of the current hour
request.AddTimeAndInterval(0, 86400000);
// apply this schedule to all counters
request.AddAllObjectsHeader(Variation.Group20Var0);
await channel.SendAndExpectEmptyResponse(association, FunctionCode.FreezeAtTime, request);
Writing deadbands
A deadband is how much an analog input has to change before the outstation reports an event. Writing deadbands lets you tune event reporting without visiting the device. An outstation that should keep them across a restart saves them in its saving callbacks. To check the values, read the analog input deadbands back: they arrive at the ReadHandler.
- Rust
- C
- C++
- Java
- C#
self.association
.write_dead_bands(vec![
DeadBandHeader::group34_var1_u8(vec![(3, 5)]),
DeadBandHeader::group34_var3_u16(vec![(4, 2.5)]),
])
.await?
dnp3_write_dead_band_request_t *request = dnp3_write_dead_band_request_create();
dnp3_write_dead_band_request_add_g34v1_u8(request, 3, 5);
dnp3_write_dead_band_request_add_g34v3_u16(request, 4, 2.5f);
dnp3_empty_response_callback_t cb = {
.on_complete = &on_empty_response_complete,
.on_failure = &on_empty_response_failure,
.on_destroy = NULL,
.ctx = "wad",
};
dnp3_param_error_t err = dnp3_master_channel_write_dead_bands(channel, association_id, request, cb);
dnp3_write_dead_band_request_destroy(request);
dnp3::WriteDeadBandRequest request;
request.add_g34v1_u8(3, 5);
request.add_g34v3_u16(4, 2.5);
channel.write_dead_bands(assoc, request, create_empty_response_callback("wad"));
WriteDeadBandRequest request = new WriteDeadBandRequest();
request.addG34v1U8(ubyte(3), ushort(5));
request.addG34v3U16(ushort(4), 2.5f);
channel.writeDeadBands(association, request).toCompletableFuture().get();
var request = new WriteDeadBandRequest();
request.AddG34v1U8(3, 5);
request.AddG34v3U16(4, 2.5f);
await channel.WriteDeadBands(association, request);