diff options
Diffstat (limited to 'mac80211/ti-utils/plt.c')
-rw-r--r-- | mac80211/ti-utils/plt.c | 723 |
1 files changed, 723 insertions, 0 deletions
diff --git a/mac80211/ti-utils/plt.c b/mac80211/ti-utils/plt.c new file mode 100644 index 0000000..96153d4 --- /dev/null +++ b/mac80211/ti-utils/plt.c @@ -0,0 +1,723 @@ +/* + * PLT utility for wireless chip supported by TI's driver wl12xx + * + * See README and COPYING for more details. + */ + +#include <sys/ioctl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdbool.h> + +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <netlink/msg.h> +#include <netlink/attr.h> +#include <linux/wireless.h> +#include "nl80211.h" + +#include "calibrator.h" +#include "plt.h" +#include "ini.h" +#include "nvs.h" + +SECTION(plt); + +static void str2mac(unsigned char *pmac, char *pch) +{ + int i; + + for (i = 0; i < MAC_ADDR_LEN; i++) { + pmac[i] = (unsigned char)strtoul(pch, &pch, 16); + pch++; + } +} + +static int plt_power_mode(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + unsigned int pmode; + + if (argc != 1) { + fprintf(stderr, "%s> Missing arguments\n", __func__); + return 2; + } + + if (strcmp(argv[0], "on") == 0) { + pmode = 1; + } else if (strcmp(argv[0], "off") == 0) { + pmode = 0; + } else { + fprintf(stderr, "%s> Invalid parameter\n", __func__); + return 2; + } + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_SET_PLT_MODE); + NLA_PUT_U32(msg, WL1271_TM_ATTR_PLT_MODE, pmode); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, power_mode, "<on|off>", + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_power_mode, + "Set PLT power mode\n"); + +static int plt_tune_channel(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_cal_channel_tune prms; + + if (argc < 1 || argc > 2) { + return 1; + } + + prms.test.id = TEST_CMD_CHANNEL_TUNE; + prms.band = (unsigned char)atoi(argv[0]); + prms.channel = (unsigned char)atoi(argv[1]); + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "fail to nla_nest_start()\n"); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, + sizeof(struct wl1271_cmd_cal_channel_tune), + &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, tune_channel, "<band> <channel>", + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tune_channel, + "Set band and channel for PLT\n"); + +static int plt_ref_point(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_cal_update_ref_point prms; + + if (argc < 1 || argc > 3){ + return 1; + } + + prms.test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT; + prms.ref_detector = atoi(argv[0]); + prms.ref_power = atoi(argv[1]); + prms.sub_band = atoi(argv[2]); + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "fail to nla_nest_start()\n"); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, ref_point, "<voltage> <power> <subband>", + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_ref_point, + "Set reference point for PLT\n"); + +static int calib_valid_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *td[WL1271_TM_ATTR_MAX + 1]; + struct wl1271_cmd_cal_p2g *prms; +#if 0 + int i; unsigned char *pc; +#endif + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_TESTDATA]) { + fprintf(stderr, "no data!\n"); + return NL_SKIP; + } + + nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]), + nla_len(tb[NL80211_ATTR_TESTDATA]), NULL); + + prms = (struct wl1271_cmd_cal_p2g *)nla_data(td[WL1271_TM_ATTR_DATA]); + + if (prms->radio_status) { + fprintf(stderr, "Fail to calibrate ith radio status (%d)\n", + (signed short)prms->radio_status); + return 2; + } +#if 0 + printf("%s> id %04x status %04x\ntest id %02x ver %08x len %04x=%d\n", + __func__, + prms->header.id, prms->header.status, prms->test.id, + prms->ver, prms->len, prms->len); + + pc = (unsigned char *)prms->buf; + printf("++++++++++++++++++++++++\n"); + for (i = 0; i < prms->len; i++) { + if (i%0xf == 0) + printf("\n"); + + printf("%02x ", *(unsigned char *)pc); + pc += 1; + } + printf("++++++++++++++++++++++++\n"); +#endif + if (prepare_nvs_file(prms, arg)) { + fprintf(stderr, "Fail to prepare calibrated NVS file\n"); + return 2; + } +#if 0 + printf("\n\tThe NVS file (%s) is ready\n\tCopy it to %s and " + "reboot the system\n\n", + NEW_NVS_NAME, CURRENT_NVS_NAME); +#endif + return NL_SKIP; +} + +static int plt_tx_bip(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_cal_p2g prms; + int i; + char nvs_path[PATH_MAX]; + + if (argc < 8) { + fprintf(stderr, "%s> Missing arguments\n", __func__); + return 2; + } + + if (argc > 8) { + strncpy(nvs_path, argv[8], strlen(argv[8])); + } else { + nvs_path[0] = '\0'; + } + + memset(&prms, 0, sizeof(struct wl1271_cmd_cal_p2g)); + + prms.test.id = TEST_CMD_P2G_CAL; + for (i = 0; i < 8; i++) { + prms.sub_band_mask |= (atoi(argv[i]) & 0x1)<<i; + } + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "fail to nla_nest_start()\n"); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + NLA_PUT_U8(msg, WL1271_TM_ATTR_ANSWER, 1); + + nla_nest_end(msg, key); + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, calib_valid_handler, nvs_path); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, tx_bip, + "<0|1> <0|1> <0|1> <0|1> <0|1> <0|1> <0|1> <0|1> [<nvs file>]", + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_bip, + "Do calibrate\n"); + +static int plt_tx_tone(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_cal_tx_tone prms; + + if (argc < 2) { + fprintf(stderr, "%s> Missing arguments\n", __func__); + return 2; + } + + memset(&prms, 0, sizeof(struct wl1271_cmd_cal_tx_tone)); + + prms.test.id = TEST_CMD_TELEC; + prms.power = atoi(argv[0]); + prms.tone_type = atoi(argv[1]); + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "fail to nla_nest_start()\n"); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, tx_tone, "<power> <tone type>", + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_tone, + "Do command tx_tone to transmit a tone\n"); + +static int plt_tx_cont(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_pkt_params prms = { + .src_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + }; + + if (argc != 15) { + return 1; + } +#if 0 + printf("%s> delay (%d) rate (%08x) size (%d) amount (%d) power (%d) " + "seed (%d) pkt_mode (%d) DCF (%d) GI (%d) preamble (%d) type " + "(%d) scramble (%d) CLPC (%d), SeqNbrMode (%d) DestMAC (%s)\n", + __func__, + atoi(argv[0]), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), + atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), atoi(argv[7]), + atoi(argv[8]), atoi(argv[9]), atoi(argv[10]), atoi(argv[11]), + atoi(argv[12]), atoi(argv[13]), argv[14] + ); +#endif + memset((void *)&prms, 0, sizeof(struct wl1271_cmd_pkt_params)); + + prms.test.id = TEST_CMD_FCC; + prms.delay = atoi(argv[0]); + prms.rate = atoi(argv[1]); + prms.size = (unsigned short)atoi(argv[2]); + prms.amount = (unsigned short)atoi(argv[3]); + prms.power = atoi(argv[4]); + prms.seed = (unsigned short)atoi(argv[5]); + prms.pkt_mode = (unsigned char)atoi(argv[6]); + prms.dcf_enable = (unsigned char)atoi(argv[7]); + prms.g_interval = (unsigned char)atoi(argv[8]); + prms.preamble = (unsigned char)atoi(argv[9]); + prms.type = (unsigned char)atoi(argv[10]); + prms.scramble = (unsigned char)atoi(argv[11]); + prms.clpc_enable = (unsigned char)atoi(argv[12]); + prms.seq_nbr_mode = (unsigned char)atoi(argv[13]); + str2mac(prms.dst_mac, argv[14]); + + if (get_mac_addr(0, prms.src_mac)) { + fprintf(stderr, "fail to get MAC addr\n"); + } + + printf("%02X:%02X:%02X:%02X:%02X:%02X\n", + prms.src_mac[0], prms.src_mac[1], prms.src_mac[2], + prms.src_mac[3], prms.src_mac[4], prms.src_mac[5]); + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "fail to nla_nest_start()\n"); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, tx_cont, "<delay> <rate> <size> <amount> <power>\n\t\t<seed> " + "<pkt mode> <DC on/off> <gi> <preamble>\n\t\t<type> <scramble> " + "<clpc> <seq nbr mode> <dest mac>", + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_cont, + "Start Tx Cont\n"); + +static int plt_tx_stop(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_pkt_params prms; + + prms.test.id = TEST_CMD_STOP_TX; + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "fail to nla_nest_start()\n"); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, tx_stop, NULL, + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_stop, + "Stop Tx Cont\n"); + +static int plt_start_rx_statcs(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_pkt_params prms; + + prms.test.id = TEST_CMD_RX_STAT_START; + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, start_rx_statcs, NULL, + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_start_rx_statcs, + "Start Rx statistics collection\n"); + +static int plt_stop_rx_statcs(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_pkt_params prms; + + prms.test.id = TEST_CMD_RX_STAT_STOP; + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, stop_rx_statcs, NULL, + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_stop_rx_statcs, + "Stop Rx statistics collection\n"); + +static int plt_reset_rx_statcs(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_cmd_pkt_params prms; + + prms.test.id = TEST_CMD_RX_STAT_RESET; + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + + nla_nest_end(msg, key); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, reset_rx_statcs, NULL, + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_reset_rx_statcs, + "Reset Rx statistics collection\n"); + +static int display_rx_statcs(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *td[WL1271_TM_ATTR_MAX + 1]; + struct wl1271_radio_rx_statcs *prms; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_TESTDATA]) { + fprintf(stderr, "no data!\n"); + return NL_SKIP; + } + + nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]), + nla_len(tb[NL80211_ATTR_TESTDATA]), NULL); + + prms = + (struct wl1271_radio_rx_statcs *) + nla_data(td[WL1271_TM_ATTR_DATA]); + + printf("\n\tTotal number of pkts\t- %d\n\tAccepted pkts\t\t- %d\n\t" + "FCS error pkts\t\t- %d\n\tAddress mismatch pkts\t- %d\n\t" + "Average SNR\t\t- % d dBm\n\tAverage RSSI\t\t- % d dBm\n\n", + prms->base_pkt_id, prms->rx_path_statcs.nbr_rx_valid_pkts, + prms->rx_path_statcs.nbr_rx_fcs_err_pkts, + prms->rx_path_statcs.nbr_rx_plcp_err_pkts, + (signed short)prms->rx_path_statcs.ave_snr/8, + (signed short)prms->rx_path_statcs.ave_rssi/8); + + return NL_SKIP; +} + +static int plt_get_rx_statcs(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + struct nlattr *key; + struct wl1271_radio_rx_statcs prms; + + prms.test.id = TEST_CMD_RX_STAT_GET; + + key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); + if (!key) { + fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__); + return 1; + } + + NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST); + NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms); + NLA_PUT_U8(msg, WL1271_TM_ATTR_ANSWER, 1); + + nla_nest_end(msg, key); + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, display_rx_statcs, NULL); + + /* Important: needed gap between tx_start and tx_get */ + sleep(2); + + return 0; + +nla_put_failure: + fprintf(stderr, "%s> building message failed\n", __func__); + return 2; +} + +COMMAND(plt, get_rx_statcs, NULL, + NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_get_rx_statcs, + "Get Rx statistics\n"); + +static int plt_rx_statistics(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + int ret; + + /* power mode on */ + { + char *prms[4] = { "wlan0", "plt", "power_mode", "on" }; + + ret = handle_cmd(state, II_NETDEV, 4, prms); + if (ret < 0) { + fprintf(stderr, "Fail to set PLT power mode on\n"); + return 1; + } + } + + /* start_rx_statcs */ + { + char *prms[3] = { "wlan0", "plt", "start_rx_statcs" }; + + ret = handle_cmd(state, II_NETDEV, 3, prms); + if (ret < 0) { + fprintf(stderr, "Fail to start Rx statistics\n"); + goto fail_out; + } + } + + /* get_rx_statcs */ + { + int err; + char *prms[3] = { "wlan0", "plt", "get_rx_statcs" }; + + err = handle_cmd(state, II_NETDEV, 3, prms); + if (err < 0) { + fprintf(stderr, "Fail to get Rx statistics\n"); + ret = err; + } + } + + + /* stop_rx_statcs */ + { + int err; + char *prms[3] = { "wlan0", "plt", "stop_rx_statcs" }; + + err = handle_cmd(state, II_NETDEV, 3, prms); + if (err < 0) { + fprintf(stderr, "Fail to stop Rx statistics\n"); + ret = err; + } + } + +fail_out: + /* power mode off */ + { + int err; + char *prms[4] = { "wlan0", "plt", "power_mode", "off"}; + + err = handle_cmd(state, II_NETDEV, 4, prms); + if (err < 0) { + fprintf(stderr, "Fail to set PLT power mode on\n"); + return 1; + } + } + + if (ret < 0) { + return 1; + } + + return 0; +} + +COMMAND(plt, rx_statistics, NULL, 0, 0, CIB_NONE, plt_rx_statistics, + "Get Rx statistics\n"); + +static int plt_calibrate(struct nl80211_state *state, struct nl_cb *cb, + struct nl_msg *msg, int argc, char **argv) +{ + int ret = 0, err; + int single_dual = 0; + + if (argc > 2 && (strncmp(argv[2], "dual", 4) == 0)) { + single_dual = 1; /* going for dual band calibration */ + } else { + single_dual = 0; /* going for single band calibration */ + } + + /* power mode on */ + { + char *pm_on[4] = { "wlan0", "plt", "power_mode", "on" }; + + err = handle_cmd(state, II_NETDEV, 4, pm_on); + if (err < 0) { + fprintf(stderr, "Fail to set PLT power mode on\n"); + ret = err; + goto fail_out_final; + } + } + + /* tune channel */ + { + char *pm_on[5] = { + "wlan0", "plt", "tune_channel", "0", "7" + }; + + err = handle_cmd(state, II_NETDEV, 5, pm_on); + if (err < 0) { + fprintf(stderr, "Fail to tune channel\n"); + ret = err; + goto fail_out; + } + } + + /* calibrate it */ + { + char *prms[11] = { + "wlan0", "plt", "tx_bip", "1", "0", "0", "0", + "0", "0", "0", "0" + }; + + /* set flags in case of dual band */ + if (single_dual) { + prms[4] = prms[5] = prms[6] = prms[7] = prms[8] = + prms[9] = prms[10] = "1"; + } + + err = handle_cmd(state, II_NETDEV, 11, prms); + if (err < 0) { + fprintf(stderr, "Fail to calibrate\n"); + ret = err; + } + } + +fail_out: + /* power mode off */ + { + char *prms[4] = { "wlan0", "plt", "power_mode", "off"}; + + err = handle_cmd(state, II_NETDEV, 4, prms); + if (err < 0) { + fprintf(stderr, "Fail to set PLT power mode on\n"); + ret = err; + } + } + +fail_out_final: + if (ret < 0) { + return 1; + } + + return 0; +} + +COMMAND(plt, calibrate, "[<single|dual>]", 0, 0, CIB_NONE, + plt_calibrate, "Do calibrate for single or dual band chip\n"); |