-
Notifications
You must be signed in to change notification settings - Fork 1
/
CEC.ino
134 lines (104 loc) · 5.04 KB
/
CEC.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "CEC_Device.h"
#define IN_LINE 2
#define OUT_LINE 3
#define HPD_LINE 10
// ugly macro to do debug printing in the OnReceive method
//#define report(X) do { DbgPrint("report " #X "\n"); report ## X (); } while (0)
#define report(X, source) do { /*DbgPrint("report " #X "- %d\n", source);*/ report ## X (source); } while (0)
#define phy1 ((_physicalAddress >> 8) & 0xFF)
#define phy2 ((_physicalAddress >> 0) & 0xFF)
unsigned char powerstate[2] = { 0x90, 0x00 };
class MyCEC: public CEC_Device {
public:
MyCEC(int physAddr): CEC_Device(physAddr,IN_LINE,OUT_LINE) { }
void reportPhysAddr(int source = 0x00) { unsigned char frame[4] = { 0x84, phy1, phy2, 0x04 }; TransmitFrame(0x0F,frame,sizeof(frame)); } // report physical address
void reportStreamState(int source = 0x00) { unsigned char frame[3] = { 0x82, phy1, phy2 }; TransmitFrame(0x0F,frame,sizeof(frame)); } // report stream state (playing)
void reportPowerState(int source = 0x00) { /*unsigned char frame[2] = { 0x90, 0x00 }; */ TransmitFrame(source,powerstate,sizeof(powerstate)); } // report power state (on)
void reportCECVersion(int source = 0x00) { unsigned char frame[2] = { 0x9E, 0x04 }; TransmitFrame(source,frame,sizeof(frame)); } // report CEC version (v1.3a)
//TODO: Fix OSDName, sometimes it doens't work...
void reportOSDName(int source = 0x00) { unsigned char frame[5] = { 0x47, 'H','T','P','C' }; TransmitFrame(source,frame,sizeof(frame)); } // FIXME: name hardcoded
void reportVendorID(int source = 0x00) { unsigned char frame[4] = { 0x87, 0x00, 0xF1, 0x0E }; TransmitFrame(source,frame,sizeof(frame)); } // report fake vendor ID
void reportMenuActivated(int source = 0x00) { unsigned char frame[2] = { 0x8E, 0x00 }; TransmitFrame(source,frame,sizeof(frame)); } // report fake vendor ID
void handleKey(unsigned char keypress, unsigned char key = 0x00) {
DbgPrint("KEY:%d:%d\n", keypress, key);
}
void handlePowerState(unsigned char* buffer, int count){
//DbgPrint("Count: %d", count);
//for (int i=0; i<count; i++)
// DbgPrint("Buffer[%d]: %d", i, buffer[i]);
if (buffer[1] == phy1 && buffer[2] == phy2)
powerstate[1] = 0x00; //On
else
powerstate[2] = 0x01; //Stand-By
}
void OnReceive(int source, int dest, unsigned char* buffer, int count) {
if (count == 0) return;
//Controllare se è monitor altrimetni intercettare solo i propri.
switch (buffer[0]) {
case 0x36: DbgPrint("standby\n"); break;
case 0x83: report(PhysAddr, source); break;
case 0x86: if (buffer[1] == phy1 && buffer[2] == phy2)
report(StreamState, source);
break;
case 0x80: handlePowerState(buffer, count); break;
case 0x82: handlePowerState(buffer, count); break;
case 0x8F: report(PowerState, source); break;
case 0x9F: report(CECVersion, source); break;
case 0x46: report(OSDName, source); break;
case 0x8C: report(VendorID, source); break;
case 0x8D: if(buffer[1] == 0x02)
report(MenuActivated, source);
break;
case 0x44: handleKey(buffer[0], buffer[1]); break;
case 0x45: handleKey(buffer[0]); break;
case 0x8A: handleKey(buffer[0], buffer[1]); break;
case 0x41: handleKey(buffer[0], buffer[1]); break;
case 0x42: handleKey(buffer[0], buffer[1]); break;
default: CEC_Device::OnReceive(source,dest,buffer,count); break;
}
}
};
// TODO: set physical address via serial (or even DDC?)
// Note: this does not need to correspond to the physical address (i.e. port number)
// where the Arduino is connected - in fact, it _should_ be a different port, namely
// the one where the PC to be controlled is connected. Basically, it is the address
// of the port where the CEC-less source device is plugged in.
MyCEC device(0x1000);
void setup()
{
// setup Hotplug pin
pinMode(HPD_LINE,INPUT);
Serial.begin(115200);
//Keyboard.begin();
//device.MonitorMode = true;
//device.Promiscuous = true;
device.Initialize(CEC_LogicalDevice::CDT_RECORDING_DEVICE);
}
void loop()
{
// FIXME: does it still work without serial connected?
// try to toggle LED e.g.
if (Serial.available())
{
unsigned char c = Serial.read();
unsigned char buffer[2] = { c, 0 };
Serial.print("Command: "); Serial.println((const char*)buffer);
switch (c)
{
case 'v':
// request vendor ID
buffer[0] = 0x8C;
device.TransmitFrame(0, buffer, 1);
break;
case 'p':
// toggle promiscuous mode
device.Promiscuous = !(device.Promiscuous);
break;
case 'h':
// query Hotplug pin
Serial.print("Hotplug state: "); Serial.println(digitalRead(HPD_LINE));
break;
}
}
device.Run();
}