|
23 | 23 | *******************************************************************************/ |
24 | 24 | package com.github.mob41.blapi; |
25 | 25 |
|
| 26 | +import java.io.IOException; |
| 27 | +import java.net.DatagramPacket; |
| 28 | +import java.net.DatagramSocket; |
| 29 | +import java.net.InetAddress; |
| 30 | +import java.net.SocketTimeoutException; |
| 31 | +import java.util.ArrayList; |
| 32 | +import java.util.List; |
| 33 | + |
| 34 | +import org.slf4j.Logger; |
| 35 | +import org.slf4j.LoggerFactory; |
| 36 | + |
| 37 | +import com.github.mob41.blapi.mac.Mac; |
| 38 | +import com.github.mob41.blapi.pkt.DiscoveryPacket; |
| 39 | + |
26 | 40 | /** |
27 | 41 | * This is the base class of all Broadlink devices (e.g. SP1, RMPro) |
28 | 42 | * @author Anthony |
29 | 43 | * |
30 | 44 | */ |
31 | 45 | public abstract class BLDevice { |
32 | 46 |
|
| 47 | + private static final Logger log = LoggerFactory.getLogger(BLDevice.class); |
| 48 | + |
33 | 49 | public static final byte[] INITIAL_KEY = { |
34 | 50 | 0x09, 0x76, 0x28, 0x34, |
35 | 51 | 0x3f, (byte) 0xe9, (byte) 0x9e, 0x23, |
@@ -89,9 +105,139 @@ public abstract class BLDevice { |
89 | 105 | public static final short DEV_A1 = 0x2714; |
90 | 106 |
|
91 | 107 | public static final short DEV_MP1 = 0x4EB5; |
| 108 | + |
| 109 | + public static final int DISCOVERY_DEST_PORT = 80; |
| 110 | + |
| 111 | + public static final int DISCOVERY_RECEIVE_BUFFER_SIZE = 0x40; //64-bytes |
92 | 112 |
|
93 | | - public BLDevice(short deviceType, String host, String mac) { |
| 113 | + protected BLDevice(short deviceType, String host, Mac mac) { |
94 | 114 |
|
95 | 115 | } |
96 | | - |
| 116 | + |
| 117 | + public static BLDevice createInstance(short deviceType, String host, Mac mac){ |
| 118 | + switch (deviceType){ |
| 119 | + case DEV_RM_2: |
| 120 | + } |
| 121 | + return null; |
| 122 | + } |
| 123 | + |
| 124 | + public static BLDevice[] discoverDevices(InetAddress sourceIpAddr, int sourcePort, int timeout) throws IOException{ |
| 125 | + List<BLDevice> devices = new ArrayList<BLDevice>(50); |
| 126 | + |
| 127 | + DiscoveryPacket dpkt = new DiscoveryPacket(sourceIpAddr, sourcePort); |
| 128 | + |
| 129 | + DatagramSocket sock = new DatagramSocket(sourcePort, sourceIpAddr); |
| 130 | + sock.setBroadcast(true); |
| 131 | + sock.setReuseAddress(true); |
| 132 | + |
| 133 | + byte[] sendBytes = dpkt.getData(); |
| 134 | + DatagramPacket sendpack = new DatagramPacket(sendBytes, sendBytes.length, |
| 135 | + InetAddress.getByName("255.255.255.255"), DISCOVERY_DEST_PORT); |
| 136 | + sock.send(sendpack); |
| 137 | + |
| 138 | + byte[] receBytes = new byte[DISCOVERY_RECEIVE_BUFFER_SIZE]; |
| 139 | + |
| 140 | + DatagramPacket recePacket = new DatagramPacket(receBytes, 0, receBytes.length); |
| 141 | + if (timeout == 0){ |
| 142 | + sock.receive(recePacket); |
| 143 | + sock.close(); |
| 144 | + |
| 145 | + String host = recePacket.getAddress().getHostAddress(); |
| 146 | + Mac mac = new Mac(subbytes(receBytes, 0x3a, 0x40)); |
| 147 | + short deviceType = (short) (receBytes[0x34] | receBytes[0x35] << 8); |
| 148 | + |
| 149 | + BLDevice inst = createInstance(deviceType, host, mac); |
| 150 | + |
| 151 | + if (inst != null){ |
| 152 | + devices.add(inst); |
| 153 | + } |
| 154 | + } else { |
| 155 | + long startTime = System.currentTimeMillis(); |
| 156 | + long elapsed; |
| 157 | + while ((elapsed = System.currentTimeMillis() - startTime) < timeout){ |
| 158 | + sock.setSoTimeout((int) (timeout - elapsed)); |
| 159 | + |
| 160 | + try { |
| 161 | + sock.receive(recePacket); |
| 162 | + } catch (SocketTimeoutException e){ |
| 163 | + break; |
| 164 | + } |
| 165 | + |
| 166 | + String host = recePacket.getAddress().getHostAddress(); |
| 167 | + Mac mac = new Mac(subbytes(receBytes, 0x3a, 0x40)); |
| 168 | + short deviceType = (short) (receBytes[0x34] | receBytes[0x35] << 8); |
| 169 | + |
| 170 | + BLDevice inst = createInstance(deviceType, host, mac); |
| 171 | + |
| 172 | + if (inst != null){ |
| 173 | + devices.add(inst); |
| 174 | + } |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + BLDevice[] out = new BLDevice[devices.size()]; |
| 179 | + for (int i = 0; i < out.length; i++){ |
| 180 | + out[i] = devices.get(i); |
| 181 | + } |
| 182 | + |
| 183 | + return out; |
| 184 | + } |
| 185 | + |
| 186 | + /** |
| 187 | + * Picks bytes from start-set to the end-set in a bytes array |
| 188 | + * @param data The bytes array to be used |
| 189 | + * @param start The starting position to be picked |
| 190 | + * @param end The ending position to be picked |
| 191 | + * @return The bytes array picked with length (<code>end - start</code>) |
| 192 | + */ |
| 193 | + public static byte[] subbytes(byte[] data, int start, int end){ |
| 194 | + byte[] out = new byte[end - start]; |
| 195 | + |
| 196 | + int outi = 0; |
| 197 | + for (int i = start; i < end; i += 0x01, outi++){ |
| 198 | + out[outi] = data[i]; |
| 199 | + } |
| 200 | + |
| 201 | + return out; |
| 202 | + } |
| 203 | + |
| 204 | + /* Not this! This will only send once and close the connection |
| 205 | + /** |
| 206 | + * Sends a compiled packet to a destination host and port, and |
| 207 | + * receives a datagram from the source port specified. |
| 208 | + * @param pkt The compiled packet to be sent |
| 209 | + * @param sourceIpAddr Source IP address to be binded for receiving datagrams |
| 210 | + * @param sourcePort Source Port to be bineded for receiving datagrams |
| 211 | + * @param destIpAddr Destination IP address |
| 212 | + * @param destPort Destination Port |
| 213 | + * @param timeout Socket timeout. 0 will disable the timeout |
| 214 | + * @param bufSize Receiving datagram's buffer size |
| 215 | + * @return The received datagram |
| 216 | + * @throws IOException Thrown if socket timed out, cannot bind source IP and source port, no permission, etc. |
| 217 | + *\/ |
| 218 | + public static DatagramPacket sendPkt(Packet pkt, |
| 219 | + InetAddress sourceIpAddr, int sourcePort, |
| 220 | + InetAddress destIpAddr, int destPort, |
| 221 | + int timeout, int bufSize) throws IOException{ |
| 222 | + DatagramSocket sock = new DatagramSocket(sourcePort, sourceIpAddr); |
| 223 | + sock.setBroadcast(true); |
| 224 | + sock.setReuseAddress(true); |
| 225 | + |
| 226 | + //sock.bind(new InetSocketAddress(ipAddr, sourcePort)); |
| 227 | + |
| 228 | + byte[] data = pkt.getData(); |
| 229 | + DatagramPacket sendpack = new DatagramPacket(data, data.length, destIpAddr, destPort); |
| 230 | + sock.send(sendpack); |
| 231 | + |
| 232 | + byte[] rece = new byte[bufSize]; |
| 233 | + |
| 234 | + DatagramPacket recepack = new DatagramPacket(rece, 0, rece.length); |
| 235 | + sock.setSoTimeout(timeout); |
| 236 | + sock.receive(recepack); |
| 237 | + |
| 238 | + sock.close(); |
| 239 | + |
| 240 | + return recepack; |
| 241 | + } |
| 242 | + */ |
97 | 243 | } |
0 commit comments