
<h1>frudata</h1>
<hr>

[toc]
<hr>

## 1 功能简介
支持标准和非标准的电子标签管理，标准电子标签直接由frudata组件将存储在eeprom和file里面的数据按域和字段解析出来，非标准电子标签由多样化硬件APP负责数据读写和解析，将数据发送给frudata，并且由frudata组件统一对外提供电子标签的读写接口。
## 2 关键特性
### 2.1 frudata资源树类设计
```mermaid
classDiagram
Fru <-- FruData
FruData <.. Component
Fru <-- Component
Fru <.. Frus
Component <..Components
class Frus{
  FruAdded()void
  FruRemoved()void
}
class Fru{
  FruId:int
  FruName:string
  FruDataId:object
}
class FruData{
  FruId:int
  FruName:string
  ProductSerialNumber:string
  FruDev:object
  EepromWp:char
  SetProductAssertTag()void
  Update()void
}
class Component{
  FruId:int
  Type:int
  Name:string
  SerialNumber:string
  UpdateHealth()void
}
class Components{
  GetComponentTypes()object
}
```
Fru类描述的是现场可替换单元（fru）的相关信息，例如主板, Raid卡, Riser卡, 硬盘背板等，一个fru只有一个Fru对象；
Frudata类描述的是Fru里面的eeprom存储的信息，一个fru最多有一个Frudata对象；
Frus主要在fru对象分发过来后，给sensor发送fruid信号来管理sdr数据；
Component类表示部件管理信息，如内存、硬盘、风扇等，一个fru里可以有多个部件，配置告警也会配一个Component对象，供event管理；
Components供WEB页面查询系统事件，根据部件类型进行筛选，需要从资源树获取当前存在的所有对象的部件类型。

### 2.2 frudata业务流程

电子标签通过CSR配置，通过硬件自发现解析成对象分发到frudata进行处理

frudata根据CSR配置解析eeprom数据并更新资源树

通过ipmi命令写电子标签时则向eeprom中写入


```mermaid
sequenceDiagram
用户->>+硬件自发现:系统上电
硬件自发现->>+硬件自发现:csr对象解析
硬件自发现->>+d-bus:对象上树
硬件自发现->>+frudata:对象分发
frudata->>+frudata:fruid分配
frudata->>+hwproxy:读取eeprom头
hwproxy-->>-frudata:返回头部数据
frudata->>+frudata:获取fru域和system域偏移
frudata->>+hwproxy:读取对应偏移的eeprom数据
hwproxy-->>-frudata:返回电子标签数据
frudata->>+frudata:c代码解析eeprom数据
frudata->>-d-bus:更新资源树对象属性
用户->>+frudata:ipmi写电子标签
frudata->>+frudata:校验数据合法性
frudata->>+frudata:写入c结构体
frudata->>+hwproxy:关闭写保护寄存器
hwproxy-->>-frudata:关闭成功
frudata->>+hwproxy:写入eeprom
hwproxy-->>-frudata:返回写入结果
frudata->>+hwproxy:开启写保护寄存器
hwproxy-->>-frudata:开启成功
frudata->>-d-bus:更新资源树对象属性
frudata-->>-用户:返回写入结果
```

### 2.3 frudata业务代码分层设计
#### 2.3.1 四层模型

APP层：只负责自发现对象注册和RPC、IPMI接口注册，业务进行下沉，单一职责；
对象服务层：承载对象的统一创建、代理，分离变化；
对象层：实现对象的差异化接口，高内聚，开闭原则；
数据层：使用统一的数据结构，存储不同格式的电子标签，向稳定方向依赖。 

```plantuml

@startuml
frame "Frudata使用四层模型：高内聚低耦合"{
rectangle lua层{
card a as "自发现对象、RPC接口注册"
note right of a
app层
end note
card b as "对Frudata对象的统一创建、代理"
note right of b
对象服务/代理层
end note
a --[hidden] b
rectangle c as "Frudata对象类"{
card Init初始化
card Read接口
Init初始化 ..[hidden] Read接口
card Write接口
card Update资源树
Write接口 ..[hidden] Update资源树
}
note right of c
对象层
end note
b --[hidden] c
}
rectangle c层{
card d as "统一数据结构存储格式"
}
note right of d
数据层
end note
Update资源树 --[hidden]d
}
@enduml

```


#### 2.3.3 使用代理模式来屏蔽app层的调用接口差异
```plantuml

@startuml
interface ipmi<<interface>>
interface rpc<<interface>>
interface add_object<<interface>>
interface Interface1<<interface>> {
init():void
read():string
write():void
update():void
}
ipmi-->Interface1
rpc-->Interface1
add_object-->Interface1
class Frudata_proxy {
Fruid:int
StorageType:string
init():void
read():string
write():boolen
update():void
}
class Frudata_tianchi {
Fruid:int
StorageType:string
init():void
read():string
write():boolen
update():void
}
class Frudata_eepromV2 {
Fruid:int
StorageType:string
init():void
read():string
write():boolen
update():void
}
class Frudata_file {
Fruid:int
StorageType:string
init():void
read():string
write():boolen
update():void
}
class Frudata_mcu {
Fruid:int
StorageType:string
init():void
read():string
write():boolen
update():void
}
Frudata_proxy <|--Frudata_tianchi
Frudata_proxy <|--Frudata_eepromV2
Frudata_proxy <|--Frudata_file
Frudata_proxy <|--Frudata_mcu
Enum Data_Struct<<Data Type>> {
internal:object
chassis:object
broad:object
product:object
extend:object
system:object
}
Frudata_proxy..>Interface1:<<Realization>>
Data_Struct <|..Frudata_tianchi
Data_Struct <|..Frudata_eepromV2
Data_Struct <|..Frudata_file
Data_Struct <|..Frudata_mcu
ipmi .[hidden] rpc
Interface1--[hidden] Frudata_proxy
Frudata_proxy --[hidden] Frudata_eepromV2
Frudata_tianchi .[hidden] Frudata_eepromV2
Frudata_eepromV2 .[hidden] Frudata_file
Frudata_file .[hidden] Frudata_mcu
Frudata_tianchi .[hidden] Frudata_eepromV2
Frudata_mcu --[hidden] Data_Struct
@enduml

```



### 2.4 Area和field字段定义

| Area | field |
| -- | -- |
| FRU_AREA_CHASSISINFO = 1 |FRU_CHASSIS_TYPE = 0<br>FRU_CHASSIS_PART_NUMBER = 1<br>FRU_CHASSIS_SERIAL_NUMBER = 2<br>FRU_CHASSIS_EXTRA = 3 |
| FRU_AREA_BOARDINFO = 2 | FRU_BOARD_MFGDATE = 0<br>FRU_BOARD_MANUFACTURER = 1<br>FRU_BOARD_PRODUCTNAME = 2<br>FRU_BOARD_SERIALNUMBER = 3<br>FRU_BOARD_PARTNUMBER = 4<br>FRU_BOARD_FRUFILEID = 5<br>FRU_BOARD_EXTRA = 6|
| FRU_AREA_PRODUCT = 3 | FRU_PRODUCT_MANUFACTURER = 0<br>FRU_PRODUCT_NAME = 1<br>FRU_PRODUCT_PARTNUMBER = 2<br>FRU_PRODUCT_VERSION = 3<br>FRU_PRODUCT_SERIALNUMBER = 4<br>FRU_PRODUCT_ASSETTAG = 5<br>FRU_PRODUCT_FRUFILEID = 6<br>FRU_PRODUCT_EXTRA = 7|
| FRU_AREA_SYS = 6 |FRU_SYSTEM_MANUFACTURE = 0<br>FRU_SYSTEM_PRODUCTNAME = 1<br>FRU_SYSTEM_VERSION = 2<br>FRU_SYSTEM_SERIALNUMBER = 3 |

## 3 对外接口 

### 3.1 资源树接口

- **bmc.kepler.FrudataService.Frudata**

**Update** 用于非标电子标签更新资源树属性

| 参数 | 签名 | 描述 |
| -- | -- | -- |
| prop1 | as | 属性名称列表 |
| prop2 | as| 属性值列表 |


**SetProductAssetTag** 设置产品资产标签

| 参数 | 签名 | 描述 |
| -- | -- | -- |
| prop1 | y | FruId |
| prop2 | s| 资产标签 |

**SetSysProductName** 设置系统产品名称

| 参数 | 签名 | 描述 |
| -- | -- | -- |
| prop1 | y | FruId |
| prop2 | s| 产品名 |

- **bmc.kepler.FrudataService.IpmiFrudata**

**Write** 写电子标签

| 参数 | 签名 | 描述 |
| -- | -- | -- |
| prop1 | y | FruId |
| prop2 | s| 属性名 |
| prop3 | s| 属性值 |

**Read** 读电子标签

| 参数 | 签名 | 描述 |
| -- | -- | -- |
| prop1 | y | FruId |
| prop2 | s| 属性名 |

- **bmc.kepler.Systems.Components**

**GetComponentTypes** 获取当前所有的部件类型

### 3.2 IPMI接口

- 具体参数参考本组件配置文件ipmi.json

| 方法  | 描述  |
|--|--|
| ClearElabelData | 清除电子标签 |
| WriteElabelData | 设置电子标签 |
| ReadElabelData | 查询电子标签 |
| UpdateElabelData | 更新电子标签  |
| GetPicmgProperties | 获取PICMG属性 |
| GetAddressInfo | 获取地址信息 |
| ComputePowerProperties | 计算功率属性 |
| GetFruidInfo | 获取FRU信息 |
| IpmiWriteFrudata | 写入FRU数据 |
| GetComponentInfo | 获取组件信息 |
| IpmiDftCustom | 设置定制化配置(Customize Flag) |
| IpmiGetDftCustom | 查询DFT全局参数(Customize Flag) |
| FruControlCapabilities | FRU控制能力 |
| GetFruInventory | 获取FRU库存区域信息 |
| GetFruidFromUid | 通过UID获取组件的Fruid |
| ReadFruData | 读取FRU数据 |
| GetComponentPositionInfo | 获取部件位置信息 |
| GetDevicePresence | 获取设备信息(在位状态) |
| GetDeviceHealth | 获取设备信息(健康状态) |
| GetDeviceBoardID | 获取设备信息(BoardID) |
| GetDeviceLocation | 获取设备信息(物理位置) |
| GetDeviceFunction | 获取设备信息(功能组或逻辑分组) |
| GetDeviceName | 获取设备信息(名称) |
| GetDeviceGroupID | 获取设备信息(设备所属组ID) |
| GetDeviceFruid | 获取设备信息(Device ID) |
| GetDeviceUniqueId | 获取设备信息(组件唯一标识) |
| GetGeneralDeviceManufacture | 获取设备信息(设备厂商名称) |

## 4 配置介绍
```
"Eeprom_EXU": {
  "OffsetWidth": 2,
  "AddrWidth": 1,
  "Address": 174,
  "WriteTmout": 100,
  "ReadTmout": 100,
  "RwBlockSize": 32,
  "WriteInterval": 20,
  "HealthStatus": 0
},
"Accessor_EXUWP": {
  "Chip": "#/Smc_ExpBoardSMC",
  "Size": 1,
  "Offset": 11776,
  "Mask": 255,
  "Type": 0,
  "Value": 0
},
"FruData_Expander": {
  "FruId": 1,
  "FruDev": "#/Eeprom_EXU",  -- 关联eeprom
  "EepromWp": "#/Accessor_EXUWP.Value",  -- 关联写保护寄存器
  "StorageType": "TianChi"  -- 存储介质类型
},
"Fru_Expander": {
  "PcbId": 1,  -- 需要关联到硬件, 从硬件读取Id
  "PcbVersion": ".A",  -- PCB版本
  "FruId": 1,
  "FruName": "ExpBoard{Slot}", 
  "PowerState": 1, 
  "Health": 0, 
  "EepStatus": "<=/Eeprom_EXU.HealthStatus", 
  "Type": 50, 
  "FruDataId": "#/FruData_Expander",  -- EEPROM状态, 当此属性关联到Accessor时进行EEPROM的监控
  "ConnectorGroupId": "{GroupId}",  -- 关联Anchor的GroupId
  "BoardId": 65535,  -- 非天池：组件单板BoardID
  "UniqueId": "00000001010302023922"  -- 天池：组件唯一标识,Vendor + ComponentID
}
```
**注意事项：**

1. fruid配置为1-63会自动分配fruid，默认可以配为1 
2. fruid为0保留给挂耳，配置64-255不会进行fruid分配
3. Fru里面的FruDataId需要关联到对应的Frudata对象
4. 天池规范的电子标签配置为TianChi，非天池的规范的标准电子标签配置为EepromV2
5. 非标电子标签StorageType可以配为MCU等，不做限制