Integrate a Device
更新时间: 2026/06/26
在Gitcode上查看源码

IMPORTANT

To get the most out of this chapter, make sure you've already completed Extend the BMC API.

As out-of-band server management software, the BMC most often deals with adapting to varied hardware. Drawing on years of experience, the openUBMC SDK offers a range of hardware-adaptation capabilities that streamline this work.

This chapter walks through incremental development on top of an existing hardware adaptation, to help you understand the overall flow. For the specifics of adapting different kinds of hardware, see the Hardware Component Adaptation Guide.

Add an IPMI Sensor

A common scenario is exposing a reading from some hardware part to users as a threshold sensor defined by the IPMI protocol. In this chapter, we'll configure an LM75 temperature part along with a matching IPMI threshold sensor, and surface it through an external API.

CSR Configuration

openUBMC uses a software description language to capture the details of a piece of hardware. This language is called the Component Self-Description Record (CSR).

NOTE

For a full introduction to the CSR, see Component Self-Description Record (CSR).

First, clone the CSR repository:

bash
git clone https://gitcode.com/openUBMC/vpd.git

Open the root.sr of the server model (vendor/Huawei/Server/Kunpeng/openUBMC).

Inside you'll find a series of configurations. First, we declare an LM75 part in the hardware topology.

On the actual hardware, there's an LM75 temperature-sensing chip at address 0x90 on the I2c_8 bus.

In the CSR's ManagementTopology, find the I2c_8 configuration; if there's no I2c_8, paste the configuration below into ManagementTopology (you can model it on I2c_2).

json
"ManagementTopology": {
    ...
    "I2c_8": {
        "Chip": [
            "Lm75_DemoSensor"
        ]
    }
    ...
}

That completes the hardware topology configuration in the CSR.

Next, alongside ManagementTopology, under Objects, define the details of the LM75 part along with its business objects:

json
"Objects": {
    ...
    "Lm75_DemoSensor": {
        "OffsetWidth": 1,
        "AddrWidth": 1,
        "Address": 144
    },
    "Scanner_GetTemperature": {
        "Chip": "#/Lm75_DemoSensor",
        "Size": 1,
        "Offset": 0,
        "Mask": 255,
        "Period": 1000
    },
    "ThresholdSensor_DemoSensor": {
        "AssertMask": 29312,
        "DeassertMask": 29312,
        "ReadingMask": 6168,
        "Linearization": 0,
        "M": 100,
        "RBExp": 224,
        "UpperCritical": 48,
        "UpperNoncritical": 46,
        "PositiveHysteresis": 2,
        "NegativeHysteresis": 2,
        "OwnerId": 32,
        "OwnerLun": 0,
        "EntityId": "<=/Entity_DemoSensor.Id",
        "EntityInstance": "<=/Entity_DemoSensor.Instance",
        "Initialization": 127,
        "Capabilities": 104,
        "SensorType": 1,
        "ReadingType": 1,
        "SensorName": "Demo Temperature Sensor",
        "Unit": 128,
        "BaseUnit": 1,
        "ModifierUnit": 0,
        "Analog": 1,
        "MaximumReading": 127,
        "MinimumReading": 128,
        "Reading": "<=/Scanner_GetTemperature.Value"
    },
    "Entity_DemoSensor":{
        "Id": 99,
        "Name": "Demo Temperature Sensor",
        "PowerState": 1,
        "Presence": 1,
        "Instance": 96
    },
    ...
}

Here we define several objects: the LM75 part, a periodic scan task (Scanner), and the software object for the IPMI threshold sensor. We link the Scanner to the LM75 part using reference syntax, and synchronize the Scanner's reading into the ThresholdSensor's reading using sync syntax.

NOTE

For IPMI sensor configuration details, see IPMI Sensor & SEL.

Build the App

Since we changed the vpd repository, we need to rebuild it.

To distinguish it from the previous version, bump the version field in service.json.

bash
bingo build --stage=stable

Build the Full Image

Find where vpd is declared, update its version to the one you just built, then build the full image again from the manifest.

bash
bingo build

Test the Full Build

After upgrading with the full image, we can query the sensor with ipmitool:

bash
> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 sdr
> Demo Temperature   | 28 degrees C      | ok

Add a Hardware Resource Object

The object definitions in the CSR come from the MDS model. By instantiating an MDS class definition, you can lay out all the hardware-management data you need in the relevant device configuration, then write the business logic around those resource objects in your app.

Define the MDS Object

First, we define a resource class in the my_app app's MDS model.

Open mds/model.json in the my_app app you created in Create an App, and add the model definition below:

NOTE

MDS (Model Description Source) describes the resource model.
For the detailed design, see MDS.

json
{
    "MyCSRModel": {
        "path": "/bmc/demo/MyCSRModel/${id}",
        "interfaces": {
            "bmc.demo.OpenUBMC.Reading": {
                "properties":{
                    "TemperatureCelsius": {
                        "usage": [
                            "CSR"
                        ]
                    }
                }
            }
        }
    }
}

Unlike an ordinary app MDS object definition, here we add a "usage": ["CSR"] declaration. It says that within some CSR there's an object called MyCSRModel carrying a TemperatureCelsius property.

Add the CSR Object

NOTE

For the design of hardware self-discovery, see Hardware Self-Discovery.

As the usage declaration above shows, TemperatureCelsius comes from the CSR, so we need to define a MyCSRModel in that CSR; hardware self-discovery then dispatches the CSR object to my_app.

json
"Objects": {
    ...
    "MyCSRModel_DemoSensor": {
        "TemperatureCelsius": "<=/Scanner_GetTemperature.Value"
    },
    ...
}

Generate Code

Since we added a model definition, we regenerate the helper code. Run the following in my_app:

bash
bingo gen

Write the Code

Because the MyCSRModel instance is already "created" in root.sr, we wait for the object to be dispatched rather than creating it ourselves. Here's how to receive that dispatch in code.

Open my_app_app.lua and add object-added callbacks in app:init().

lua
local object_manage = require 'mc.mdb.object_manage'
lua
function app:init() -- The app's initialization function
    app.super.init(self) -- Call the base class initializer first
    self.my_mds_model = self:CreateMyMDSModel(1, function(object) -- Create an MDS object instance
        object.ObjectName = "MyMDSModel_1"  -- Assign the object's properties inside the callback
        object.WelcomeMessage = "Hello OpenUBMC!"
        object.SecretNumber = 330
    end)
    self:register_ipmi()
    self:register_mds_callback() -- Newly added MDS callbacks
end

function app:register_mds_callback()
    object_manage.on_add_object(self.bus, function(class_name, object, position)
        if class_name == 'MyCSRModel' then
            self.my_csr_model = object
        end
    end)
    object_manage.on_add_object_complete(self.bus, function(position)
    end)
    object_manage.on_delete_object(self.bus, function(class_name, object, position)
        if self.my_csr_model == object then
            self.my_csr_model = nil
        end
    end)
    object_manage.on_delete_object_complete(self.bus, function(position)
    end)
end

Build the App

Since we changed the my_app repository, we need to build it.

To distinguish it from the previous version, manually bump the version field in mds/service.json—usually by incrementing the last digit—then run the app build.

bash
bingo build --stage=rc

Build the Full Image

In the manifest, find where my_app was declared earlier (in Create an App it was placed in manifest/build/product/openUBMC/openUBMC/manifest.yml), update its version to the one you just built, then build the full image.

bash
bingo build

Test the Full Build

After upgrading with the full image, we can inspect the MDB interface (resource collaboration interface) object:

bash
source /etc/profile
busctl --user tree bmc.kepler.my_app
bash
└─/bmc
  |─/bmc/demo
  |  |─/bmc/demo/MyCSRModel
  |  | └─/bmc/demo/MyCSRModel/MyCSRModel_DemoSensor_01
  |  └─/bmc/kepler/MyMDSModel
  |    └─/bmc/kepler/MyMDSModel/1
  └─/bmc/kepler
  | └─/bmc/kepler/IpmiCmds
  |   └─/bmc/kepler/IpmiCmds/30
  |     └─/bmc/kepler/IpmiCmds/30/90
  |       |─/bmc/kepler/IpmiCmds/30/90/GetSecretNumber
  |       └─/bmc/kepler/IpmiCmds/30/90/SetSecretNumber
  └─/bmc/kepler/my_app
    └─/bmc/kepler/my_app/MicroComponent

The busctl --user tree output now shows an extra object—the one configured in the CSR. We can inspect it with busctl --user introspect:

bash
busctl --user introspect bmc.kepler.my_app /bmc/demo/MyCSRModel/MyCSRModel_DemoSensor_01
log
NAME                                    TYPE      SIGNATURE   RESULT/VALUE               FLAGS
bmc.kepler.OpenUBMC.Reading             interface -           -                          -
.TemperatureCelsius                     property  n           28                         emits-change writable
bmc.kepler.Object.Properties            interface -           -                          -
.GetAllWithContext                      method    a{ss}s      a{sv}                      -
.GetOptions                             method    a{ss}ss     a{ss}                      -
.GetPropertiesByNames                   method    a{ss}sas    a{sv}a{sv}                 -
.GetPropertiesByOptions                 method    a{ss}sa{ss} as                         -
.GetWithContext                         method    a{ss}ss     v                          -
.SetWithContext                         method    a{ss}ssv    -                          -
.ClassName                              property  s           "MyCSRModel"               emits-change
.ObjectIdentifier                       property  (ysss)      0 "1" "" "01"              emits-change
.ObjectName                             property  s           "MyCSRModel_DemoSensor_01" emits-change
org.freedesktop.DBus.Introspectable     interface -           -                          -
.Introspect                             method    -           s                          -
org.freedesktop.DBus.ObjectManager      interface -           -                          -
.GetManagedObjects                      method    -           a{oa{sa{sv}}}              -
org.freedesktop.DBus.Peer               interface -           -                          -
.GetMachineId                           method    -           s                          -
.Ping                                   method    -           -                          -
org.freedesktop.DBus.Properties         interface -           -                          -
.Get                                    method    ss          v                          -
.GetAll                                 method    s           a{sv}                      -
.Set                                    method    ssv         -                          -
.PropertiesChanged                      signal    sa{sv}as    -                          -