Skip to content
Snippets Groups Projects
Commit 3f74ab0e authored by Jungshik Jang's avatar Jungshik Jang
Browse files

Implement logical address allocation logic for HDMI CEC.

Logical address in CEC is to distinguish each logical device from others.
In order to allocate logical address for new device, CEC sends
<Polling Message> to CEC bus. <Polling Message> is a CEC message
which has the same address for both source and destination without
body frame. (10bits).
CEC allows one and more logical address for a device type.
For example, there are 3 logical address defined for recorder device(1, 2, 9).
Among logical address candidates for the given device type, CEC scans
first the previous logical address (preferred logical address) of device.
If a device has not been allocated any logical address, preferred address
will be 15 (Unregistered), which means scan address from the minimum address
number of type. For example for recorder device, it starts from 1.
If no devices acks to the <Polling Message> during scan, it will be the
logical address of the device.
Since logical address is determined by a series of sending <Polling Message>
it happens in IO thread with separate allocate logical address message
instead of individual sendCommand message.

Along with this, updated ADDR_FREE_USE(14) to ADDR_SPECIFIC_USE(14)
which is revised name on HDMI 1.4.

Change-Id: Ic96dcdbe4aaa3789cfed0352a88ca75369335a98
parent 8822d4be
No related branches found
No related tags found
No related merge requests found
......@@ -12287,7 +12287,6 @@ package android.hardware.hdmi {
method public static boolean isValidType(int);
field public static final int ADDR_AUDIO_SYSTEM = 5; // 0x5
field public static final int ADDR_BROADCAST = 15; // 0xf
field public static final int ADDR_FREE_USE = 14; // 0xe
field public static final int ADDR_INVALID = -1; // 0xffffffff
field public static final int ADDR_PLAYBACK_1 = 4; // 0x4
field public static final int ADDR_PLAYBACK_2 = 8; // 0x8
......@@ -12297,6 +12296,7 @@ package android.hardware.hdmi {
field public static final int ADDR_RECORDER_3 = 9; // 0x9
field public static final int ADDR_RESERVED_1 = 12; // 0xc
field public static final int ADDR_RESERVED_2 = 13; // 0xd
field public static final int ADDR_SPECIFIC_USE = 14; // 0xe
field public static final int ADDR_TUNER_1 = 3; // 0x3
field public static final int ADDR_TUNER_2 = 6; // 0x6
field public static final int ADDR_TUNER_3 = 7; // 0x7
......@@ -85,7 +85,7 @@ public final class HdmiCec {
public static final int ADDR_RESERVED_2 = 13;
/** Logical address for TV other than the one assigned with {@link #ADDR_TV} */
public static final int ADDR_FREE_USE = 14;
public static final int ADDR_SPECIFIC_USE = 14;
/** Logical address for devices to which address cannot be allocated */
public static final int ADDR_UNREGISTERED = 15;
......@@ -179,6 +179,7 @@ public final class HdmiCec {
DEVICE_RECORDER, // ADDR_RECORDER_3
DEVICE_TUNER, // ADDR_TUNER_4
DEVICE_PLAYBACK, // ADDR_PLAYBACK_3
DEVICE_TV, // ADDR_SPECIFIC_USE
};
private static final String[] DEFAULT_NAMES = {
......@@ -194,6 +195,7 @@ public final class HdmiCec {
"Recorder_3",
"Tuner_4",
"Playback_3",
"Secondary_TV",
};
private HdmiCec() { } // Prevents instantiation.
......@@ -221,9 +223,7 @@ public final class HdmiCec {
* @return true if the given address is valid
*/
public static boolean isValidAddress(int address) {
// TODO: We leave out the address 'free use(14)' for now. Check this later
// again to make sure it is a valid address for communication.
return (ADDR_TV <= address && address <= ADDR_PLAYBACK_3);
return (ADDR_TV <= address && address <= ADDR_SPECIFIC_USE);
}
/**
......
......@@ -25,6 +25,8 @@ import android.os.Message;
import android.util.Slog;
import android.util.SparseArray;
import libcore.util.EmptyArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
......@@ -41,11 +43,17 @@ import java.util.List;
class HdmiCecController {
private static final String TAG = "HdmiCecController";
private static final byte[] EMPTY_BODY = EmptyArray.BYTE;
// A message to pass cec send command to IO looper.
private static final int MSG_SEND_CEC_COMMAND = 1;
// A message to delegate logical allocation to IO looper.
private static final int MSG_ALLOCATE_LOGICAL_ADDRESS = 2;
// Message types to handle incoming message in main service looper.
private final static int MSG_RECEIVE_CEC_COMMAND = 1;
// A message to report allocated logical address to main control looper.
private final static int MSG_REPORT_LOGICAL_ADDRESS = 2;
// TODO: move these values to HdmiCec.java once make it internal constant class.
// CEC's ABORT reason values.
......@@ -56,6 +64,11 @@ class HdmiCecController {
private static final int ABORT_REFUSED = 4;
private static final int ABORT_UNABLE_TO_DETERMINE = 5;
private static final int NUM_LOGICAL_ADDRESS = 16;
// TODO: define other constants for errors.
private static final int ERROR_SUCCESS = 0;
// Handler instance to process synchronous I/O (mainly send) message.
private Handler mIoHandler;
......@@ -98,6 +111,43 @@ class HdmiCecController {
return handler;
}
/**
* Interface to report allocated logical address.
*/
interface AllocateLogicalAddressCallback {
/**
* Called when a new logical address is allocated.
*
* @param deviceType requested device type to allocate logical address
* @param logicalAddress allocated logical address. If it is
* {@link HdmiCec#ADDR_UNREGISTERED}, it means that
* it failed to allocate logical address for the given device type
*/
void onAllocated(int deviceType, int logicalAddress);
}
/**
* Allocate a new logical address of the given device type. Allocated
* address will be reported through {@link AllocateLogicalAddressCallback}.
*
* <p> Declared as package-private, accessed by {@link HdmiControlService} only.
*
* @param deviceType type of device to used to determine logical address
* @param preferredAddress a logical address preferred to be allocated.
* If sets {@link HdmiCec#ADDR_UNREGISTERED}, scans
* the smallest logical address matched with the given device type.
* Otherwise, scan address will start from {@code preferredAddress}
* @param callback callback interface to report allocated logical address to caller
*/
void allocateLogicalAddress(int deviceType, int preferredAddress,
AllocateLogicalAddressCallback callback) {
Message msg = mIoHandler.obtainMessage(MSG_ALLOCATE_LOGICAL_ADDRESS);
msg.arg1 = deviceType;
msg.arg2 = preferredAddress;
msg.obj = callback;
mIoHandler.sendMessage(msg);
}
private static byte[] buildBody(int opcode, byte[] params) {
byte[] body = new byte[params.length + 1];
body[0] = (byte) opcode;
......@@ -119,11 +169,59 @@ class HdmiCecController {
nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
cecMessage.getDestination(), body);
break;
case MSG_ALLOCATE_LOGICAL_ADDRESS:
int deviceType = msg.arg1;
int preferredAddress = msg.arg2;
AllocateLogicalAddressCallback callback =
(AllocateLogicalAddressCallback) msg.obj;
handleAllocateLogicalAddress(deviceType, preferredAddress, callback);
break;
default:
Slog.w(TAG, "Unsupported CEC Io request:" + msg.what);
break;
}
}
private void handleAllocateLogicalAddress(int deviceType, int preferredAddress,
AllocateLogicalAddressCallback callback) {
int startAddress = preferredAddress;
// If preferred address is "unregistered", start_index will be the smallest
// address matched with the given device type.
if (preferredAddress == HdmiCec.ADDR_UNREGISTERED) {
for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
if (deviceType == HdmiCec.getTypeFromAddress(i)) {
startAddress = i;
break;
}
}
}
int logcialAddress = HdmiCec.ADDR_UNREGISTERED;
// Iterates all possible addresses which has the same device type.
for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
if (curAddress != HdmiCec.ADDR_UNREGISTERED
&& deviceType == HdmiCec.getTypeFromAddress(i)) {
// <Polling Message> is a message which has empty body and
// uses same address for both source and destination address.
// If sending <Polling Message> failed (NAK), it becomes
// new logical address for the device because no device uses
// it as logical address of the device.
int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress,
EMPTY_BODY);
if (error != ERROR_SUCCESS) {
logcialAddress = curAddress;
break;
}
}
}
Message msg = mControlHandler.obtainMessage(MSG_REPORT_LOGICAL_ADDRESS);
msg.arg1 = deviceType;
msg.arg2 = logcialAddress;
msg.obj = callback;
mControlHandler.sendMessage(msg);
}
}
private final class ControlHandler extends Handler {
......@@ -138,6 +236,13 @@ class HdmiCecController {
// TODO: delegate it to HdmiControl service.
onReceiveCommand((HdmiCecMessage) msg.obj);
break;
case MSG_REPORT_LOGICAL_ADDRESS:
int deviceType = msg.arg1;
int logicalAddress = msg.arg2;
AllocateLogicalAddressCallback callback =
(AllocateLogicalAddressCallback) msg.obj;
callback.onAllocated(deviceType, logicalAddress);
break;
default:
Slog.i(TAG, "Unsupported message type:" + msg.what);
break;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment