Commit | Line | Data |
---|---|---|
a75e3a5a LOK |
1 | /* |
2 | * This file is part of the libCEC(R) library. | |
3 | * | |
4 | * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. | |
5 | * libCEC(R) is an original work, containing original code. | |
6 | * | |
7 | * libCEC(R) is a trademark of Pulse-Eight Limited. | |
8 | * | |
9 | * This program is dual-licensed; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
22 | * | |
23 | * | |
24 | * Alternatively, you can license this library under a commercial license, | |
25 | * please contact Pulse-Eight Licensing for more information. | |
26 | * | |
27 | * For more information contact: | |
28 | * Pulse-Eight Licensing <license@pulse-eight.com> | |
29 | * http://www.pulse-eight.com/ | |
30 | * http://www.pulse-eight.net/ | |
31 | */ | |
32 | ||
33 | #include "USBCECAdapterCommands.h" | |
34 | #include "../LibCEC.h" | |
35 | #include "../CECProcessor.h" | |
36 | ||
37 | using namespace CEC; | |
38 | using namespace PLATFORM; | |
39 | ||
40 | cec_datapacket CUSBCECAdapterCommands::RequestSetting(cec_adapter_messagecode msgCode) | |
41 | { | |
42 | cec_datapacket retVal; | |
43 | retVal.Clear(); | |
44 | ||
45 | CCECAdapterMessage params; | |
46 | CCECAdapterMessage *message = m_comm->SendCommand(msgCode, params); | |
47 | if (message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED) | |
48 | { | |
49 | retVal = message->response; | |
50 | retVal.Shift(2); // shift out start and msgcode | |
51 | retVal.size -= 1; // remove end | |
52 | } | |
53 | delete message; | |
54 | return retVal; | |
55 | } | |
56 | ||
57 | uint16_t CUSBCECAdapterCommands::RequestFirmwareVersion(void) | |
58 | { | |
59 | m_iFirmwareVersion = CEC_FW_VERSION_UNKNOWN; | |
60 | unsigned int iFwVersionTry(0); | |
61 | ||
62 | while (m_iFirmwareVersion == CEC_FW_VERSION_UNKNOWN && iFwVersionTry++ < 3) | |
63 | { | |
64 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting the firmware version"); | |
65 | cec_datapacket response = RequestSetting(MSGCODE_FIRMWARE_VERSION); | |
66 | if (response.size == 2) | |
67 | m_iFirmwareVersion = (response[0] << 8 | response[1]); | |
68 | else | |
69 | { | |
70 | CLibCEC::AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d)", iFwVersionTry); | |
71 | CEvent::Sleep(500); | |
72 | } | |
73 | } | |
74 | ||
75 | if (m_iFirmwareVersion == CEC_FW_VERSION_UNKNOWN) | |
76 | { | |
77 | CLibCEC::AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1"); | |
78 | m_iFirmwareVersion = 1; | |
79 | } | |
80 | ||
81 | return m_iFirmwareVersion; | |
82 | } | |
83 | ||
84 | bool CUSBCECAdapterCommands::RequestSettingAutoEnabled(bool &enabled) | |
85 | { | |
86 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting autonomous mode setting"); | |
87 | ||
88 | cec_datapacket response = RequestSetting(MSGCODE_GET_AUTO_ENABLED); | |
89 | if (response.size == 1) | |
90 | { | |
91 | enabled = response[0] == 1; | |
92 | return true; | |
93 | } | |
94 | return false; | |
95 | } | |
96 | ||
97 | bool CUSBCECAdapterCommands::RequestSettingCECVersion(cec_version &version) | |
98 | { | |
99 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting CEC version setting"); | |
100 | ||
101 | cec_datapacket response = RequestSetting(MSGCODE_GET_HDMI_VERSION); | |
102 | if (response.size == 1) | |
103 | { | |
104 | version = (cec_version)response[0]; | |
105 | return true; | |
106 | } | |
107 | return false; | |
108 | } | |
109 | ||
110 | bool CUSBCECAdapterCommands::RequestSettingDefaultLogicalAddress(cec_logical_address &address) | |
111 | { | |
112 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting default logical address setting"); | |
113 | ||
114 | cec_datapacket response = RequestSetting(MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS); | |
115 | if (response.size == 1) | |
116 | { | |
117 | address = (cec_logical_address)response[0]; | |
118 | return true; | |
119 | } | |
120 | return false; | |
121 | } | |
122 | ||
123 | bool CUSBCECAdapterCommands::RequestSettingDeviceType(cec_device_type &value) | |
124 | { | |
125 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting device type setting"); | |
126 | ||
127 | cec_datapacket response = RequestSetting(MSGCODE_GET_DEVICE_TYPE); | |
128 | if (response.size == 1) | |
129 | { | |
130 | value = (cec_device_type)response[0]; | |
131 | return true; | |
132 | } | |
133 | return false; | |
134 | } | |
135 | ||
136 | bool CUSBCECAdapterCommands::RequestSettingLogicalAddressMask(uint16_t &iMask) | |
137 | { | |
138 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting logical address mask setting"); | |
139 | ||
140 | cec_datapacket response = RequestSetting(MSGCODE_GET_LOGICAL_ADDRESS_MASK); | |
141 | if (response.size == 2) | |
142 | { | |
143 | iMask = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]); | |
144 | return true; | |
145 | } | |
146 | return false; | |
147 | } | |
148 | ||
149 | bool CUSBCECAdapterCommands::RequestSettingOSDName(CStdString &strOSDName) | |
150 | { | |
151 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting OSD name setting"); | |
152 | ||
153 | cec_datapacket response = RequestSetting(MSGCODE_GET_OSD_NAME); | |
154 | if (response.size == 0) | |
155 | return false; | |
156 | ||
157 | char buf[14]; | |
158 | for (uint8_t iPtr = 0; iPtr < response.size && iPtr < 13; iPtr++) | |
159 | buf[iPtr] = (char)response[iPtr]; | |
160 | buf[response.size] = 0; | |
161 | ||
162 | strOSDName.Format("%s", buf); | |
163 | return true; | |
164 | } | |
165 | ||
166 | bool CUSBCECAdapterCommands::RequestSettingPhysicalAddress(uint16_t &iPhysicalAddress) | |
167 | { | |
168 | CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting physical address setting"); | |
169 | ||
170 | cec_datapacket response = RequestSetting(MSGCODE_GET_PHYSICAL_ADDRESS); | |
171 | if (response.size == 2) | |
172 | { | |
173 | iPhysicalAddress = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]); | |
174 | return true; | |
175 | } | |
176 | return false; | |
177 | } | |
178 | ||
179 | bool CUSBCECAdapterCommands::SetSettingAutoEnabled(bool enabled) | |
180 | { | |
181 | CLibCEC::AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off"); | |
182 | ||
183 | CCECAdapterMessage params; | |
184 | params.PushEscaped(enabled ? 1 : 0); | |
185 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_AUTO_ENABLED, params); | |
186 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
187 | delete message; | |
188 | return bReturn; | |
189 | } | |
190 | ||
191 | bool CUSBCECAdapterCommands::SetSettingDeviceType(cec_device_type type) | |
192 | { | |
193 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the device type to %1X", (uint8_t)type); | |
194 | ||
195 | CCECAdapterMessage params; | |
196 | params.PushEscaped((uint8_t)type); | |
197 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_DEVICE_TYPE, params); | |
198 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
199 | delete message; | |
200 | return bReturn; | |
201 | } | |
202 | ||
203 | bool CUSBCECAdapterCommands::SetSettingDefaultLogicalAddress(cec_logical_address address) | |
204 | { | |
205 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the default logical address to %1X", address); | |
206 | ||
207 | CCECAdapterMessage params; | |
208 | params.PushEscaped((uint8_t)address); | |
209 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, params); | |
210 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
211 | delete message; | |
212 | return bReturn; | |
213 | } | |
214 | ||
215 | bool CUSBCECAdapterCommands::SetSettingLogicalAddressMask(uint16_t iMask) | |
216 | { | |
217 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X", iMask); | |
218 | ||
219 | CCECAdapterMessage params; | |
220 | params.PushEscaped(iMask >> 8); | |
221 | params.PushEscaped((uint8_t)iMask); | |
222 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_LOGICAL_ADDRESS_MASK, params); | |
223 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
224 | delete message; | |
225 | return bReturn; | |
226 | } | |
227 | ||
228 | bool CUSBCECAdapterCommands::SetSettingPhysicalAddress(uint16_t iPhysicalAddress) | |
229 | { | |
230 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the physical address to %04X", iPhysicalAddress); | |
231 | ||
232 | CCECAdapterMessage params; | |
233 | params.PushEscaped(iPhysicalAddress >> 8); | |
234 | params.PushEscaped((uint8_t)iPhysicalAddress); | |
235 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_PHYSICAL_ADDRESS, params); | |
236 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
237 | delete message; | |
238 | return bReturn; | |
239 | } | |
240 | ||
241 | bool CUSBCECAdapterCommands::SetSettingCECVersion(cec_version version) | |
242 | { | |
243 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s", CLibCEC::GetInstance()->ToString(version)); | |
244 | ||
245 | CCECAdapterMessage params; | |
246 | params.PushEscaped((uint8_t)version); | |
247 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_HDMI_VERSION, params); | |
248 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
249 | delete message; | |
250 | return bReturn; | |
251 | } | |
252 | ||
253 | bool CUSBCECAdapterCommands::SetSettingOSDName(const char *strOSDName) | |
254 | { | |
255 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s", strOSDName); | |
256 | ||
257 | CCECAdapterMessage params; | |
258 | for (size_t iPtr = 0; iPtr < strlen(strOSDName); iPtr++) | |
259 | params.PushEscaped(strOSDName[iPtr]); | |
260 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_OSD_NAME, params); | |
261 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
262 | delete message; | |
263 | return bReturn; | |
264 | } | |
265 | ||
266 | bool CUSBCECAdapterCommands::WriteEEPROM(void) | |
267 | { | |
268 | CLibCEC::AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM"); | |
269 | ||
270 | CCECAdapterMessage params; | |
271 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_WRITE_EEPROM, params); | |
272 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
273 | delete message; | |
274 | return bReturn; | |
275 | } | |
276 | ||
277 | bool CUSBCECAdapterCommands::PersistConfiguration(libcec_configuration *configuration) | |
278 | { | |
279 | if (m_iFirmwareVersion < 2) | |
280 | return false; | |
281 | ||
282 | bool bReturn(true); | |
283 | bReturn &= SetSettingAutoEnabled(true); | |
284 | bReturn &= SetSettingDeviceType(CLibCEC::GetType(configuration->logicalAddresses.primary)); | |
285 | bReturn &= SetSettingDefaultLogicalAddress(configuration->logicalAddresses.primary); | |
286 | bReturn &= SetSettingLogicalAddressMask(CLibCEC::GetMaskForType(configuration->logicalAddresses.primary)); | |
287 | bReturn &= SetSettingPhysicalAddress(configuration->iPhysicalAddress); | |
288 | bReturn &= SetSettingCECVersion(CEC_VERSION_1_3A); | |
289 | bReturn &= SetSettingOSDName(configuration->strDeviceName); | |
290 | if (bReturn) | |
291 | bReturn = WriteEEPROM(); | |
292 | return bReturn; | |
293 | } | |
294 | ||
295 | bool CUSBCECAdapterCommands::GetConfiguration(libcec_configuration *configuration) | |
296 | { | |
297 | configuration->iFirmwareVersion = m_iFirmwareVersion; | |
298 | if (m_iFirmwareVersion < 2) | |
299 | return false; | |
300 | ||
301 | bool bReturn(true); | |
302 | cec_device_type type; | |
303 | if (RequestSettingDeviceType(type)) | |
304 | { | |
305 | CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted device type setting %s", CLibCEC::GetInstance()->ToString(type)); | |
306 | configuration->deviceTypes.Clear(); | |
307 | configuration->deviceTypes.Add(type); | |
308 | } | |
309 | else | |
310 | { | |
311 | CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted device type setting"); | |
312 | bReturn = false; | |
313 | } | |
314 | ||
315 | if (RequestSettingPhysicalAddress(configuration->iPhysicalAddress)) | |
316 | { | |
317 | CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted physical address setting %4x", configuration->iPhysicalAddress); | |
318 | } | |
319 | else | |
320 | { | |
321 | CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted physical address setting"); | |
322 | bReturn = false; | |
323 | } | |
324 | ||
325 | CStdString strDeviceName; | |
326 | if (RequestSettingOSDName(strDeviceName)) | |
327 | { | |
328 | snprintf(configuration->strDeviceName, 13, "%s", strDeviceName.c_str()); | |
329 | CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted device name setting %s", configuration->strDeviceName); | |
330 | } | |
331 | else | |
332 | { | |
333 | CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted device name setting"); | |
334 | bReturn = false; | |
335 | } | |
336 | ||
337 | // don't read the following settings: | |
338 | // - auto enabled (always enabled) | |
339 | // - default logical address (autodetected) | |
340 | // - logical address mask (autodetected) | |
341 | // - CEC version (1.3a) | |
342 | ||
343 | // TODO to be added to the firmware: | |
344 | // - base device (4 bits) | |
345 | // - HDMI port number (4 bits) | |
346 | // - TV vendor id (12 bits) | |
347 | // - wake devices (8 bits) | |
348 | // - standby devices (8 bits) | |
349 | // - use TV menu language (1 bit) | |
350 | // - activate source (1 bit) | |
351 | // - power off screensaver (1 bit) | |
352 | // - power off on standby (1 bit) | |
353 | // - send inactive source (1 bit) | |
354 | return bReturn; | |
355 | } | |
356 | ||
357 | bool CUSBCECAdapterCommands::PingAdapter(void) | |
358 | { | |
359 | CLibCEC::AddLog(CEC_LOG_DEBUG, "sending ping"); | |
360 | ||
361 | CCECAdapterMessage params; | |
362 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_PING, params); | |
363 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
364 | delete message; | |
365 | return bReturn; | |
366 | } | |
367 | ||
368 | bool CUSBCECAdapterCommands::SetAckMask(uint16_t iMask) | |
369 | { | |
370 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask); | |
371 | ||
372 | CCECAdapterMessage params; | |
373 | params.PushEscaped(iMask >> 8); | |
374 | params.PushEscaped((uint8_t)iMask); | |
375 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_ACK_MASK, params); | |
376 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
377 | delete message; | |
378 | return bReturn; | |
379 | } | |
380 | ||
381 | bool CUSBCECAdapterCommands::StartBootloader(void) | |
382 | { | |
383 | CLibCEC::AddLog(CEC_LOG_DEBUG, "starting the bootloader"); | |
384 | ||
385 | CCECAdapterMessage params; | |
386 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_START_BOOTLOADER, params); | |
387 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
388 | delete message; | |
389 | return bReturn; | |
390 | } | |
391 | ||
392 | bool CUSBCECAdapterCommands::SetLineTimeout(uint8_t iTimeout) | |
393 | { | |
394 | CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the line timeout to %d", iTimeout); | |
395 | CCECAdapterMessage params; | |
396 | params.PushEscaped(iTimeout); | |
397 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_TRANSMIT_IDLETIME, params); | |
398 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
399 | delete message; | |
400 | return bReturn; | |
401 | } | |
402 | ||
403 | bool CUSBCECAdapterCommands::SetControlledMode(bool controlled) | |
404 | { | |
405 | CLibCEC::AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off"); | |
406 | ||
407 | CCECAdapterMessage params; | |
408 | params.PushEscaped(controlled ? 1 : 0); | |
409 | CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_CONTROLLED, params); | |
410 | bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; | |
411 | delete message; | |
412 | return bReturn; | |
413 | } |