fix: decode special log records in ReadRange without status flags#77
fix: decode special log records in ReadRange without status flags#77
Conversation
Special log records (log-interrupted, buffer-purged, log-disabled) use the log-status choice which does NOT include status flags. The previous code unconditionally consumed the status flags bytes, causing it to read into subsequent records and lose sync. This fix: - Validates closing tag 1 before consuming it - Checks for context tag 2 (status flags) presence before decoding - Adds support for log-status choice (context tag 0) - Adds isLogStatus and logStatus fields to differentiate special records - Adds comprehensive test for mixed normal and special log records Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
- Extract LogRecord, LogStatusFlags, LogRecordStatusFlags interfaces - Update ReadRangeAcknowledge.values to use LogRecord[] instead of any[] - Update decodeRange to return Decode<LogRecord[]> - Use assert.strictEqual for undefined checks in tests Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
robertsLando
left a comment
There was a problem hiding this comment.
ASHRAE 135 Standard Reference
This library implements ASHRAE Standard 135 (BACnet). Always consult the official specification and reference implementations when reviewing or implementing features:
[bacnet-stack](https://github.com/bacnet-stack/bacnet-stack) — The most widely used open-source BACnet implementation in C. Use as the primary source of truth for protocol behavior and packet formats.
[BACnet.org technical papers](https://bacnet.org/developer-resources/) — Free PDFs covering specific topics (foreign devices, BBMDs, routing, etc.)
[Wireshark BVLC dissector](https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-bvlc.c) — Useful for verifying packet formats and field layouts
When implementing or modifying protocol features, reference the relevant standard section in a code comment. Example:
// Encode object identifier per ASHRAE 135-2024 §20.2.14
encodeApplicationObjectId(buffer, objectType, instance)
There was a problem hiding this comment.
Pull request overview
Adds typed support for decoding BACnet TREND_LOG “log-status” records in ReadRange acknowledgements, including handling records that omit status flags per ASHRAE 135.
Changes:
- Extended
baAsn1.decodeRangeto decode thelog-datumCHOICE[0] log-statusand to tolerate missing status flags for log-status records. - Introduced
LogRecord(and related flag interfaces) and updatedReadRangeAcknowledge.valuesto use it. - Added a unit test covering mixed normal + log-status log records in a single range buffer.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| test/unit/service-read-range.spec.ts | Adds coverage for decoding log-status records that omit status flags. |
| src/lib/types.ts | Introduces LogRecord typing and narrows ReadRangeAcknowledge.values to LogRecord[]. |
| src/lib/asn1.ts | Updates decodeRange to parse log-status records and make status flags optional when appropriate. |
| src/lib/services/WriteProperty.ts | Formatting-only changes (no behavioral change). |
You can also share your feedback on Copilot code review. Take the survey.
Reference ASHRAE 135 Standard Section 12.25 for LogRecord structure in JSDoc comments for decodeRange function and LogRecord types. Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Added ASHRAE 135 §12.25 standard references to the |
|
@copilot Address review comments please. Ignore the ones marked as RESOLVED |
Address code review comments:
- Use BACNetBitString for bitstring casts instead of { value: number[] }
- Add LogRecordValue union type to narrow LogRecord.value from unknown
Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Addressed the unresolved review comments in commit
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Pull request overview
This pull request extends the ReadRange ACK decoding path to properly handle BACnet TREND_LOG “log-status” records (which omit status-flags), and adds stronger typing around decoded log records.
Changes:
- Add unit coverage for decoding log-status records without status flags in ReadRange acknowledgements.
- Introduce
LogRecord/ related types and updateReadRangeAcknowledge.valuestyping accordingly. - Update
decodeRangelogic to decode log-status choice records and treat status-flags as optional for non-log-status records.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| test/unit/service-read-range.spec.ts | Adds a regression test for decoding mixed normal + log-status log records. |
| src/lib/types.ts | Adds LogRecord-related types and updates ReadRangeAcknowledge.values to LogRecord[]. |
| src/lib/asn1.ts | Updates decodeRange to support log-status choice records and optional status-flags. |
| src/lib/services/WriteProperty.ts | Formatting-only changes. |
Comments suppressed due to low confidence (1)
src/lib/asn1.ts:2534
- The comment lists multiple
log-datumCHOICE alternatives, but the implementation currently only handles tag 0 (log-status), tag 2 (REAL), and some ENUMERATED cases. If other alternatives (e.g., boolean, unsigned, signed, null, string, object-id) appear,decodeRangewill returnundefinedandReadRangeAcknowledge.valueswill be omitted. Consider either decoding the remaining alternatives or making the supported subset explicit (and non-fatal) so mixed/other record types don't prevent returning parsed values for known records.
// log-datum [1] CHOICE per ASHRAE 135 §12.25:
// [0] log-status (BACnetLogStatus bitstring - special records)
// [1] boolean-value
// [2] real-value
// [3] enum-value
// [4] unsigned-value
// ... and more
tag = decodeTagNumberAndValue(buffer, offset + len)
len += tag.len
let value: ApplicationData | undefined
let isLogStatus = false
if (tag.tagNumber === 0) {
// log-status choice: BACnetLogStatus bitstring per ASHRAE 135 §12.25
// Special log records (log-disabled, buffer-purged, log-interrupted)
// do NOT have statusFlags [2] after the log-datum
value = bacappDecodeData(
buffer,
offset + len,
maxOffset,
ApplicationTag.BIT_STRING,
tag.value,
)
isLogStatus = true
} else if (tag.tagNumber === 2 && tag.value === 4) {
value = bacappDecodeData(
buffer,
offset + len,
maxOffset,
ApplicationTag.REAL,
tag.value,
)
} else if (tag.tagNumber === 4 && tag.value === 1) {
value = bacappDecodeData(
buffer,
offset + len,
maxOffset,
ApplicationTag.ENUMERATED,
tag.value,
)
} else if (tag.tagNumber === 3 && tag.value === 1) {
value = bacappDecodeData(
buffer,
offset + len,
maxOffset,
ApplicationTag.ENUMERATED,
tag.value,
)
}
You can also share your feedback on Copilot code review. Take the survey.
|
@copilot fix review |
Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Fixed in
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
robertsLando
left a comment
There was a problem hiding this comment.
@copilot Don't introduce unnecessary braking changes. Keep the previous property names in interfaces
Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Reverted in |
log-interrupted)decodeRangeunconditionally consumes closing tag 1 + context tag 2 (status flags), but special records only have closing tag 1 with no status flagsdecodeRangeinsrc/lib/asn1.ts:isLogStatusandlogStatusfields to differentiate special recordsLogRecord,LogStatusFlags,LogRecordStatusFlagsinterfaces to types.tsReadRangeAcknowledge.valuesto useLogRecord[]instead ofany[]decodeRangeto returnDecode<LogRecord[]>assert.strictEqualfor undefined checks in testsBACNetBitStringfor bitstring casts instead of{ value: number[] }LogRecordValueunion type to narrowLogRecord.valuefromunknownlog_disabled,buffer_purged,log_interrupted,out_of_service,in_alarm) to avoid breaking changesOriginal prompt
💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.