第一步:验证PWM控制
# 引出pwm4
echo 4 > /sys/class/pwm/pwmchip0/export
# 设置周期为 1秒,数值以纳秒为单位
echo 1000000000 > /sys/class/pwm/pwmchip0/pwm4/period
# 设置300毫秒的占空比
echo 300000000 > /sys/class/pwm/pwmchip0/pwm4/duty_cycle
# 设置极性,normal为正极,inversed为负极
echo normal > /sys/class/pwm/pwmchip0/pwm4/polarity
# 使能pwm
echo 1 > /sys/class/pwm/pwmchip0/pwm4/enable
# 停止pwm
echo 0 > /sys/class/pwm/pwmchip0/pwm4/enable
# 删除pwm设备
echo 4 > /sys/class/pwm/pwmchip0/unexport
第二步:创建rpcd 插件
创建 /usr/libexec/rpcd/t113_pwm 文件
#!/bin/sh
. /usr/share/libubox/jshn.sh
case "$1" in
list)
echo '{ "set": {"is_positive": 1, "cycle": "1", "value": "0"} }'
;;
call)
if [ "$2" = "set" ]; then
# 优先使用命令行参数
json_input="$3"
# 如果没有命令行参数,尝试读取标准输入
[ -z "$json_input" ] && [ ! -t 0 ] && json_input=$(head -c 4096 2>/dev/null)
[ -z "$json_input" ] && {
echo '{ "error": "No JSON input provided" }'
exit 1
}
json_load "$json_input" 2>/dev/null || {
echo '{ "error": "Invalid JSON" }'
exit 1
}
# 获取参数
json_get_var cycle cycle
json_get_var value value
json_get_var is_positive is_positive
# 默认值
: ${cycle:=1}
: ${value:=0}
: ${is_positive:=1}
# 参数验证
case "$is_positive" in
0|1) ;;
*) echo '{ "error": "is_positive must be 0 or 1" }'; exit 1 ;;
esac
# 验证cycle
echo "$cycle" | awk '{
if ($0 <= 0) exit 1
if ($0 !~ /^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/) exit 1
}' >/dev/null 2>&1 || {
echo '{ "error": "cycle must be a positive number" }'
exit 1
}
# 验证value
echo "$value" | awk '{
if ($0 < 0 || $0 > 100) exit 1
if ($0 !~ /^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/) exit 1
}' >/dev/null 2>&1 || {
echo '{ "error": "value must be 0-100" }'
exit 1
}
# 计算PWM参数
new_period_ns=$(echo "$cycle" | awk '{ printf "%.0f", $1 * 1000000000 }')
new_duty_ns=$(echo "$new_period_ns $value" | awk '{ printf "%.0f", $1 * $2 / 100 }')
# 确保占空比不超过周期
[ "$new_duty_ns" -gt "$new_period_ns" ] && new_duty_ns="$new_period_ns"
# PWM设备处理
PWM_PATH="/sys/class/pwm/pwmchip0/pwm4"
[ ! -e "$PWM_PATH" ] && {
echo 4 > /sys/class/pwm/pwmchip0/export 2>/dev/null
sleep 0.1
}
# 保存当前启用状态
current_enabled=$(cat "$PWM_PATH/enable" 2>/dev/null || echo "0")
# 读取当前实际的周期值
current_period_ns=$(cat "$PWM_PATH/period" 2>/dev/null || echo "0")
# 计算新周期与当前周期的比值
# 如果当前周期为0,视为首次设置,按周期变大处理
if [ "$current_period_ns" -eq 0 ] 2>/dev/null; then
# 首次设置或当前周期为0,直接设置为新值
period_ratio=0 # 特殊值,表示首次设置
else
# 计算比值:新周期 / 当前周期
period_ratio=$(echo "$new_period_ns $current_period_ns" | awk '{printf "%.3f", $1/$2}')
fi
# 调试信息(可选)
# echo "DEBUG: current_period_ns=$current_period_ns, new_period_ns=$new_period_ns, period_ratio=$period_ratio" >&2
# 根据周期比值决定调整顺序
if [ "$period_ratio" = "0" ]; then
# 首次设置或当前周期为0
# 直接设置周期,再设置占空比
echo "$new_period_ns" > "$PWM_PATH/period" 2>/dev/null || {
echo '{ "error": "Failed to set period (initial setup)" }'
exit 1
}
echo "$new_duty_ns" > "$PWM_PATH/duty_cycle" 2>/dev/null || {
echo '{ "error": "Failed to set duty cycle (initial setup)" }'
exit 1
}
else
# 非首次设置,比较周期比值
# 使用awk进行浮点数比较
compare_result=$(echo "$period_ratio 1.0" | awk '{
if ($1 < $2) print "smaller"
else if ($1 > $2) print "larger"
else print "equal"
}')
# 根据比较结果调整顺序
case "$compare_result" in
smaller)
# 周期缩小:新周期 < 当前周期
# 先设置占空比(确保占空比不超过新周期)
# 检查当前占空比是否可能超过新周期
current_duty_ns=$(cat "$PWM_PATH/duty_cycle" 2>/dev/null || echo "0")
if [ "$current_duty_ns" -gt "$new_period_ns" ] 2>/dev/null; then
# 当前占空比大于新周期,需要先设为0
echo 0 > "$PWM_PATH/duty_cycle" 2>/dev/null
fi
# 先设置占空比
echo "$new_duty_ns" > "$PWM_PATH/duty_cycle" 2>/dev/null || {
echo '{ "error": "Failed to set duty cycle (period reduction)" }'
exit 1
}
# 再设置周期
echo "$new_period_ns" > "$PWM_PATH/period" 2>/dev/null || {
echo '{ "error": "Failed to set period (period reduction)" }'
exit 1
}
;;
larger)
# 周期变大:新周期 > 当前周期
# 先设置周期,再设置占空比
# 先设置周期
echo "$new_period_ns" > "$PWM_PATH/period" 2>/dev/null || {
echo '{ "error": "Failed to set period (period increase)" }'
exit 1
}
# 再设置占空比
echo "$new_duty_ns" > "$PWM_PATH/duty_cycle" 2>/dev/null || {
echo '{ "error": "Failed to set duty cycle (period increase)" }'
exit 1
}
;;
equal)
# 周期不变
# 可以直接设置,但为了安全先周期后占空比
echo "$new_period_ns" > "$PWM_PATH/period" 2>/dev/null || {
echo '{ "error": "Failed to set period (no change)" }'
exit 1
}
echo "$new_duty_ns" > "$PWM_PATH/duty_cycle" 2>/dev/null || {
echo '{ "error": "Failed to set duty cycle (no change)" }'
exit 1
}
;;
esac
fi
# 设置极性,一定要在设置完周期和占空比之后再设置
[ "$is_positive" = "1" ] && polarity="normal" || polarity="inversed"
echo "$polarity" > "$PWM_PATH/polarity" 2>/dev/null || {
echo '{ "error": "Failed to set polarity" }'
exit 1
}
# 启用pwm
if [ "$current_enabled" -eq 0 ]; then
echo 1 > "$PWM_PATH/enable" 2>/dev/null || {
echo '{ "error": "Failed to enable PWM" }'
exit 1
}
fi
echo '{ "status": "ok", "period_ns": "'"$new_period_ns"'", "duty_ns": "'"$new_duty_ns"'", "value_percent": "'"$value"'", "period_ratio": "'"$period_ratio"'", "old_period_ns": "'"$current_period_ns"'" }'
else
echo '{ "error": "Method not found" }'
exit 1
fi
;;
*)
echo '{ "error": "Invalid command" }'
exit 1
;;
esac
赋予执行权限
chmod +x /usr/libexec/rpcd/t113_pwm
第三步:重启rpcd服务
/etc/init.d/rpcd restart
第四步:验证ubus服务是否注册成功
ubus list | grep t113
# 应输出: t113_led t113_pwm
ubus call t113_pwm set '{"is_positive": 1, "cycle": 1, "value": 20 }'
# 应返回: { "status": "ok",
# "period_ns": "1000000000",
# "duty_ns": "200000000",
# "value_percent": "20",
# "period_ratio": "0",
# "old_period_ns": "0"
# }
第五步:创建luci页面
- controller: /usr/lib/luci/controller/t113_led.lua
module("luci.controller.greeting", package.seeall)
function index()
-- 使用 'view' 而非 'cbi',就是使用js来渲染
-- entry({"admin", "system", "greeting"}, cbi("greeting"), _("Greeting"), 99)
entry({"admin", "system", "greeting"}, view("eboy_light/greeting"), _("Greeting"), 99)
entry({"admin", "system", "t113_led"}, view("eboy_light/t113_led"), _("T113_LED"), 98)
end
- view: /www/luci-static/resources/view/eboy_light/t113_pwm.js
'use strict';
'require rpc';
'require view';
'require uci';
var callPWMSet = rpc.declare({
object: 't113_pwm',
method: 'set',
params: ['value','cycle','is_positive'],
expect: { '': {} }
});
return view.extend({
render: function() {
const map = new form.Map(
'eboylight',
_('灯控配置'),
_('设置开关灯、调光阶段.')
)
let s = map.section(form.NamedSection, 'pwm','pwm', _('PWM'))
s.addremove = false
s.anonymous = true
let msg = s.option(form.Value, 'value', _('PWM值(%)'))
msg.datatype = 'range(0,100)'
msg.default = '50'
msg.rmempty = false
msg = s.option(form.Value, 'cycle', _('PWM周期(秒)'))
msg.datatype = 'range(0,1000)'
msg.default = '1'
msg.rmempty = false
msg = s.option(form.ListValue, 'is_positive', _('PWM极性'))
msg.value('1', _('正'))
msg.value('0', _('负'))
msg.default = '1'
map.save = function(){
const options = {
value: parseInt(uci.get('eboylight', 'pwm', 'value')),
cycle: parseFloat(uci.get('eboylight', 'pwm', 'cycle')),
is_positive: parseInt(uci.get('eboylight', 'pwm', 'is_positive'))
}
console.log(options)
callPWMSet(options.value, options.cycle, options.is_positive).then(function (res) {
if (res.status === 'ok') {
alert(_('PWM已设置'))
} else {
alert(_('Error: %s').format(res.error || 'Unknown'))
}
})
return form.Map.prototype.save.apply(this, arguments)
}
}
});
- 对应配置文件:/etc/config/eboylight
config pwm 'pwm'
option is_positive '1'
option cycle '1'
option value '60'
第六步:配置权限
创建 /usr/share/rpcd/acl.d/t113_pwm.json
{
"t113_led": {
"description": "T113 PWM control",
"read": {
"ubus": {
"t113_pwm": [ "list" ]
}
},
"write": {
"ubus": {
"t113_pwm": [ "set" ]
}
}
}
}
重启rpcd服务
/etc/init.d/rpcd restart
#or service rpcd restart


787

被折叠的 条评论
为什么被折叠?



