bacnet-stack

repository·master·Indexed 20 days ago

https://github.com/bacnet-stack/bacnet-stack

An open-source, royalty-free C library implementing the BACnet protocol stack for embedded systems, RTOS, and full operating systems including Linux, Windows, and macOS. The repository includes various applications such as a GTK Discovery Application, a Modbus RTU ↔ BACnet Gateway, and fuzzing targets using AFL and libFuzzer.

Tokens
72.8K
Snippets
186
Records
318
Agent score
69%

What's inside bacnet-stack

  1. Overview of the Modbus RTU ↔ BACnet Gateway

    master

    The Modbus RTU ↔ BACnet Gateway is a generic bridge that connects Modbus RTU devices to a BACnet network. It reads Modbus registers or coils from one or more slaves and exposes them as BACnet objects, such as Analog Input (AI), Analog Output (AO), Binary Input (BI), or Binary Output (BO).

    Configuration is handled via a single gateway_config.json file at runtime. The gateway supports multiple BACnet datalink types, including mstp, bip, bip6, ethernet, and bsc (BACnet/SC).

  2. Overview of uBASIC+BACnet

    master

    uBASIC+BACnet is an extended BASIC interpreter designed for embedded systems. It builds upon the original uBasic by Adam Dunkels and incorporates string support from David Mitchell, CHDK-style scripting constructs, and specialized BACnet keywords.

    Key architectural features include:

    • Multi-program support: Enables multiple uBASIC programs to run concurrently.
    • Callback-based Hardware Abstraction Layer (HAL): Allows the interpreter to be ported to various hardware platforms by implementing specific hardware callbacks.
    • BACnet Integration: Provides native keywords to create, read, and write BACnet objects and properties directly from scripts.
  3. Run the BACnet Simple Router Demo

    master
    The BACnet Simple Router demo is designed to bridge a BACnet/IP network and a BACnet/IPv6 network. It includes a BBMD (BACnet Broadcast Management Device) implementation, which enables Foreign Device Registration. This allows you to tunnel local command line demos across both BACnet/IP and BACnet/IPv6 networks.
  4. Handle Priority Array writes and evaluation

    master

    When implementing objects with a Priority_Array (like Output objects), follow these rules to ensure stability and prevent race conditions:

    1. Level 6 Reservation: Never use Priority Level 6 for any purpose other than the Minimum On/Off Time algorithm. It is reserved by the BACnet standard.
    2. Immediate Re-evaluation: When the Present_Value of an object containing a Priority_Array is written, you must re-evaluate the array and update the Present_Value before the next service is processed. Ideally, this should happen before the write is acknowledged to avoid race conditions where a subsequent ReadProperty request returns stale data.
    3. Fallback for Resource-Constrained Devices: If a device cannot afford the memory/overhead of a priority array for an "Output" object, use a "Value" object (e.g., a Binary Value instead of a Binary Output) which is not required to have a priority array.
  5. Handle variable Bit String lengths for Protocol properties

    master
    Client devices must be prepared to handle Bit String values for Protocol_Services_Supported and Protocol_Object_Types_Supported that vary in length based on the server's protocol revision. Do not assume a fixed length based on your own implementation's revision; always be prepared to accept strings that are longer or shorter than your local definition.
  6. Implement COV (Change of Value) subscriptions correctly

    master

    When implementing Change of Value (COV) services, follow these rules to ensure interoperability and prevent resource exhaustion:

    • Avoid Indefinite Lifetimes: Do not issue SubscribeCOV or SubscribeCOVProperty requests with a Lifetime parameter set to zero. This prevents permanent allocation of storage for removed devices and ensures subscriptions can be recovered after resets.
    • Use Non-Zero Lifetimes: Issue subscriptions with a non-zero Lifetime (e.g., the duration acceptable for operating with out-of-date data) and refresh them periodically.
    • Handle Failures: If a COV subscription fails, the client should fall back to polling for data and/or notifying the operator.
    • Server Lifetime Support: COV servers must support all lifetime values between 1 and 28,800 seconds (8 hours).
    • Client Lifetime Support: COV clients must be able to subscribe with a lifetime within the 1 to 28,800 second range.
    • Proprietary Object Notifications: COV notifications from proprietary objects should include Present_Value and Status_Flags for consistency with standard objects.
  7. Implement robust BACnet communication and error handling

    master

    When implementing a BACnet device or client, follow these interoperability guidelines to ensure compatibility with other BTL-listed devices:

    • Avoid Assumptions: Do not assume a peer supports optional properties, services, or protocol revisions. Always be prepared to communicate with devices using earlier protocol revisions.
    • Implement Fallbacks: If an optional feature (like COV subscription) is unavailable or rejected, fall back to a required feature (like polling).
    • Handle Service Forms: If a device supports a service, it must support all forms of that service (including all parameter variations) unless specifically exempted by the standard.
    • Don't Give Up on Communication: If a confirmed service request fails after all retries, do not stop attempting to communicate. If using dynamic binding (Who-Is/Who-Has), periodically re-initiate these requests to re-locate the device or object.
    • Handle Future Changes: Implement parsers that can handle expanded ASN.1 choices or new enumeration values (like BACnetPropertyIdentifier) without crashing.
  8. Handle BACnet address conflicts and validation

    master

    The coordinator manages address integrity in the BZLL network.

    Conflict Resolution

    If the coordinator detects duplicate or invalid addresses, it may perform a Write Attribute operation on the target node's Protocol Address. Upon receiving a new address, the node must:

    1. Update its internal BACnet address.
    2. Synchronize the value with the BACnet stack.
    3. Perform a new address advertisement.
    4. Other nodes update their tables via bzll_update_node_protocol_address(...).

    Address Validation

    The coordinator can validate address consistency using the Send Match Protocol Address Command. The node must pass the received address to: bzll_match_protocol_address(...)

    // Used by the node to validate a received address against its local configuration
    void bzll_match_protocol_address(address_t received_addr);
  9. Configure Protocol_Services_Supported property correctly

    master
    The Protocol_Services_Supported property must only have bits set to '1' for services that the device can actually execute. If a service is initiated by the device but not executed by it, the corresponding bit must be set to '0'. This property is used by other devices to advertise which services they can accept and execute.
  10. Understand the Modbus RTU ↔ BACnet Gateway operation flow

    master

    The gateway operates by mapping Modbus RTU registers/coils to BACnet objects (AI, AO, BI, BO).

    Startup Sequence:

    1. Parse CLI arguments (config path, device instance override).
    2. Load gateway_config.json containing BACnet/Modbus settings and the point table.
    3. Initialize the BACnet datalink (MSTP, BIP, BIP6, Ethernet, or BSC) via dlenv_init.
    4. Create BACnet objects based on the point table.
    5. Initialize the Modbus RTU port.
    6. Broadcast the BACnet 'I-Am' message.
    7. Perform the initial Modbus poll.

    Main Loop:

    • BACnet Communication: Calls datalink_receive() to process incoming frames via npdu_handler().
    • Timers: Manages 1-second BACnet timers (dcc_timer, tsm_timer, Device_Timer).
    • Modbus Polling: Every poll_interval_sec, the gateway reads registers/coils for each enabled point. It updates the BACnet Present_Value. If a Modbus read fails, the gateway sets the BACnet object's Out-of-Service property to true.
    [Startup]
      │
      ├─ Parse CLI arguments (config path, device instance override)
      ├─ Load gateway_config.json  →  BACnet & Modbus settings + point table
      ├─ Initialize BACnet datalink  (mstp / bip / bip6 / ethernet / bsc via dlenv_init)
      ├─ Create BACnet objects from point table  (AI / AO / BI / BO)
      ├─ Initialize Modbus RTU port
      ├─ Broadcast I-Am
      ├─ Initial Modbus poll
      │
      └─ [Main loop] ────────────────────────────────────────────────┐
           │                                                         │
           ├─ datalink_receive()                                    │
           │     Receive BACnet frames → npdu_handler()             │
           │                                                         │
           ├─ 1-second BACnet timers                                 │
           │     dcc_timer / tsm_timer / Device_Timer                │
           │                                                         │
           └─ Modbus poll  (every poll_interval_sec seconds)         │
                 Read registers/coils for each enabled point         │
                 → Update BACnet Present_Value                       │
                 → On failure: set Out-of-Service = true ────────────┘
  11. Understand memory section definitions in memap

    master

    When reviewing the memap output table, the following terms define the memory sections:

    • .text: Application code and constants located in Flash.
    • .data: Non-zero initialized variables; allocated in both RAM and Flash (copied from Flash to RAM at runtime).
    • .bss: Uninitialized data allocated in RAM, or variables initialized to zero.
    • Heap: Dynamic allocations in the RAM Heap area (e.g., used by malloc). Size is defined at build time.
    • Stack: Dynamic allocations in the RAM Stack area (e.g., for local data or context switches). Size is defined at build time.
    • Fill: Bytes filled with zeros by the toolchain to ensure proper alignment of data or code.
    • Misc: Helper libraries introduced by the toolchain (like libc) or modules not part of mbed.