-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local c_object = require 'mc.orm.object'
local c_pump_object = require 'pump_object'
local ctx = require 'mc.context'
local log = require 'mc.logging'

local pumps_manager = c_object('Pumps')

local MIN_PWM = 25
local MAX_PWM = 100

local function is_valid_pwm(pwm)
    return pwm >= MIN_PWM and pwm <= MAX_PWM
end

local function cal_hardware_pwm(pwm_percent, max_supported_pwm)
    return math.floor(pwm_percent / 100 * max_supported_pwm + 0.5)
end

local function get_pump_pwm(pump_obj, pwm_percent)
    -- 泵不满足下发调速，则不能改变当前的占空比，直接返回当前转速
    if not pump_obj:is_present() or not is_valid_pwm(pwm_percent) then
        return pump_obj:get_actual_pwm()
    end
    -- 不在位泵照常下发转速，不影响泵组其它泵调速
    return cal_hardware_pwm(pwm_percent, pump_obj.MaxSupportedPWM)
end

function pumps_manager:set_pwm(l_pwm)
    for index, pump_obj in ipairs(self.pump_collection) do
        self.t_pwm[index] = get_pump_pwm(pump_obj, l_pwm[index])
        pump_obj:set_expected_pwm(self.t_pwm[index])
    end
    return self:send_pumps_pwm(string.pack(string.rep('B', #self.t_pwm), table.unpack(self.t_pwm)))
end

function pumps_manager:send_pumps_pwm(data)
    local ok, resp = pcall(function()
        return self.PWMChip:Write(ctx.new(), self.SetPWMCmd, data)
    end)

    if not ok then
        log:info('Set pumps failed, resp: %s', resp)
        return 1
    end
    return 0
end

function pumps_manager:ctor()
    self.pump_collection = {}
    self.t_pwm = {}
    self.l_pwm = {}
end

function pumps_manager:init()
    self:connect_signal(self.on_add_object_complete, function()
        self:next_tick(function()
            -- 同一个板子的泵 position是相同的，从小到大存放pump_collection中
            self.pump_collection = c_pump_object.collection:fetch_by_position(self:get_position())
            table.sort(
                self.pump_collection,
                function (pump_1, pump_2)
                    return pump_1.Id < pump_2.Id
                end
            )
        end)
    end)
    pumps_manager.super.init(self)
end

return pumps_manager
