1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum CecKeyCode {
18 Select = 0,
19 Up = 1,
20 Down = 2,
21 Left = 3,
22 Right = 4,
23 Rightup = 5,
24 Rightdown = 6,
25 Leftup = 7,
26 Leftdown = 8,
27 Rootmenu = 9,
28 Setupmenu = 10,
29 Contentsmenu = 11,
30 Favoritemenu = 12,
31 Exit = 13,
32 Mediatopmenu = 16,
33 Mediacontextsensitivemenu = 17,
34 Numberentrymode = 29,
35 Number11 = 30,
36 Number12 = 31,
37 Number0ornumber10 = 32,
38 Numbers1 = 33,
39 Numbers2 = 34,
40 Numbers3 = 35,
41 Numbers4 = 36,
42 Numbers5 = 37,
43 Numbers6 = 38,
44 Numbers7 = 39,
45 Numbers8 = 40,
46 Numbers9 = 41,
47 Dot = 42,
48 Enter = 43,
49 Clear = 44,
50 Nextfavorite = 47,
51 Channelup = 48,
52 Channeldown = 49,
53 Previouschannel = 50,
54 Soundselect = 51,
55 Inputselect = 52,
56 Displayinformation = 53,
57 Help = 54,
58 Pageup = 55,
59 Pagedown = 56,
60 Power = 64,
61 Volumeup = 65,
62 Volumedown = 66,
63 Mute = 67,
64 Play = 68,
65 Stop = 69,
66 Pause = 70,
67 Record = 71,
68 Rewind = 72,
69 Fastforward = 73,
70 Eject = 74,
71 Forward = 75,
72 Backward = 76,
73 Stoprecord = 77,
74 Pauserecord = 78,
75 Reserved = 79,
76 Angle = 80,
77 Subpicture = 81,
78 Videoondemand = 82,
79 Electronicprogramguide = 83,
80 Timerprogramming = 84,
81 Initialconfiguration = 85,
82 Selectbroadcasttype = 86,
83 Selectsoundpresentation = 87,
84 Playfunction = 96,
85 Pauseplayfunction = 97,
86 Recordfunction = 98,
87 Pauserecordfunction = 99,
88 Stopfunction = 100,
89 Mutefunction = 101,
90 Restorevolumefunction = 102,
91 Tunefunction = 103,
92 Selectmediafunction = 104,
93 Selectavinputfunction = 105,
94 Selectaudioinputfunction = 106,
95 Powertogglefunction = 107,
96 Powerofffunction = 108,
97 Poweronfunction = 109,
98 F1blue = 113,
99 F2red = 114,
100 F3green = 115,
101 F4yellow = 116,
102 F5 = 117,
103 Data = 118,
104}
105
106impl CecKeyCode {
107 pub fn from_u8(value: u8) -> Option<Self> {
109 match value {
110 0 => Some(CecKeyCode::Select),
111 1 => Some(CecKeyCode::Up),
112 2 => Some(CecKeyCode::Down),
113 3 => Some(CecKeyCode::Left),
114 4 => Some(CecKeyCode::Right),
115 5 => Some(CecKeyCode::Rightup),
116 6 => Some(CecKeyCode::Rightdown),
117 7 => Some(CecKeyCode::Leftup),
118 8 => Some(CecKeyCode::Leftdown),
119 9 => Some(CecKeyCode::Rootmenu),
120 10 => Some(CecKeyCode::Setupmenu),
121 11 => Some(CecKeyCode::Contentsmenu),
122 12 => Some(CecKeyCode::Favoritemenu),
123 13 => Some(CecKeyCode::Exit),
124 16 => Some(CecKeyCode::Mediatopmenu),
125 17 => Some(CecKeyCode::Mediacontextsensitivemenu),
126 29 => Some(CecKeyCode::Numberentrymode),
127 30 => Some(CecKeyCode::Number11),
128 31 => Some(CecKeyCode::Number12),
129 32 => Some(CecKeyCode::Number0ornumber10),
130 33 => Some(CecKeyCode::Numbers1),
131 34 => Some(CecKeyCode::Numbers2),
132 35 => Some(CecKeyCode::Numbers3),
133 36 => Some(CecKeyCode::Numbers4),
134 37 => Some(CecKeyCode::Numbers5),
135 38 => Some(CecKeyCode::Numbers6),
136 39 => Some(CecKeyCode::Numbers7),
137 40 => Some(CecKeyCode::Numbers8),
138 41 => Some(CecKeyCode::Numbers9),
139 42 => Some(CecKeyCode::Dot),
140 43 => Some(CecKeyCode::Enter),
141 44 => Some(CecKeyCode::Clear),
142 47 => Some(CecKeyCode::Nextfavorite),
143 48 => Some(CecKeyCode::Channelup),
144 49 => Some(CecKeyCode::Channeldown),
145 50 => Some(CecKeyCode::Previouschannel),
146 51 => Some(CecKeyCode::Soundselect),
147 52 => Some(CecKeyCode::Inputselect),
148 53 => Some(CecKeyCode::Displayinformation),
149 54 => Some(CecKeyCode::Help),
150 55 => Some(CecKeyCode::Pageup),
151 56 => Some(CecKeyCode::Pagedown),
152 64 => Some(CecKeyCode::Power),
153 65 => Some(CecKeyCode::Volumeup),
154 66 => Some(CecKeyCode::Volumedown),
155 67 => Some(CecKeyCode::Mute),
156 68 => Some(CecKeyCode::Play),
157 69 => Some(CecKeyCode::Stop),
158 70 => Some(CecKeyCode::Pause),
159 71 => Some(CecKeyCode::Record),
160 72 => Some(CecKeyCode::Rewind),
161 73 => Some(CecKeyCode::Fastforward),
162 74 => Some(CecKeyCode::Eject),
163 75 => Some(CecKeyCode::Forward),
164 76 => Some(CecKeyCode::Backward),
165 77 => Some(CecKeyCode::Stoprecord),
166 78 => Some(CecKeyCode::Pauserecord),
167 79 => Some(CecKeyCode::Reserved),
168 80 => Some(CecKeyCode::Angle),
169 81 => Some(CecKeyCode::Subpicture),
170 82 => Some(CecKeyCode::Videoondemand),
171 83 => Some(CecKeyCode::Electronicprogramguide),
172 84 => Some(CecKeyCode::Timerprogramming),
173 85 => Some(CecKeyCode::Initialconfiguration),
174 86 => Some(CecKeyCode::Selectbroadcasttype),
175 87 => Some(CecKeyCode::Selectsoundpresentation),
176 96 => Some(CecKeyCode::Playfunction),
177 97 => Some(CecKeyCode::Pauseplayfunction),
178 98 => Some(CecKeyCode::Recordfunction),
179 99 => Some(CecKeyCode::Pauserecordfunction),
180 100 => Some(CecKeyCode::Stopfunction),
181 101 => Some(CecKeyCode::Mutefunction),
182 102 => Some(CecKeyCode::Restorevolumefunction),
183 103 => Some(CecKeyCode::Tunefunction),
184 104 => Some(CecKeyCode::Selectmediafunction),
185 105 => Some(CecKeyCode::Selectavinputfunction),
186 106 => Some(CecKeyCode::Selectaudioinputfunction),
187 107 => Some(CecKeyCode::Powertogglefunction),
188 108 => Some(CecKeyCode::Powerofffunction),
189 109 => Some(CecKeyCode::Poweronfunction),
190 113 => Some(CecKeyCode::F1blue),
191 114 => Some(CecKeyCode::F2red),
192 115 => Some(CecKeyCode::F3green),
193 116 => Some(CecKeyCode::F4yellow),
194 117 => Some(CecKeyCode::F5),
195 118 => Some(CecKeyCode::Data),
196 _ => None,
197 }
198 }
199
200 pub fn to_u8(self) -> u8 {
202 self as u8
203 }
204}
205
206impl From<CecKeyCode> for u8 {
207 fn from(val: CecKeyCode) -> Self {
208 val as u8
209 }
210}
211
212#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
213#[repr(u8)]
214pub enum Status {
215 Success = 0,
217 Unsupportedkey = 1,
219 Invalidkeyincurrentstate = 2,
221}
222
223impl Status {
224 pub fn from_u8(value: u8) -> Option<Self> {
226 match value {
227 0 => Some(Status::Success),
228 1 => Some(Status::Unsupportedkey),
229 2 => Some(Status::Invalidkeyincurrentstate),
230 _ => None,
231 }
232 }
233
234 pub fn to_u8(self) -> u8 {
236 self as u8
237 }
238}
239
240impl From<Status> for u8 {
241 fn from(val: Status) -> Self {
242 val as u8
243 }
244}
245
246pub fn encode_send_key(key_code: CecKeyCode) -> anyhow::Result<Vec<u8>> {
250 let tlv = tlv::TlvItemEnc {
251 tag: 0,
252 value: tlv::TlvItemValueEnc::StructInvisible(vec![
253 (0, tlv::TlvItemValueEnc::UInt8(key_code.to_u8())).into(),
254 ]),
255 };
256 Ok(tlv.encode()?)
257}
258
259pub fn get_command_list() -> Vec<(u32, &'static str)> {
262 vec![
263 (0x00, "SendKey"),
264 ]
265}
266
267pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
268 match cmd_id {
269 0x00 => Some("SendKey"),
270 _ => None,
271 }
272}
273
274pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
275 match cmd_id {
276 0x00 => Some(vec![
277 crate::clusters::codec::CommandField { tag: 0, name: "key_code", kind: crate::clusters::codec::FieldKind::Enum { name: "CecKeyCode", variants: &[(0, "Select"), (1, "Up"), (2, "Down"), (3, "Left"), (4, "Right"), (5, "Rightup"), (6, "Rightdown"), (7, "Leftup"), (8, "Leftdown"), (9, "Rootmenu"), (10, "Setupmenu"), (11, "Contentsmenu"), (12, "Favoritemenu"), (13, "Exit"), (16, "Mediatopmenu"), (17, "Mediacontextsensitivemenu"), (29, "Numberentrymode"), (30, "Number11"), (31, "Number12"), (32, "Number0ornumber10"), (33, "Numbers1"), (34, "Numbers2"), (35, "Numbers3"), (36, "Numbers4"), (37, "Numbers5"), (38, "Numbers6"), (39, "Numbers7"), (40, "Numbers8"), (41, "Numbers9"), (42, "Dot"), (43, "Enter"), (44, "Clear"), (47, "Nextfavorite"), (48, "Channelup"), (49, "Channeldown"), (50, "Previouschannel"), (51, "Soundselect"), (52, "Inputselect"), (53, "Displayinformation"), (54, "Help"), (55, "Pageup"), (56, "Pagedown"), (64, "Power"), (65, "Volumeup"), (66, "Volumedown"), (67, "Mute"), (68, "Play"), (69, "Stop"), (70, "Pause"), (71, "Record"), (72, "Rewind"), (73, "Fastforward"), (74, "Eject"), (75, "Forward"), (76, "Backward"), (77, "Stoprecord"), (78, "Pauserecord"), (79, "Reserved"), (80, "Angle"), (81, "Subpicture"), (82, "Videoondemand"), (83, "Electronicprogramguide"), (84, "Timerprogramming"), (85, "Initialconfiguration"), (86, "Selectbroadcasttype"), (87, "Selectsoundpresentation"), (96, "Playfunction"), (97, "Pauseplayfunction"), (98, "Recordfunction"), (99, "Pauserecordfunction"), (100, "Stopfunction"), (101, "Mutefunction"), (102, "Restorevolumefunction"), (103, "Tunefunction"), (104, "Selectmediafunction"), (105, "Selectavinputfunction"), (106, "Selectaudioinputfunction"), (107, "Powertogglefunction"), (108, "Powerofffunction"), (109, "Poweronfunction"), (113, "F1blue"), (114, "F2red"), (115, "F3green"), (116, "F4yellow"), (117, "F5"), (118, "Data")] }, optional: false, nullable: false },
278 ]),
279 _ => None,
280 }
281}
282
283pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
284 match cmd_id {
285 0x00 => {
286 let key_code = {
287 let n = crate::clusters::codec::json_util::get_u64(args, "key_code")?;
288 CecKeyCode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid CecKeyCode: {}", n))?
289 };
290 encode_send_key(key_code)
291 }
292 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
293 }
294}
295
296#[derive(Debug, serde::Serialize)]
297pub struct SendKeyResponse {
298 pub status: Option<Status>,
299}
300
301pub fn decode_send_key_response(inp: &tlv::TlvItemValue) -> anyhow::Result<SendKeyResponse> {
305 if let tlv::TlvItemValue::List(_fields) = inp {
306 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
307 Ok(SendKeyResponse {
308 status: item.get_int(&[0]).and_then(|v| Status::from_u8(v as u8)),
309 })
310 } else {
311 Err(anyhow::anyhow!("Expected struct fields"))
312 }
313}
314
315pub async fn send_key(conn: &crate::controller::Connection, endpoint: u16, key_code: CecKeyCode) -> anyhow::Result<SendKeyResponse> {
319 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_KEYPAD_INPUT, crate::clusters::defs::CLUSTER_KEYPAD_INPUT_CMD_ID_SENDKEY, &encode_send_key(key_code)?).await?;
320 decode_send_key_response(&tlv)
321}
322