1f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum/*
2f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * Copyright 2017, The Android Open Source Project
3f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum *
4f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * Licensed under the Apache License, Version 2.0 (the "License");
5f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * you may not use this file except in compliance with the License.
6f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * You may obtain a copy of the License at
7f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum *
8f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum *     http://www.apache.org/licenses/LICENSE-2.0
9f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum *
10f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * Unless required by applicable law or agreed to in writing, software
11f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * distributed under the License is distributed on an "AS IS" BASIS,
12f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * See the License for the specific language governing permissions and
14f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum * limitations under the License.
15f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum */
16f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
17f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumpackage com.android.commands.lowpan;
18f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
19f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.ILowpanInterface;
20f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanBeaconInfo;
21f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanCredential;
22f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanEnergyScanResult;
23f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanException;
24f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanIdentity;
25f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanInterface;
26f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanManager;
27f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanProvision;
28f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.net.lowpan.LowpanScanner;
2941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaumimport android.net.LinkAddress;
30f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.os.RemoteException;
31f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.os.ServiceSpecificException;
32f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport android.util.AndroidRuntimeException;
33f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport com.android.internal.os.BaseCommand;
34f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport com.android.internal.util.HexDump;
35f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport java.io.PrintStream;
36f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport java.util.HashMap;
37f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport java.util.Map;
38f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport java.util.concurrent.Semaphore;
39f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumimport java.util.concurrent.TimeUnit;
40f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
41f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaumpublic class LowpanCtl extends BaseCommand {
42f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private LowpanManager mLowpanManager;
43f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private LowpanInterface mLowpanInterface;
44f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private ILowpanInterface mILowpanInterface;
45f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private String mLowpanInterfaceName;
46f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
47f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    /**
48f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum     * Command-line entry point.
49f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum     *
50f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum     * @param args The command-line arguments
51f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum     */
52f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    public static void main(String[] args) {
53f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        new LowpanCtl().run(args);
54f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
55f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
56f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    @Override
57f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    public void onShowUsage(PrintStream out) {
58f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        out.println(
59f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                "usage: lowpanctl [options] [subcommand] [subcommand-options]\n"
6041641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "options:\n"
6141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       -I / --interface <iface-name> ..... Interface Name\n"
6241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "subcommands:\n"
63f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "       lowpanctl status\n"
64f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "       lowpanctl form\n"
65f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "       lowpanctl join\n"
6641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       lowpanctl attach\n"
67f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "       lowpanctl leave\n"
6841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       lowpanctl enable\n"
6941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       lowpanctl disable\n"
7041641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       lowpanctl show-credential\n"
71f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "       lowpanctl scan\n"
72f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "       lowpanctl reset\n"
73f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "       lowpanctl list\n"
7441641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "\n"
7541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "usage: lowpanctl [options] join/form/attach [network-name]\n"
7641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "subcommand-options:\n"
7741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       --name <network-name> ............. Network Name\n"
7841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       -p / --panid <panid> .............. PANID\n"
7941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       -c / --channel <channel> .......... Channel Index\n"
8041641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       -x / --xpanid <xpanid> ............ XPANID\n"
8141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       -k / --master-key <master-key> .... Master Key\n"
8241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       --master-key-index <key-index> .... Key Index\n"
8341641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "\n"
8441641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "usage: lowpanctl [options] show-credential\n"
8541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "subcommand-options:\n"
8641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                        + "       -r / --raw ........................ Print only key contents\n"
87f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        + "\n");
8841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
89f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
90f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
91f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private class CommandErrorException extends AndroidRuntimeException {
92f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        public CommandErrorException(String desc) {
93f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            super(desc);
94f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
95f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
96f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
97f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void throwCommandError(String desc) {
98f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        throw new CommandErrorException(desc);
99f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
100f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
101f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private LowpanInterface getLowpanInterface() {
102f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (mLowpanInterface == null) {
103f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            if (mLowpanInterfaceName == null) {
104f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                String interfaceArray[] = mLowpanManager.getInterfaceList();
105f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                if (interfaceArray.length != 0) {
106f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    mLowpanInterfaceName = interfaceArray[0];
107f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else {
108f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    throwCommandError("No LoWPAN interfaces are present");
109f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                }
110f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
111f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            mLowpanInterface = mLowpanManager.getInterface(mLowpanInterfaceName);
112f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
113f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            if (mLowpanInterface == null) {
114f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                throwCommandError("Unknown LoWPAN interface \"" + mLowpanInterfaceName + "\"");
115f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
116f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
117f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        return mLowpanInterface;
118f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
119f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
120f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private ILowpanInterface getILowpanInterface() {
121f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (mILowpanInterface == null) {
122f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            mILowpanInterface = getLowpanInterface().getService();
123f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
124f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        return mILowpanInterface;
125f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
126f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
127f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    @Override
128f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    public void onRun() throws Exception {
129f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        mLowpanManager = LowpanManager.getManager();
130f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
131f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (mLowpanManager == null) {
132f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            System.err.println(NO_SYSTEM_ERROR_CODE);
133f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            throwCommandError("Can't connect to LoWPAN service; is the service running?");
134f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
135f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
136f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        try {
137f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            String op;
138f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            while ((op = nextArgRequired()) != null) {
139f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                if (op.equals("-I") || op.equals("--interface")) {
140f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    mLowpanInterfaceName = nextArgRequired();
141f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.startsWith("-")) {
142f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    throwCommandError("Unrecognized argument \"" + op + "\"");
143f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("status") || op.equals("stat")) {
144f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runStatus();
145f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
146f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("scan") || op.equals("netscan") || op.equals("ns")) {
147f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runNetScan();
148f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
14941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                } else if (op.equals("attach")) {
150f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runAttach();
151f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
15241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                } else if (op.equals("enable")) {
15341641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                    runEnable();
15441641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                    break;
15541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                } else if (op.equals("disable")) {
15641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                    runDisable();
15741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                    break;
15841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                } else if (op.equals("show-credential")) {
15941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                    runShowCredential();
160f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
161f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("join")) {
162f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runJoin();
163f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
164f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("form")) {
165f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runForm();
166f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
167f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("leave")) {
168f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runLeave();
169f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
170f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("energyscan") || op.equals("energy") || op.equals("es")) {
171f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runEnergyScan();
172f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
173f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("list") || op.equals("ls")) {
174f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runListInterfaces();
175f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
176f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else if (op.equals("reset")) {
177f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    runReset();
178f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
179f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                } else {
180f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    showError("Error: unknown command '" + op + "'");
181f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    break;
182f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                }
183f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
184f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        } catch (ServiceSpecificException x) {
185f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            System.out.println(
186f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    "ServiceSpecificException: " + x.errorCode + ": " + x.getLocalizedMessage());
187f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        } catch (CommandErrorException x) {
188f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            System.out.println("error: " + x.getLocalizedMessage());
189f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
190f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
191f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
192f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runReset() throws LowpanException {
193f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        getLowpanInterface().reset();
194f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
195f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
19641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum    private void runEnable() throws LowpanException {
19741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        getLowpanInterface().setEnabled(true);
19841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum    }
19941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
20041641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum    private void runDisable() throws LowpanException {
20141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        getLowpanInterface().setEnabled(false);
20241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum    }
20341641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
204f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private LowpanProvision getProvisionFromArgs(boolean credentialRequired) {
205f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanProvision.Builder builder = new LowpanProvision.Builder();
206f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        Map<String, Object> properties = new HashMap();
207f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanIdentity.Builder identityBuilder = new LowpanIdentity.Builder();
208f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanCredential credential = null;
209f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        String arg;
210f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        byte[] masterKey = null;
211f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        int masterKeyIndex = 0;
212f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        boolean hasName = false;
213f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
214f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        while ((arg = nextArg()) != null) {
215f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            if (arg.equals("--name")) {
216f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                identityBuilder.setName(nextArgRequired());
217f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                hasName = true;
218f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else if (arg.equals("-p") || arg.equals("--panid")) {
219f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                identityBuilder.setPanid(Integer.decode(nextArgRequired()));
220f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else if (arg.equals("-c") || arg.equals("--channel")) {
221f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                identityBuilder.setChannel(Integer.decode(nextArgRequired()));
222f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else if (arg.equals("-x") || arg.equals("--xpanid")) {
223f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                identityBuilder.setXpanid(HexDump.hexStringToByteArray(nextArgRequired()));
224f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else if (arg.equals("-k") || arg.equals("--master-key")) {
225f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                masterKey = HexDump.hexStringToByteArray(nextArgRequired());
226f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else if (arg.equals("--master-key-index")) {
227f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                masterKeyIndex = Integer.decode(nextArgRequired());
22841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            } else if (arg.equals("--help")) {
22941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                throwCommandError("");
230f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else if (arg.startsWith("-") || hasName) {
231f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                throwCommandError("Unrecognized argument \"" + arg + "\"");
232f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else {
233f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                // This is the network name
234f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                identityBuilder.setName(arg);
235f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                hasName = true;
236f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
237f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
238f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
239f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (credential == null && masterKey != null) {
240f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            if (masterKeyIndex == 0) {
241f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                credential = LowpanCredential.createMasterKey(masterKey);
242f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else {
243f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                credential = LowpanCredential.createMasterKey(masterKey, masterKeyIndex);
244f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
245f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
246f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
247f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (credential != null) {
248f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            builder.setLowpanCredential(credential);
249f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        } else if (credentialRequired) {
250f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            throwCommandError("No credential (like a master key) was specified!");
251f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
252f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
253f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        return builder.setLowpanIdentity(identityBuilder.build()).build();
254f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
255f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
256f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runAttach() throws LowpanException {
257f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanProvision provision = getProvisionFromArgs(true);
258f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
259f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        System.out.println(
260f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                "Attaching to " + provision.getLowpanIdentity() + " with provided credential");
261f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
262f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        getLowpanInterface().attach(provision);
263f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
264f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        System.out.println("Attached.");
265f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
266f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
267f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runLeave() throws LowpanException {
268f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        getLowpanInterface().leave();
269f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
270f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
271f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runJoin() throws LowpanException {
272f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanProvision provision = getProvisionFromArgs(true);
273f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
274f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        System.out.println(
275f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                "Joining " + provision.getLowpanIdentity() + " with provided credential");
276f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
277f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        getLowpanInterface().join(provision);
278f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
279f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        System.out.println("Joined.");
280f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
281f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
282f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runForm() throws LowpanException {
283f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanProvision provision = getProvisionFromArgs(false);
284f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
285f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (provision.getLowpanCredential() != null) {
286f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            System.out.println(
287f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    "Forming "
28841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                            + provision.getLowpanIdentity()
289f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                            + " with provided credential");
290f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        } else {
29141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            System.out.println("Forming " + provision.getLowpanIdentity());
292f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
293f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
294f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        getLowpanInterface().form(provision);
295f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
296f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        System.out.println("Formed.");
297f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
298f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
29941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum    private void runStatus() throws LowpanException, RemoteException {
30041641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        LowpanInterface iface = getLowpanInterface();
30141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        StringBuffer sb = new StringBuffer();
30241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
30341641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        sb.append(iface.getName())
30441641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                .append("\t")
30541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                .append(iface.getState() + " (" + iface.getRole() + ")");
30641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
30741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        if (iface.isUp()) {
30841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            sb.append(" UP");
309f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
310f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
31141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        if (iface.isConnected()) {
31241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            sb.append(" CONNECTED");
313f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
314f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
31541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        if (iface.isCommissioned()) {
31641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            sb.append(" COMMISSIONED");
31741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        }
31841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
31941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        sb
32041641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            .append("\n\t")
32141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            .append(getLowpanInterface().getLowpanIdentity());
32241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
32341641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        for (LinkAddress addr : iface.getLinkAddresses()) {
32441641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            sb.append("\n\t").append(addr);
32541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        }
32641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
32741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        sb.append("\n");
32841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        System.out.println(sb.toString());
329f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
330f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
33141641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum    private void runShowCredential() throws LowpanException, RemoteException {
33241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        LowpanInterface iface = getLowpanInterface();
33341641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        boolean raw = false;
33441641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        String arg;
33541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        while ((arg = nextArg()) != null) {
33641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            if (arg.equals("--raw") || arg.equals("-r")) {
33741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                raw = true;
33841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            } else {
33941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                throwCommandError("Unrecognized argument \"" + arg + "\"");
340f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
341f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
34241641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum
34341641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        LowpanCredential credential = iface.getLowpanCredential();
34441641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        if (raw) {
34541641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            System.out.println(HexDump.toHexString(credential.getMasterKey()));
34641641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        } else {
34741641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum            System.out.println(
34841641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum                iface.getName() + "\t" + credential.toSensitiveString());
34941641f3e0d7ebccbb18ef1e03898688b50ae3e30Robert Quattlebaum        }
350f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
351f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
352f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runListInterfaces() {
353f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        for (String name : mLowpanManager.getInterfaceList()) {
354f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            System.out.println(name);
355f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
356f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
357f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
358f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runNetScan() throws LowpanException, InterruptedException {
359f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanScanner scanner = getLowpanInterface().createScanner();
360f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        String arg;
361f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
362f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        while ((arg = nextArg()) != null) {
363f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            if (arg.equals("-c") || arg.equals("--channel")) {
364f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                scanner.addChannel(Integer.decode(nextArgRequired()));
365f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else {
366f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                throwCommandError("Unrecognized argument \"" + arg + "\"");
367f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
368f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
369f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
370f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        Semaphore semaphore = new Semaphore(1);
371f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
372f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        scanner.setCallback(
373f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                new LowpanScanner.Callback() {
374f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    @Override
375f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    public void onNetScanBeacon(LowpanBeaconInfo beacon) {
376f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        System.out.println(beacon.toString());
377f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    }
378f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
379f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    @Override
380f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    public void onScanFinished() {
381f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        semaphore.release();
382f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    }
383f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                });
384f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
385f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        semaphore.acquire();
386f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        scanner.startNetScan();
387f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
388f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        // Wait for our scan to complete.
389f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (semaphore.tryAcquire(1, 60L, TimeUnit.SECONDS)) {
390f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            semaphore.release();
391f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        } else {
392f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            throwCommandError("Timeout while waiting for scan to complete.");
393f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
394f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
395f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
396f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    private void runEnergyScan() throws LowpanException, InterruptedException {
397f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        LowpanScanner scanner = getLowpanInterface().createScanner();
398f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        String arg;
399f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
400f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        while ((arg = nextArg()) != null) {
401f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            if (arg.equals("-c") || arg.equals("--channel")) {
402f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                scanner.addChannel(Integer.decode(nextArgRequired()));
403f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            } else {
404f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                throwCommandError("Unrecognized argument \"" + arg + "\"");
405f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            }
406f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
407f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
408f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        Semaphore semaphore = new Semaphore(1);
409f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
410f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        scanner.setCallback(
411f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                new LowpanScanner.Callback() {
412f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    @Override
413f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    public void onEnergyScanResult(LowpanEnergyScanResult result) {
414f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        System.out.println(result.toString());
415f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    }
416f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
417f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    @Override
418f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    public void onScanFinished() {
419f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                        semaphore.release();
420f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                    }
421f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum                });
422f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
423f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        semaphore.acquire();
424f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        scanner.startEnergyScan();
425f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum
426f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        // Wait for our scan to complete.
427f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        if (semaphore.tryAcquire(1, 60L, TimeUnit.SECONDS)) {
428f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            semaphore.release();
429f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        } else {
430f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum            throwCommandError("Timeout while waiting for scan to complete.");
431f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum        }
432f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum    }
433f15236e9c6adc5f69be5152bc61fe19bc975c222Robert Quattlebaum}
434