chore: HERV 통합 저장소 초기 커밋
- 펌웨어(program), C# 대시보드(TestProgram), 시뮬레이터(Simulator), 프로토콜/문서(Protocol, doc) 전체를 단일 저장소로 통합 - program 폴더의 별도 git 저장소를 제거하고 통합 저장소에 흡수 - 빌드 산출물(program/build, bin/obj, *.o/.elf/.bin/.hex 등) .gitignore 처리 - 사내 Synology NAS Git 원격 연결 예정 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
namespace ErvProtocol
|
||||
{
|
||||
// StatusRecord → STATUS(0x81) 134B payload. StatusDecoder 의 역(逆).
|
||||
// ERV(메인보드/시뮬레이터) 측이 STATUS 를 송신할 때 사용. PC_ERV_Protocol.md 4장.
|
||||
public static class StatusEncoder
|
||||
{
|
||||
static void W16(byte[] p, int off, int v) // 빅엔디안
|
||||
{
|
||||
p[off] = (byte)((v >> 8) & 0xFF);
|
||||
p[off + 1] = (byte)(v & 0xFF);
|
||||
}
|
||||
|
||||
// StatusRecord → 134B payload
|
||||
public static byte[] Encode(StatusRecord s)
|
||||
{
|
||||
var p = new byte[StatusDecoder.STATUS_LEN];
|
||||
|
||||
// 글로벌 0~16
|
||||
p[0] = s.Power;
|
||||
p[1] = s.RunMode;
|
||||
p[2] = s.AutoState;
|
||||
p[3] = s.FanMode;
|
||||
p[4] = s.SubMode;
|
||||
p[5] = s.Hood;
|
||||
p[6] = s.HystPreset;
|
||||
W16(p, 7, s.HystPm25);
|
||||
W16(p, 9, s.HystPm10);
|
||||
W16(p, 11, s.HystVoc);
|
||||
W16(p, 13, s.HystCo2);
|
||||
W16(p, 15, s.ErrorCode);
|
||||
|
||||
// 각실 17~ (14B x 4)
|
||||
const int baseOff = 17;
|
||||
for (int r = 0; r < 4; r++)
|
||||
{
|
||||
int o = baseOff + r * 14;
|
||||
var room = s.Rooms[r];
|
||||
p[o + 0] = room.Damper;
|
||||
W16(p, o + 1, room.Pm25);
|
||||
W16(p, o + 3, room.Pm10);
|
||||
W16(p, o + 5, room.Voc);
|
||||
W16(p, o + 7, room.Co2);
|
||||
p[o + 9] = room.AirQuality;
|
||||
p[o + 10] = room.LedDim;
|
||||
W16(p, o + 11, room.LoadScore);
|
||||
p[o + 13] = room.FinalVolume;
|
||||
}
|
||||
|
||||
// ERV 리셋 (offset 73)
|
||||
p[73] = s.Reset;
|
||||
|
||||
// 풍량 VSP (offset 74~, 9엔트리 × u16 SA·EA)
|
||||
const int vspOff = 74;
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
int o = vspOff + i * 4;
|
||||
W16(p, o, s.Vsp[i].Sa);
|
||||
W16(p, o + 2, s.Vsp[i].Ea);
|
||||
}
|
||||
|
||||
// 히스테리시스 프리셋 테이블 (offset 110~, 3프리셋 × PM2.5/PM10/VOC/CO2 u16)
|
||||
const int hystOff = 110;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int o = hystOff + i * 8;
|
||||
W16(p, o, s.HystTable[i].Pm25);
|
||||
W16(p, o + 2, s.HystTable[i].Pm10);
|
||||
W16(p, o + 4, s.HystTable[i].Voc);
|
||||
W16(p, o + 6, s.HystTable[i].Co2);
|
||||
}
|
||||
|
||||
// 모드별 오염단계 임계표 (offset 134~, 3프리셋 × [CO2,PM2.5,PM10,VOC] × L1~L4)
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int o = StatusDecoder.THR_OFF + i * 32;
|
||||
for (int k = 0; k < 4; k++) W16(p, o + 0 + k * 2, s.ThrTable[i].Co2[k]);
|
||||
for (int k = 0; k < 4; k++) W16(p, o + 8 + k * 2, s.ThrTable[i].Pm25[k]);
|
||||
for (int k = 0; k < 4; k++) W16(p, o + 16 + k * 2, s.ThrTable[i].Pm10[k]);
|
||||
for (int k = 0; k < 4; k++) W16(p, o + 24 + k * 2, s.ThrTable[i].Voc[k]);
|
||||
}
|
||||
|
||||
// 각실 온도/습도 (offset 230~, 4실 × [Temp, Humi])
|
||||
for (int r = 0; r < 4; r++)
|
||||
{
|
||||
int o = StatusDecoder.TEMPHUMI_OFF + r * 2;
|
||||
p[o + 0] = s.Rooms[r].Temp;
|
||||
p[o + 1] = s.Rooms[r].Humi;
|
||||
}
|
||||
|
||||
// (꺼짐)예약 잔여초 (offset 238, u16)
|
||||
W16(p, StatusDecoder.RESERVE_OFF, s.ReserveRemainSec);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// STATUS(0x81) 완성 프레임 (CRC 포함)
|
||||
public static byte[] BuildStatusFrame(StatusRecord s) => CtrlFrame.Build(StatusDecoder.STATUS, Encode(s));
|
||||
|
||||
// ACK(0x82) 프레임 : [echoCmd][result(0 OK/1 ERR)]
|
||||
public static byte[] BuildAckFrame(byte echoCmd, byte result) => CtrlFrame.Build(StatusDecoder.ACK, echoCmd, result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user