fix: arbitrate display requests atomically

This commit is contained in:
way
2026-09-26 23:01:15 +08:00
parent 6fc428ef18
commit a84f4895ef
3 changed files with 18 additions and 6 deletions
+1 -1
View File
@@ -69,7 +69,7 @@ CHECK STORAGE
### 4. DisplayController、OLED 与 RGB
每个当前故障都是 DisplayController 中的一个 active request,包含稳定 ID、priority、severity、OLED 显示数据、首次发现时间、最后变化时间和元数据。监控只提交或清除 request。DisplayController 始终只选一个 owner,OLED 和 RGB 同步表达该 owner;`NORMAL_HOME` 是 priority 0 的常驻 request,有任何故障 owner 时不会抢回显示权。同优先级新 request 排队而不抢占,owner 恢复后按 priority、first_seen、ID 重新仲裁。历史 power flags 只进入 diagnose 和一次性 Journal 记录。
每个当前故障都是 DisplayController 中的一个 active request,包含稳定 ID、priority、severity、OLED 显示数据、首次发现时间、最后变化时间和元数据。监控只提交或清除 request,同一轮采样作为一个原子批次,全部更新后只仲裁一次。DisplayController 始终只选一个 owner,OLED 和 RGB 同步表达该 owner;`NORMAL_HOME` 是 priority 0 的常驻 request,有任何故障 owner 时不会抢回显示权。同优先级新 request 排队而不抢占,owner 恢复后按 priority、first_seen、ID 重新仲裁。历史 power flags 只进入 diagnose 和一次性 Journal 记录。
### 5. RGB 告警引擎
+2 -2
View File
@@ -1,6 +1,6 @@
162b3c8dee7576d0cd81ac9b4cd5c7f1051f8d1dc7f35fd8b3eeb2a932662d95 README.md
72e5eabe3093fde436d9bbef417660ada81a52164f9697486dcbd73f5322c205 README.md
72c46162c33f9587c6ccb01ad53fbaaf4ecec8cd21014b909e87e8707e253e36 app/oled_font_5x7.bin
f750ec8189c14fb8a4cdadc691752ce757b9ab4e26784197ba09883aaa630b4c app/pigway_pi_control.py
319ee4dbeed007df5ff3ce60f5a4b24b950f797f595848917542862bcbcbbd7d app/pigway_pi_control.py
dfb1d083c9d64a5e0d6ccfa60a4ef5f71e83ea137ebc53b169a69f6b1458883f config/pigway-pi-control.conf
4c2816da08378f2927c746b70ecfa7d5312e1730c08727cd89e8c2801e707054 install.sh
81aea0a89b298b2512fcb9bf6418618ba7a66474d425390cf95a0128c4093474 systemd/pigway-pi-control.service
+15 -3
View File
@@ -488,6 +488,7 @@ class DisplayController:
self.current_priority=0
self.current_rgb_mode="OFF"
self.owner_since=now
self.batch_depth=0
self.stop_event=threading.Event()
self.rgb_thread=threading.Thread(target=self._rgb_worker,name="rgb",daemon=True)
@@ -518,14 +519,23 @@ class DisplayController:
("priority","severity","rgb_mode","title","l2","l3","l4","metadata"))
if not changed: request["last_changed"]=current["last_changed"]
self.requests[request_id]=request
self._arbitrate_locked()
if self.batch_depth==0: self._arbitrate_locked()
def clear(self,request_id):
if request_id=="NORMAL_HOME": return
with self.lock:
if self.requests.pop(request_id,None) is not None:
log("INFO","ALERT_RECOVERED",alert=request_id)
self._arbitrate_locked()
if self.batch_depth==0: self._arbitrate_locked()
def begin_update(self):
with self.lock: self.batch_depth+=1
def end_update(self):
with self.lock:
if self.batch_depth<=0: raise RuntimeError("display update batch imbalance")
self.batch_depth-=1
if self.batch_depth==0: self._arbitrate_locked()
def _arbitrate_locked(self):
current=self.requests.get(self.current_owner_id)
@@ -654,7 +664,9 @@ try:
c,t,m,d=latest
display.update_home(c,t,m,d)
update_active_alerts(c,t,m,d,sample_elapsed)
display.begin_update()
try: update_active_alerts(c,t,m,d,sample_elapsed)
finally: display.end_update()
if now-last_render >= OLED_REFRESH:
display.refresh()
last_render=now