# power_mgmt
## 功能简介
电源管理组件，负责电源基础信息的获取如电压、电流、温度、功率等，提供电源工作模式、睡眠模式的设置与电源固件升级的功能，同时提供异常事件、告警、黑匣子日志等多种方式用于监测电源状态与故障定位

## 关键特性

### 电源信息获取
电源模块通过关联的fru读写地址与协议读写地址，获取电源的基本信息, 不同厂商会定制一些oem命令。用户通过对应接口，如redfish、IPMI命令可查询到相关信息。
#### 电源协议
##### 协议类型-PMBus
PMBus（Power Management Bus是一种开放标准的数字电源管理通信协议。PMBus使用串行通信协议，基于标准的I2C总线，可以通过单个总线连接多个从设备，允许电源管理器与系统中的其他设备（如处理器、存储器和外围设备）进行通信，以实现电源管理和监控功能。

##### 协议类型-CANbus
CAN（Controller Area Network）总线协议是一种用于实时应用的串行通信协议，广泛应用于汽车、工业控制、航空航天等领域。它是一种高可靠性、高带宽、低成本的通信协议，被设计用于在不需要主机（Host）的情况下，允许网络上的单片机和仪器相互通信。

### 黑匣子
提供电源黑匣子，电源黑匣子主要是记录电源寄存器信息的设备，它可以帮助电源部收集到的黑匣子信息进行解析，电源发生异常事件时的状态，定位电源问题。一键采集功能收集日志时会采集黑匣子里的数据并存储到`/dump_info/LogDump/ps_black_box.log` 

### 固件升级
提供电源固件升级的能力，通过电源固件升级包可完成电源固件升级。电源升级时，会停止基本信息监控，同时设置电源模式为主用，保证升级时服务器不断电，升级完成后会重新启动基本信息监控

### 电源模式
支持电源模式的查询与设置，电源模式可设置为主用（Enabled）或备用（StandbySpare）。其中负载均衡模式下所有电源工作在主用模式下，主备供电仅设置的主用电源工作在主用模式，其余电源工作在备用模式

### 电源告警

Aclost告警，监控gpio的中断信号，ac之后检测上次掉电原因，如果发生中断，则继续往下设置事件产生标志位记录事件

## 对外接口

### 资源树接口
- OnePower
    - Path: `/bmc/kepler/Systems/:SystemId/PowerMgmt/:ID` 
    - Interface: `bmc.kepler.Systems.PowerMgmt.OnePower`
        | 方法  | 描述  |
        | :------------: | :------------: |
        | SetPowerWorkMode | 设置电源工作模式，1：设置为备用，0：设置为主用 |
    - Interface: `bmc.kepler.Systems.PowerMgmt.OnePower.Status` 
        | 方法  | 描述  |
        | :------------: | :------------: |
        | SetSleepMode | 设置电源休眠模式，Normal或DeepSleep |


### IPMI命令
- 具体参数参考本组件配置文件`ipmi.json`

| 方法  | 描述  |
| :------------: | :------------: |
| GetPowerSupplyInfo | 获取电源信息，如厂商信息、电源型号、固件版本、电源协议、序列号等 |
| SetPowerStatus |设置电源状态 |
| GetThresholdSensorReadingVoltageInput | 获取电源输入电压传感器值 |
| GetThresholdSensorReadingVoltageOutput | 获取电源输出电压传感器值 |
| GetThresholdSensorReadingCurrentInput | 获取电源输入电流传感器值 |
| GetThresholdSensorReadingCurrentOutput | 获取电源输出电流传感器值 |
| SetPsuFruConfig | 设置电源Fru配置，0：显示硬件版本，1：显示软件版本（固件版本） |
| GetPsuFruConfig | 获取电源Fru配置，0：显示硬件版本，1：显示软件版本（固件版本） |

## 配置介绍

### 关键类定义

#### 电源槽位对象PsuSlot
- PsuSlot
    - SlotNumber：电源槽位号，必须全局唯一，OnePower对象通过槽位关联
    - Presence：电源在位
    - SlotI2cAddr：电源I2C地址, PsuChip的address是私有对象，需要从这里获取
    - PsuChip：电源关联的Chip对象，通过Chip类访问电源
    - FruI2cAddr：电源FRU信息I2C地址
    - FruChip：电源FRU关联的Chip对象，FruSource为1时，会去EEPROM获取fru数据
    - FruSource：为1时，会去EEPROM获取fru数据；否则从Psu获取

#### 单电源监测对象OnePower
- OnePower
    - SlotNumber：电源槽位
    - Presence：电源在位，默认配死为1
    - PhysicalInterface：电源加载协议
    - DeviceLocator：电源丝印
    - Position：电源位置
    - OutputState：CPLD获取到的Output状态
    - RefFrudata：关联的Fru对象，用于填充Fru信息

### 设备树管理
#### 设备树Adapter
##### OnePower
设备树加载通用模型，与通用逻辑不一致的需要自行在对应的csr目录下补充adapter
通用OnePower在init阶段关联上一级position的同槽位PsuSlot对象，并刷新Fru信息

##### PsuSlot
PsuSlot所在不同的单板，需要独立配置一份adapter。框架在获取到PsuSlot对象后，会根据所属的csr，拉起不同的adapter

PsuSlot主要有两个逻辑（适配新adapter需要实现这两个函数）：

1. fetch_power_supply_info

注册对应的协议(如pmbus,canbus)，并刷新Fru数据

2. power_monitor_start

拉起属性轮询任务
##### Monitor
不同协议的电源在属性查询、轮询周期等实现上有所不同，所以需要对fetch_power_supply_info和power_monitor_start的实现函数提取，不同的任务调度提取出来作为monitor

##### Protocol
电源协议，根据不同的电源类型实现，对外屏蔽命令字和逻辑功能实现，接口功能和名称保持一致

#### 注册协议Protocol适配与加载

init.lua（`include/device_tree/adapters/power_mgmt/protocol/init.lua` ）根据上层传入的physical_interface（即OnePower对象上配置的PhysicalInterface属性）加载不同的协议文件，封装monitor(可不配置)

- 支持如下两种写法
1. `physical_interface = {OnePower对外显示Protocol字段， require xxx文件, monitor的文件路径}`
2. `厂商 = {
 [型号] = {OnePower对外显示Protocol字段， require xxx文件, monitor的文件路径}
} 该写法需要先加载默认协议，由adapter读完厂商型号后，再根据厂商、型号重新加载协议文件`

##### 配置案例
以CRPS为例，CSR上OnePower对象PhysicalInterface属性配置pmbus，PsuSlot会根据
PhysicalInterface加载pmbus协议 读取厂商型号
1. init.lua里需要在protocol表配置
`['Great Wall'] = {
 ['GW-CRPS800N2'] = {'CRPS'(OnePower对象对外展示的字段)， require xxx.crps   (crps文件需要自行实现，可继承pmbus,复写差异化命令字实现函数)}
}`
2. xxx/crps.lua(文件命名可自定义)里实现crps协议
3. crps与pmbus协议在命令字实现上无较大差异，可以考虑继承pmbus，重写部分函数