blob: ecd6bc4cb27292043e991f773d72ab9b19155828 [file] [log] [blame] [edit]
/*
* Copyright (c) 2011-2012 Qualcomm Atheros Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <net/if.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include "athtestcmd.h"
#include "libtcmd.h"
#include "testcmd.h"
#include "sinit_eep.h"
#include "sinit_common.h"
const char *progname;
const char commands[] = "commands:\n"
"--tx <sine/frame/tx99/tx100/off>\n"
"--txfreq <Tx channel or freq(default 2412)>\n"
"--txrate <rate index>\n"
"--txpwr <frame/tx99/tx100: 0-30dBm,0.5dBm resolution; sine: 0-60, PCDAC vaule>\n"
"--txantenna <1/2/0 (auto)>\n"
"--txpktsz <pkt size, [32-1500](default 1500)>\n"
"--txpattern <tx data pattern, 0: all zeros; 1: all ones;"
" 2: repeating 10; 3: PN7; 4: PN9; 5: PN15\n"
"--ani (Enable ANI. The ANI is disabled if this option is not specified)\n"
"--scrambleroff (Disable scrambler. The scrambler is enabled by default)\n"
"--aifsn <AIFS slots num,[0-252](Used only under '--tx frame' mode)>\n"
"--shortguard (use short guard)\n"
"--mode <ht40plus/ht40minus/ht20>\n"
"--setlongpreamble <1/0>\n"
"--numpackets <number of packets to send 0-65535>\n"
"--tx sine --txfreq <Tx channel or freq(default 2412)>\n"
"--rx <promis/filter/report>\n"
"--rxfreq <Rx channel or freq(default 2412)>\n"
"--rxantenna <1/2/0 (auto)>\n"
"--mode <ht40plus/ht40minus>\n"
"--pm <wakeup/sleep/deepsleep>\n"
"--setmac <mac addr like 00:03:7f:be:ef:11>\n"
"--getmac\n"
"--SetAntSwitchTable <table1 in decimal value>"
" <table2 in decimal value> (Set table1=0 and table2=0 will"
" restore the default AntSwitchTable)\n"
"--efusedump --start <start address> --end <end address>\n"
"--efusewrite --start <start address> --data <data> (could be one or multiple data in quotation marks)\n"
"--otpwrite --data (could be one or multiple data in quotation marks)\n"
"--otpdump\n";
#define A_ERR(ret, args...) printf(args); exit(ret);
#define A_FREQ_MIN 4920
#define A_FREQ_MAX 5825
#define A_CHAN0_FREQ 5000
#define A_CHAN_MAX ((A_FREQ_MAX - A_CHAN0_FREQ)/5)
#define BG_FREQ_MIN 2412
#define BG_FREQ_MAX 2484
#define BG_CHAN0_FREQ 2407
#define BG_CHAN_MIN ((BG_FREQ_MIN - BG_CHAN0_FREQ)/5)
#define BG_CHAN_MAX 14 /* corresponding to 2484 MHz */
#define A_20MHZ_BAND_FREQ_MAX 5000
#define INVALID_FREQ 0
#define A_OK 0
#define ATH6KL_INTERFACE "wlan0"
#define A_RATE_NUM 28
#define G_RATE_NUM 28
#define RATE_STR_LEN 20
#define VENUS_OTP_SIZE 512
typedef const char RATE_STR[RATE_STR_LEN];
const RATE_STR bgRateStrTbl[G_RATE_NUM] = {
{"1 Mb"},
{"2 Mb"},
{"5.5 Mb"},
{"11 Mb"},
{"6 Mb"},
{"9 Mb"},
{"12 Mb"},
{"18 Mb"},
{"24 Mb"},
{"36 Mb"},
{"48 Mb"},
{"54 Mb"},
{"HT20 MCS0 6.5 Mb"},
{"HT20 MCS1 13 Mb"},
{"HT20 MCS2 19.5 Mb"},
{"HT20 MCS3 26 Mb"},
{"HT20 MCS4 39 Mb"},
{"HT20 MCS5 52 Mb"},
{"HT20 MCS6 58.5 Mb"},
{"HT20 MCS7 65 Mb"},
{"HT40 MCS0 13.5 Mb"},
{"HT40 MCS1 27.0 Mb"},
{"HT40 MCS2 40.5 Mb"},
{"HT40 MCS3 54 Mb"},
{"HT40 MCS4 81 Mb"},
{"HT40 MCS5 108 Mb"},
{"HT40 MCS6 121.5 Mb"},
{"HT40 MCS7 135 Mb"}
};
#if !defined(_printf)
#define _printf printf
#endif
#define _NAME_MAX 256
#define _LABEL_MAX 16
typedef struct _calSetup {
double attenDUT2PM_5G;
double attenDUT2PM_2G;
char testflowBinFilename[_NAME_MAX];
char goldenBinFilename[_NAME_MAX];
char outputBinFilename[_NAME_MAX];
char label[_LABEL_MAX];
} _CAL_SETUP;
_CAL_SETUP calSetup = {
19.0,
18.0,
"calTestFlow.bin",
#ifdef ANDROID
"/system/etc/firmware/ath6k/AR6003/hw2.1.1/bdata.bin",
#else
"/lib/firmware/ath6k/AR6003/hw2.1.1/bdata.bin",
#endif
#ifdef ANDROID
"/persist/bdata.bin",
#else
"new_bdata.bin",
#endif
"wbgf10_010_d0001",
};
uint32_t AR6003_EEPROM_SIZE;
uint32_t AR6K_EEPROM_SIZE;
static bool bCalResult;
#define FIRST_WAIT_INTERVAL 2
#define POLLING_INTERVAL 1
#define MAX_WAIT_CYCLE 20
static time_t startTime, endTime;
static void rxReport(void *buf);
static void rx_cb(void *buf, int len);
static uint32_t freqValid(uint32_t val);
static uint16_t wmic_ieee2freq(uint32_t chan);
static void prtRateTbl(uint32_t freq);
static uint32_t rateValid(uint32_t val, uint32_t freq);
static uint32_t antValid(uint32_t val);
static bool txPwrValid(TCMD_CONT_TX * txCmd);
static int ath_ether_aton(const char *orig, uint8_t * eth);
static uint32_t pktSzValid(uint32_t val);
static void updateCALData(_CAL_SETUP *pCalSetup, TC_MSG *pTCMsg);
static bool dumpPSATCharResult2File(TC_MSG *pTCMsg);
static bool isHex(char c) {
return (((c >= '0') && (c <= '9')) ||
((c >= 'A') && (c <= 'F')) ||
((c >= 'a') && (c <= 'f')));
}
static int usage(void)
{
fprintf(stderr, "usage:\n%s [-i device] commands\n", progname);
fprintf(stderr, "%s\n", commands);
prtRateTbl(INVALID_FREQ);
A_ERR(-1, "Incorrect usage");
}
unsigned int cmd = 0;
unsigned int act = 0;
uint16_t data_length = 0;
uint16_t efuse_begin = 0, efuse_end = (VENUS_OTP_SIZE - 1);
static TC_CMDS sTcCmds;
int main(int argc, char **argv)
{
int c, err,i;
char ifname[IFNAMSIZ];
progname = argv[0];
char buf[2048];
bool resp = false;
TCMD_CONT_TX *txCmd = (TCMD_CONT_TX *) buf;
TCMD_CONT_RX *rxCmd = (TCMD_CONT_RX *) buf;
TCMD_PM *pmCmd = (TCMD_PM *) buf;
TCMD_SET_REG *setRegCmd = (TCMD_SET_REG *)buf;
TC_CMDS *tCmds = (TC_CMDS *)buf;
char efuseBuf[VENUS_OTP_SIZE];
char efuseWriteBuf[VENUS_OTP_SIZE];
int bufferLength = sizeof(*txCmd);
txCmd->numPackets = 0;
txCmd->wlanMode = TCMD_WLAN_MODE_NOHT;
txCmd->tpcm = TPC_TX_PWR;
rxCmd->u.para.wlanMode = TCMD_WLAN_MODE_NOHT;
rxCmd->u.para.freq = 2412;
if (argc == 1) {
usage();
}
/* Log The Start time */
startTime = time(NULL);
while (1) {
int option_index = 0;
static struct option long_options[] = {
{"version", 0, NULL, 'v'},
{"interface", 1, NULL, 'i'},
{"tx", 1, NULL, 't'},
{"txfreq", 1, NULL, 'f'},
{"txrate", 1, NULL, 'g'},
{"txpwr", 1, NULL, 'h'},
{"tgtpwr", 0, NULL, 'H'},
{"pcdac", 1, NULL, 'I'},
{"txantenna", 1, NULL, 'j'},
{"txpktsz", 1, NULL, 'z'},
{"txpattern", 1, NULL, 'e'},
{"rx", 1, NULL, 'r'},
{"rxfreq", 1, NULL, 'p'},
{"rxantenna", 1, NULL, 'q'},
{"pm", 1, NULL, 'x'},
{"setmac", 1, NULL, 's'},
{"getmac", 0, NULL, 'C'},
{"ani", 0, NULL, 'a'},
{"scrambleroff", 0, NULL, 'o'},
{"aifsn", 1, NULL, 'u'},
{"SetAntSwitchTable", 1, NULL, 'S'},
{"shortguard", 0, NULL, 'G'},
{"numpackets", 1, NULL, 'n'},
{"mode", 1, NULL, 'M'},
{"setlongpreamble", 1, NULL, 'l'},
{"setreg", 1, NULL, 'R'},
{"regval", 1, NULL, 'V'},
{"flag", 1, NULL, 'F'},
{"writeotp", 0, NULL, 'w'},
{"otpregdmn", 1, NULL, 'E'},
{"efusedump", 0, NULL, 'm'},
{"efusewrite", 0, NULL, 'W'},
{"start", 1, NULL, 'A'},
{"end", 1, NULL, 'L'},
{"data", 1, NULL, 'U'},
{"otpwrite", 0, NULL, 'O'},
{"otpdump", 0, NULL, 'P'},
{"btaddr", 1, NULL, 'B'},
{"therm", 0, NULL, 'c'},
{"selfInit", 0, NULL, TCMD_PSAT_CAL},
{"selfInit_result", 0, NULL, TCMD_PSAT_CAL_RESULT},
{"psat_char", 1, NULL, TCMD_CHAR_PSAT},
{"psat_char_result", 0, NULL, TCMD_CHAR_PSAT_RESULT},
{"sinit", 0, NULL, TCMD_SINIT_WAIT},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "vi:t:f:g:h:HI:r:p:q:x:u:ao:M:A:L:mU:WOP",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'i':
memset(ifname, '\0', 8);
strcpy(ifname, optarg);
break;
case 't':
cmd = TESTMODE_CONT_TX;
txCmd->testCmdId = TCMD_CONT_TX_ID;
if (!strcmp(optarg, "sine")) {
txCmd->mode = TCMD_CONT_TX_SINE;
} else if (!strcmp(optarg, "offset")) {
txCmd->mode = TCMD_CONT_TX_OFFSETTONE;
} else if (!strcmp(optarg, "frame")) {
txCmd->mode = TCMD_CONT_TX_FRAME;
} else if (!strcmp(optarg, "tx99")) {
txCmd->mode = TCMD_CONT_TX_TX99;
} else if (!strcmp(optarg, "tx100")) {
txCmd->mode = TCMD_CONT_TX_TX100;
} else if (!strcmp(optarg, "off")) {
txCmd->mode = TCMD_CONT_TX_OFF;
}else {
cmd = 0;
}
break;
case 'f':
if (TESTMODE_CMDS == cmd) {
uint32_t freq = freqValid(atoi(optarg));
uint8_t freqBin;
// TBD: temporarily borrow the length's high B for freq
if (freq < 4900) {
freqBin = FREQ2FBIN(atoi(optarg), 1);
}
else {
freqBin = FREQ2FBIN(atoi(optarg), 0);
}
tCmds->hdr.u.parm.length &= 0x00ff;
tCmds->hdr.u.parm.length |= (freqBin << 8) & 0xff00;
}
else {
txCmd->freq = freqValid(atoi(optarg));
}
break;
case 'G':
txCmd->shortGuard = 1;
break;
case 'M':
if(cmd == TESTMODE_CONT_TX) {
if (!strcmp(optarg, "ht20")) {
txCmd->wlanMode = TCMD_WLAN_MODE_HT20;
} else if (!strcmp(optarg, "ht40plus")) {
txCmd->wlanMode = TCMD_WLAN_MODE_HT40PLUS;
} else if (!strcmp(optarg, "ht40minus")) {
txCmd->wlanMode = TCMD_WLAN_MODE_HT40MINUS;
}
} else if(cmd == TESTMODE_CONT_RX) {
if (!strcmp(optarg, "ht20")) {
rxCmd->u.para.wlanMode = TCMD_WLAN_MODE_HT20;
} else if (!strcmp(optarg, "ht40plus")) {
rxCmd->u.para.wlanMode = TCMD_WLAN_MODE_HT40PLUS;
} else if (!strcmp(optarg, "ht40minus")) {
rxCmd->u.para.wlanMode = TCMD_WLAN_MODE_HT40MINUS;
}
}
break;
case 'n':
txCmd->numPackets = atoi(optarg);
break;
case 'g':
/* let user input index of rateTable instead of string parse */
txCmd->dataRate = rateValid(atoi(optarg), txCmd->freq);
break;
case 'h':
{
int txPowerAsInt;
/* Get tx power from user. This is given in the form of a number
* that's supposed to be either an integer, or an integer + 0.5
*/
double txPowerIndBm = atof(optarg);
/*
* Check to make sure that the number given is either an integer
* or an integer + 0.5
*/
txPowerAsInt = (int)txPowerIndBm;
if (((txPowerIndBm - (double)txPowerAsInt) == 0) ||
(((txPowerIndBm - (double)txPowerAsInt)) == 0.5) ||
(((txPowerIndBm - (double)txPowerAsInt)) == -0.5)) {
if ((txCmd->mode != TCMD_CONT_TX_SINE) && (txCmd->mode != TCMD_CONT_TX_OFFSETTONE)) {
txCmd->txPwr = txPowerIndBm * 2;
} else {
txCmd->txPwr = txPowerIndBm;
}
} else {
printf("Bad argument to --txpwr, must be in steps of 0.5 dBm\n");
cmd = 0;
}
txCmd->tpcm = TPC_TX_PWR;
}
break;
case 'H':
txCmd->tpcm = TPC_TGT_PWR;
break;
case 'I':
txCmd->tpcm = TPC_FORCED_GAIN;
txCmd->txPwr = atof(optarg);
break;
case 'j':
txCmd->antenna = antValid(atoi(optarg));
break;
case 'z':
txCmd->pktSz = pktSzValid(atoi(optarg));
break;
case 'e':
txCmd->txPattern = atoi(optarg);
break;
case 'r':
cmd = TESTMODE_CONT_RX;
rxCmd->testCmdId = TCMD_CONT_RX_ID;
if (!strcmp(optarg, "promis")) {
rxCmd->act = TCMD_CONT_RX_PROMIS;
printf(" Its cont Rx promis mode \n");
} else if (!strcmp(optarg, "filter")) {
rxCmd->act = TCMD_CONT_RX_FILTER;
printf(" Its cont Rx filter mode \n");
} else if (!strcmp(optarg, "report")) {
printf(" Its cont Rx report mode \n");
rxCmd->act = TCMD_CONT_RX_REPORT;
resp = true;
} else {
cmd = 0;
}
break;
case 'p':
rxCmd->u.para.freq = freqValid(atoi(optarg));
break;
case 'q':
rxCmd->u.para.antenna = antValid(atoi(optarg));
break;
case 'x':
cmd = TESTMODE_PM;
pmCmd->testCmdId = TCMD_PM_ID;
if (!strcmp(optarg, "wakeup")) {
pmCmd->mode = TCMD_PM_WAKEUP;
} else if (!strcmp(optarg, "sleep")) {
pmCmd->mode = TCMD_PM_SLEEP;
} else if (!strcmp(optarg, "deepsleep")) {
pmCmd->mode = TCMD_PM_DEEPSLEEP;
} else {
cmd = 0;
}
break;
case 's':
{
uint8_t mac[ATH_MAC_LEN];
cmd = TESTMODE_CONT_RX;
rxCmd->testCmdId = TCMD_CONT_RX_ID;
rxCmd->act = TCMD_CONT_RX_SETMAC;
if (ath_ether_aton(optarg, mac) != 0) {
printf("Invalid mac address format! \n");
}
memcpy(rxCmd->u.mac.addr, mac, ATH_MAC_LEN);
printf("JLU: tcmd: setmac 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
break;
}
case 'C':
cmd = TESTMODE_CONT_RX;
rxCmd->testCmdId = TCMD_CONT_RX_ID;
act = rxCmd->act = TCMD_CONT_RX_GETMAC;
resp = true;
break;
case 'u':
{
txCmd->aifsn = atoi(optarg) & 0xff;
printf("AIFS:%d\n", txCmd->aifsn);
}
break;
case 'a':
if(cmd == TESTMODE_CONT_TX) {
txCmd->enANI = true;
} else if(cmd == TESTMODE_CONT_RX) {
rxCmd->enANI = true;
}
break;
case 'o':
txCmd->scramblerOff = true;
break;
case 'S':
if (argc < 4)
usage();
cmd = TESTMODE_CONT_RX;
rxCmd->testCmdId = TCMD_CONT_RX_ID;
rxCmd->act = TCMD_CONT_RX_SET_ANT_SWITCH_TABLE;
rxCmd->u.antswitchtable.antswitch1 = strtoul(argv[2], (char **)NULL,0);
rxCmd->u.antswitchtable.antswitch2 = strtoul(argv[3], (char **)NULL,0);
break;
case 'l':
printf("Not supported\n");
return 0;
break;
case 'R':
if (argc < 5) {
printf("usage:athtestcmd -i wlan0 --setreg 0x1234 --regval 0x01 --flag 0\n");
}
cmd = TESTMODE_SETREG;
setRegCmd->testCmdId = TCMD_SET_REG_ID;
setRegCmd->regAddr = strtoul(optarg, (char **)NULL, 0);//atoi(optarg);
break;
case 'V':
setRegCmd->val = strtoul(optarg, (char **)NULL, 0);
break;
case 'F':
setRegCmd->flag = atoi(optarg);
break;
case 'w':
rxCmd->u.mac.otpWriteFlag = 1;
break;
case 'E':
rxCmd->u.mac.regDmn[0] = 0xffff&(strtoul(optarg, (char **)NULL, 0));
rxCmd->u.mac.regDmn[1] = 0xffff&(strtoul(optarg, (char **)NULL, 0)>>16);
break;
case 'B':
{
uint8_t btaddr[ATH_MAC_LEN];
if (ath_ether_aton(optarg, btaddr) != 0) {
printf("Invalid mac address format! \n");
}
memcpy(rxCmd->u.mac.btaddr, btaddr, ATH_MAC_LEN);
printf("JLU: tcmd: setbtaddr 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
btaddr[0], btaddr[1], btaddr[2], btaddr[3], btaddr[4], btaddr[5]);
}
break;
case 'c':
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
{
tCmds->hdr.u.parm.length = 0;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
act = tCmds->hdr.act = TC_CMDS_READTHERMAL;//TC_CMDS_CAL_THERMALVOLT;
resp = true;
}
break;
case 'A':
efuse_begin = atoi(optarg);
break;
case 'L':
efuse_end = atoi(optarg);
break;
case 'U':
{
uint8_t* pucArg = (uint8_t*)optarg;
uint8_t c;
uint8_t strBuf[256];
uint8_t pos = 0;
uint16_t length = 0;
uint32_t data;
/* Sweep string to end */
while (1) {
c = *pucArg++;
if (isHex(c)) {
strBuf[pos++] = c;
} else {
strBuf[pos] = '\0';
pos = 0;
sscanf(((char *)&strBuf), "%x", &data);
efuseWriteBuf[length++] = (data & 0xFF);
/* End of arg string */
if (c == '\0') {
break;
}
}
}
data_length = length;
}
break;
case 'm':
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
act = tCmds->hdr.act = TC_CMDS_EFUSEDUMP;
resp = true;
break;
case 'W':
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
act = tCmds->hdr.act = TC_CMDS_EFUSEWRITE;
resp = true;
break;
case 'O':
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
act = tCmds->hdr.act = TC_CMDS_OTPSTREAMWRITE;
resp = true;
break;
case 'P':
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
act = tCmds->hdr.act = TC_CMDS_OTPDUMP;
resp = true;
break;
case TCMD_PSAT_CAL:
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
tCmds->hdr.u.parm.length = 0;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
tCmds->hdr.act = TC_CMDS_PSAT_CAL;
resp = true;
break;
case TCMD_SINIT_WAIT:
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
tCmds->hdr.u.parm.length = (uint16_t)0;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
tCmds->hdr.act = TC_CMDS_SINIT_WAIT;
resp = true;
break;
case TCMD_PSAT_CAL_RESULT:
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
{
tCmds->hdr.u.parm.length = 0;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
tCmds->hdr.act = TC_CMDS_PSAT_CAL_RESULT;
}
resp = true;
bCalResult = false;
break;
case TCMD_CHAR_PSAT:
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
{
tCmds->hdr.u.parm.length = 0;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
tCmds->hdr.act = TC_CMDS_CHAR_PSAT;
}
// TBD: temporarily borrow the length's lower B for sweep entry
tCmds->hdr.u.parm.length &= 0xff00;
tCmds->hdr.u.parm.length |= (atoi(optarg)) & 0xff;
printf("optarg %s %d\n", optarg, tCmds->hdr.u.parm.length );
break;
case TCMD_CHAR_PSAT_RESULT:
cmd = TESTMODE_CMDS;
tCmds->hdr.testCmdId = TC_CMDS_ID;
{
tCmds->hdr.u.parm.length = NUM_PSAT_CHAR_PARMS;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
tCmds->hdr.act = TC_CMDS_CHAR_PSAT_RESULT;
}
resp = true;
break;
default:
usage();
}
}
if ( cmd == TESTMODE_CMDS )
{
if ( tCmds->hdr.act == TC_CMDS_EFUSEWRITE )
{
int i;
/* Error check */
if (data_length == 0) {
printf("No data to write, exit..\n");
return 0;
} else if ((efuse_begin + data_length + 4) > TC_CMDS_SIZE_MAX) {
printf("Exceed eFuse border: %d, exit..\n", (TC_CMDS_SIZE_MAX - 1));
return 0;
}
/* PRINT */
printf("eFuse data (%d Bytes): ", data_length);
for (i = 0; i < data_length; i++) {
printf("%02X ", efuseWriteBuf[i]);
}
printf("\n");
/* Write address and data length */
tCmds->buf[0] = (efuse_begin & 0xFF);
tCmds->buf[1] = (efuse_begin >> 8) & 0xFF;
tCmds->buf[2] = (data_length & 0xFF);
tCmds->buf[3] = (data_length >> 8) & 0xFF;
/* Copy data to tcmd buffer. The first 4 bytes are the ID and length */
memcpy((void*)&(tCmds->buf[4]), (void*)&(efuseWriteBuf[0]), data_length);
/* Construct eFuse Write */
tCmds->hdr.u.parm.length = (4 + data_length);
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
}
else if ( tCmds->hdr.act == TC_CMDS_OTPSTREAMWRITE )
{
int i;
/* Error check */
if (data_length == 0) {
printf("No data to write, exit..\n");
return 0;
} else if ((data_length + 4) > TC_CMDS_SIZE_MAX) {
printf("Exceed OTP size: %d, exit..\n", data_length);
return 0;
}
/* PRINT */
printf("Write OTP data (%d Bytes): ", data_length);
for (i = 0; i < data_length; i++) {
printf("%02X ", efuseWriteBuf[i]);
}
printf("\n");
/* Copy data to tcmd buffer. The first 4 bytes are the ID and length */
memcpy((void*)&(tCmds->buf[0]), (void*)&(efuseWriteBuf[0]), data_length);
/* Construct eFuse Write */
tCmds->hdr.u.parm.length = data_length;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
}
else if ( tCmds->hdr.act == TC_CMDS_OTPDUMP )
{
tCmds->hdr.u.parm.length = 0;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
}
else if ( tCmds->hdr.act == TC_CMDS_CHAR_PSAT )
{
uint32_t ii = tCmds->hdr.u.parm.length & 0xff;
uint8_t freq= (uint8_t)((tCmds->hdr.u.parm.length >> 8) & 0xff);
tCmds->hdr.u.parm.length = NUM_PSAT_CHAR_PARMS;
tCmds->buf[0] = psatSweepTbl[ii].an_txrf3_rdiv2g;
tCmds->buf[1] = psatSweepTbl[ii].an_txrf3_pdpredist2g;
tCmds->buf[2] = psatSweepTbl[ii].an_rxtx2_mxrgain;
tCmds->buf[3] = psatSweepTbl[ii].an_rxrf_bias1_pwd_ic25mxr2gh;
tCmds->buf[4] = psatSweepTbl[ii].an_bias2_pwd_ic25rxrf;
tCmds->buf[5] = psatSweepTbl[ii].an_bb1_i2v_curr2x;
tCmds->buf[6] = psatSweepTbl[ii].an_txrf3_capdiv2g;
tCmds->buf[7] = freq;
printf("freq %d %d %d %d %d %d %d %d\n", tCmds->buf[7], tCmds->buf[0], tCmds->buf[1], tCmds->buf[2], tCmds->buf[3],tCmds->buf[4], tCmds->buf[5], tCmds->buf[6]);
}
}
/* default bufferLength = sizeof(*txCmd)*/
if ( cmd == TESTMODE_CONT_TX )
{
bufferLength = sizeof(*txCmd);
}
else if ( cmd == TESTMODE_CONT_RX )
{
bufferLength = sizeof(*rxCmd);
}
else if ( cmd == TESTMODE_PM )
{
bufferLength = sizeof(*pmCmd);
}
else if ( cmd == TESTMODE_SETREG)
{
bufferLength = sizeof(*setRegCmd);
}
else if ( cmd == TESTMODE_CMDS )
{
bufferLength = sizeof(*tCmds);
}
printf("Cmd %d length %d respNeeded %d\n",cmd,bufferLength,resp);
err = tcmd_tx_init(ATH6KL_INTERFACE, rx_cb);
if (err)
return err;
if ( (cmd == TESTMODE_CMDS) && (tCmds->hdr.act == TC_CMDS_EFUSEDUMP) )
{
int i, k;
int blkNum;
uint16_t efuseEnd = efuse_end;
uint16_t efuseBegin = efuse_begin;
uint16_t efusePrintAnkor;
uint16_t numPlaceHolder;
/* Input check */
if (efuseEnd > (VENUS_OTP_SIZE - 1)) {
efuseEnd = (VENUS_OTP_SIZE - 1);
}
if (efuseBegin > efuseEnd) {
efuseBegin = efuseEnd;
}
efusePrintAnkor = efuseBegin;
blkNum = ((efuseEnd - efuseBegin) / TC_CMDS_SIZE_MAX) + 1;
/* Request data in several trys */
for (i = 0; i < blkNum; i++) {
tCmds->hdr.testCmdId = TC_CMDS_ID;
tCmds->hdr.act = TC_CMDS_EFUSEDUMP;
tCmds->hdr.u.parm.length = 4;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
tCmds->buf[0] = (efuseBegin & 0xFF);
tCmds->buf[1] = (efuseBegin >> 8) & 0xFF;
tCmds->buf[2] = (efuseEnd & 0xFF);
tCmds->buf[3] = (efuseEnd >> 8) & 0xFF;
/* This field may get polluted so needs a refresh here */
tCmds->hdr.u.parm.bufLen = 4;
if ((err = tcmd_tx(buf, bufferLength /* weak */, resp))) {
fprintf(stderr, "tcmd_tx had error: %s!\n", strerror(-err));
return 0;
}
/* Last block? */
//sTcCmds populated in the callback..
if ((efuseEnd - efuseBegin + 1) < TC_CMDS_SIZE_MAX) {
memcpy((void*)(efuseBuf + efuseBegin), (void*)&(sTcCmds.buf[0]), (efuseEnd - efuseBegin + 1));
} else {
memcpy((void*)(efuseBuf + efuseBegin), (void*)&(sTcCmds.buf[0]), TC_CMDS_SIZE_MAX);
}
/* Adjust the efuseBegin but keep efuseEnd unchanged */
efuseBegin += TC_CMDS_SIZE_MAX;
}
/* Output Dump */
printf("------------------- eFuse Dump ----------------------");
for (i = efusePrintAnkor; i <= efuseEnd; i++) {
/* Cosmetics */
if (i == efusePrintAnkor) {
numPlaceHolder = (efusePrintAnkor & 0x0F);
printf("\n%04X:", (efusePrintAnkor & 0xFFF0));
for (k = 0; k < numPlaceHolder; k++) {
printf(" ");
}
} else if ((i & 0x0F) == 0) {
printf("\n%04X:", i);
}
printf(" %02X", efuseBuf[i]);
}
printf("\n\n");
}
else if ( (cmd == TESTMODE_CMDS) && (tCmds->hdr.act == TC_CMDS_SINIT_WAIT) )
{
if ((err = tcmd_tx(buf, bufferLength /* weak */, resp))) {
fprintf(stderr, "tcmd_tx had error: %s!\n", strerror(-err));
return 0;
}
sleep(FIRST_WAIT_INTERVAL); /* Wait 2s first */
/* Request data in several trys */
for (i = 0; i < MAX_WAIT_CYCLE; i++) {
tCmds->hdr.testCmdId = TC_CMDS_ID;
tCmds->hdr.u.parm.length = (uint16_t)0;
tCmds->hdr.u.parm.version = TC_CMDS_VERSION_TS;
tCmds->hdr.act = TC_CMDS_PSAT_CAL_RESULT;
resp = true;
bCalResult = false;
if ((err = tcmd_tx(buf, bufferLength /* weak */, resp))) {
/*don't let main return bcs the reply may not be ready. Try again.*/
/*fprintf(stderr, "tcmd_tx had error: %s!\n", strerror(-err));*/
/*return 0;*/
}
if (!bCalResult) {
sleep(POLLING_INTERVAL);
printf(".");
} else {
endTime = time(NULL);
printf("Wait time = %ld(s)\n", (endTime - startTime));
break;
}
}
}
else
{
if ((err = tcmd_tx(buf, bufferLength /* weak */, resp))) {
fprintf(stderr, "tcmd_tx had error: %s!\n", strerror(-err));
}
}
return 0;
}
static void rxReport(void *buf)
{
struct TCMD_CONT_RX_REPORT *report = &((TCMD_CONT_RX *) buf)->u.report;
uint32_t pkt = report->totalPkt;
int32_t rssi = report->rssiInDBm;
uint32_t crcError = report->crcErrPkt;
uint32_t secErr = report->secErrPkt;
uint16_t *rateCnt = report->rateCnt;
uint16_t *rateCntShortGuard = report->rateCntShortGuard;
printf
("total pkt %d ; crcError pkt %d ; secErr pkt %d ; average rssi %d\n",
pkt, crcError, secErr,
(int32_t) (pkt ? (rssi / (int32_t) pkt) : 0));
printf("1Mbps %d\n", rateCnt[0]);
printf("2Mbps %d\n", rateCnt[1]);
printf("5.5Mbps %d\n", rateCnt[2]);
printf("11Mbps %d\n", rateCnt[3]);
printf("6Mbps %d\n", rateCnt[4]);
printf("9Mbps %d\n", rateCnt[5]);
printf("12Mbps %d\n", rateCnt[6]);
printf("18Mbps %d\n", rateCnt[7]);
printf("24Mbps %d\n", rateCnt[8]);
printf("36Mbps %d\n", rateCnt[9]);
printf("48Mbps %d\n", rateCnt[10]);
printf("54Mbps %d\n", rateCnt[11]);
printf("\n");
printf("HT20 MCS0 6.5Mbps %d (SGI: %d)\n", rateCnt[12],
rateCntShortGuard[12]);
printf("HT20 MCS1 13Mbps %d (SGI: %d)\n", rateCnt[13],
rateCntShortGuard[13]);
printf("HT20 MCS2 19.5Mbps %d (SGI: %d)\n", rateCnt[14],
rateCntShortGuard[14]);
printf("HT20 MCS3 26Mbps %d (SGI: %d)\n", rateCnt[15],
rateCntShortGuard[15]);
printf("HT20 MCS4 39Mbps %d (SGI: %d)\n", rateCnt[16],
rateCntShortGuard[16]);
printf("HT20 MCS5 52Mbps %d (SGI: %d)\n", rateCnt[17],
rateCntShortGuard[17]);
printf("HT20 MCS6 58.5Mbps %d (SGI: %d)\n", rateCnt[18],
rateCntShortGuard[18]);
printf("HT20 MCS7 65Mbps %d (SGI: %d)\n", rateCnt[19],
rateCntShortGuard[19]);
printf("\n");
printf("HT40 MCS0 13.5Mbps %d (SGI: %d)\n", rateCnt[20],
rateCntShortGuard[20]);
printf("HT40 MCS1 27.0Mbps %d (SGI: %d)\n", rateCnt[21],
rateCntShortGuard[21]);
printf("HT40 MCS2 40.5Mbps %d (SGI: %d)\n", rateCnt[22],
rateCntShortGuard[22]);
printf("HT40 MCS3 54Mbps %d (SGI: %d)\n", rateCnt[23],
rateCntShortGuard[23]);
printf("HT40 MCS4 81Mbps %d (SGI: %d)\n", rateCnt[24],
rateCntShortGuard[24]);
printf("HT40 MCS5 108Mbps %d (SGI: %d)\n", rateCnt[25],
rateCntShortGuard[25]);
printf("HT40 MCS6 121.5Mbps %d (SGI: %d)\n", rateCnt[26],
rateCntShortGuard[26]);
printf("HT40 MCS7 135Mbps %d (SGI: %d)\n", rateCnt[27],
rateCntShortGuard[27]);
}
static void readThermal(void *buf,int len)
{
TC_CMDS *tCmd;
tCmd = (TC_CMDS *)buf;
printf("Length rx cb rcvd %d\n",len);
printf("act %d version %d length %d\n",tCmd->hdr.act,tCmd->hdr.u.parm.version,tCmd->hdr.u.parm.length);
printf("chip thermal value:%d\n", tCmd->buf[0]);
return;
}
static void getMac(void *buf,int len)
{
TC_CMDS *tCmd;
tCmd = (TC_CMDS *)buf;
printf("Length rx cb rcvd %d\n",len);
printf("act %d version %d length %d\n",tCmd->hdr.act,tCmd->hdr.u.parm.version,tCmd->hdr.u.parm.length);
printf("MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", tCmd->buf[0], tCmd->buf[1], tCmd->buf[2], tCmd->buf[3], tCmd->buf[4], tCmd->buf[5]);
return;
}
static void cmdReply(void *buf, int len)
{
TC_CMDS tCmdReply;
TC_MSG *pTCMsg;
uint32_t act;
uint16_t wBytes;
int i=0;
printf("Length rx cb rcvd %d\n",len);
buf = (void*)((uint8_t*)buf + (2 * sizeof(unsigned int)));
uint8_t *reply = (uint8_t*)buf;
tCmdReply.hdr.u.parm.length = *(uint16_t *)&(reply[0]);
tCmdReply.hdr.u.parm.version = (uint8_t)(reply[2]);
act = tCmdReply.hdr.u.parm.version;
pTCMsg = (TC_MSG *)&(tCmdReply.buf[0]);
/* Error Check */
if (tCmdReply.hdr.u.parm.length > (TC_CMDS_SIZE_MAX + 1)) {
printf("Error: Reply lenth=%d, limit=%d\n", tCmdReply.hdr.u.parm.length, TC_CMDS_SIZE_MAX);
return;
} else {
;
}
if (tCmdReply.hdr.u.parm.length > 0) {
memcpy((void*)&(tCmdReply.buf), (void*)((uint8_t*)buf+4), tCmdReply.hdr.u.parm.length);
memcpy((void*)&(sTcCmds.buf[0]), (void*)&(tCmdReply.buf[0]), tCmdReply.hdr.u.parm.length);
sTcCmds.hdr.u.parm.length = tCmdReply.hdr.u.parm.length;
}
switch (act) {
case TC_CMDS_EFUSEDUMP:
printf("eFuse data:\n");
break;
case TC_CMDS_EFUSEWRITE:
printf("(write eFuse data)\n");
wBytes = ((sTcCmds.buf[1] << 8) | sTcCmds.buf[0]);
printf("%d bytes written to eFuse.\n", wBytes);
break;
case TC_CMDS_OTPSTREAMWRITE:
printf("(OTP stream write)\n");
if (sTcCmds.buf[0] == A_OK) {
printf("Write %d bytes to OTP\n", data_length);
} else {
printf("Failed to write OTP\n");
}
break;
case TC_CMDS_OTPDUMP:
printf("OTP Dump\n");
if (sTcCmds.hdr.u.parm.length) {
/* Received bytes are in sTcCmds */
for (i = 0; i < sTcCmds.hdr.u.parm.length; i++) {
printf("%02x ", sTcCmds.buf[i]);
}
printf("\n");
} else {
printf("No valid stream found in OTP!\n");
}
break;
case TC_CMDS_PSAT_CAL:
break;
case TC_CMDS_SINIT_WAIT:
if (TC_MSG_PSAT_CAL_ACK == (TC_MSG_ID)pTCMsg->msgId) {
printf("ACK Received.\n");
}
break;
case TC_CMDS_PSAT_CAL_RESULT:
if (TC_MSG_PSAT_CAL_RESULTS == (TC_MSG_ID)pTCMsg->msgId) {
// update CAL data, read eeprom bin, re-generate eeprom bin
updateCALData(&calSetup, pTCMsg);
bCalResult = true;
}
break;
case TC_CMDS_CHAR_PSAT:
break;
case TC_CMDS_CHAR_PSAT_RESULT:
if (TC_MSG_CHAR_PSAT_RESULTS == (TC_MSG_ID)pTCMsg->msgId) {
dumpPSATCharResult2File(pTCMsg);
}
break;
default:
printf("Invalid action!\n");
break;
}
}
static void rx_cb(void *buf, int len)
{
TCMD_ID tcmd;
if ( cmd == TESTMODE_CMDS )
{
if ( act == TC_CMDS_READTHERMAL )
{
readThermal(buf,len);
}
else
{
cmdReply(buf,len);
}
return;
}
if ( cmd == TESTMODE_CONT_RX )
{
if ( act == TCMD_CONT_RX_GETMAC )
{
getMac(buf, len);
}
}
tcmd = * ((uint32_t *) buf + 1);
switch (tcmd) {
case TCMD_CONT_RX_REPORT:
rxReport(buf);
break;
default:
break;
}
}
static uint32_t freqValid(uint32_t val)
{
do {
if (val <= A_CHAN_MAX) {
uint16_t freq;
if (val < BG_CHAN_MIN)
break;
freq = wmic_ieee2freq(val);
if (INVALID_FREQ == freq)
break;
else
return freq;
}
if ((val == BG_FREQ_MAX) ||
((val < BG_FREQ_MAX) && (val >= BG_FREQ_MIN)
&& !((val - BG_FREQ_MIN) % 5)))
return val;
else if ((val >= A_FREQ_MIN) && (val < A_20MHZ_BAND_FREQ_MAX)
&& !((val - A_FREQ_MIN) % 20))
return val;
else if ((val >= A_20MHZ_BAND_FREQ_MAX) && (val <= A_FREQ_MAX)
&& !((val - A_20MHZ_BAND_FREQ_MAX) % 5))
return val;
} while (false);
A_ERR(-1, "Invalid channel or freq #: %d !\n", val);
return 0;
}
static uint32_t rateValid(uint32_t val, uint32_t freq)
{
if (((freq >= A_FREQ_MIN) && (freq <= A_FREQ_MAX)
&& (val >= A_RATE_NUM)) || ((freq >= BG_FREQ_MIN)
&& (freq <= BG_FREQ_MAX)
&& (val >= G_RATE_NUM))) {
printf("Invalid rate value %d for frequency %d! \n", val, freq);
prtRateTbl(freq);
A_ERR(-1, "Invalid rate value %d for frequency %d! \n", val,
freq);
}
return val;
}
static void prtRateTbl(uint32_t freq)
{
int i;
for (i = 0; i < G_RATE_NUM; i++) {
printf("<rate> %d \t \t %s \n", i, bgRateStrTbl[i]);
}
printf("\n");
}
/*
* converts ieee channel number to frequency
*/
static uint16_t wmic_ieee2freq(uint32_t chan)
{
if (chan == BG_CHAN_MAX) {
return BG_FREQ_MAX;
}
if (chan < BG_CHAN_MAX) { /* 0-13 */
return (BG_CHAN0_FREQ + (chan * 5));
}
if (chan <= A_CHAN_MAX) {
return (A_CHAN0_FREQ + (chan * 5));
} else {
return INVALID_FREQ;
}
}
static uint32_t antValid(uint32_t val)
{
if (val > 2) {
A_ERR(-1,
"Invalid antenna setting! <0: auto; 1/2: ant 1/2>\n");
}
return val;
}
static bool txPwrValid(TCMD_CONT_TX * txCmd)
{
bool rc = false;
if (txCmd->mode == TCMD_CONT_TX_SINE) {
if ((txCmd->txPwr >= 0) && (txCmd->txPwr <= 150))
rc = true;
} else if (txCmd->mode == TCMD_CONT_TX_OFFSETTONE) {
if ((txCmd->txPwr >= 0) && (txCmd->txPwr <= 150))
rc = true;
} else if (txCmd->mode != TCMD_CONT_TX_OFF) {
if (txCmd->tpcm != TPC_FORCED_GAIN) {
if ((txCmd->txPwr >= -30) && (txCmd->txPwr <= 60))
rc = true;
} else {
if ((txCmd->txPwr >= 0) && (txCmd->txPwr <= 120))
rc = true;
}
} else if (txCmd->mode == TCMD_CONT_TX_OFF) {
rc = true;
}
if (!rc)
A_ERR(1,
"Invalid Tx Power value! \nTx data: [-15 - 14]dBm \nTx sine: [ 0 - 150]PCDAC value\n");
return rc;
}
static uint32_t pktSzValid(uint32_t val)
{
if ((val < 32) || (val > 1500)) {
A_ERR(-1, "Invalid package size! < 32 - 1500 >\n");
}
return val;
}
#ifdef NOTYET
// Validate a hex character
static bool _is_hex(char c)
{
return (((c >= '0') && (c <= '9')) ||
((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')));
}
// Convert a single hex nibble
static int _from_hex(char c)
{
int ret = 0;
if ((c >= '0') && (c <= '9')) {
ret = (c - '0');
} else if ((c >= 'a') && (c <= 'f')) {
ret = (c - 'a' + 0x0a);
} else if ((c >= 'A') && (c <= 'F')) {
ret = (c - 'A' + 0x0A);
}
return ret;
}
// Convert a character to lower case
static char _tolower(char c)
{
if ((c >= 'A') && (c <= 'Z')) {
c = (c - 'A') + 'a';
}
return c;
}
// Validate alpha
static bool isalpha(int c)
{
return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')));
}
// Validate digit
static bool isdigit(int c)
{
return ((c >= '0') && (c <= '9'));
}
// Validate alphanum
static bool isalnum(int c)
{
return (isalpha(c) || isdigit(c));
}
#endif
/*------------------------------------------------------------------*/
/*
* Input an Ethernet address and convert to binary.
*/
static int ath_ether_aton(const char *orig, uint8_t * eth)
{
int mac[6];
if (sscanf(orig, "%02x:%02x:%02X:%02X:%02X:%02X",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6) {
int i;
#ifdef DEBUG
if (*(orig + 12 + 5) != 0) {
fprintf(stderr, "%s: trailing junk '%s'!\n", __func__,
orig);
return -1;
}
#endif
for (i = 0; i < 6; ++i)
eth[i] = mac[i] & 0xff;
return 0;
}
return -1;
}
// Read "golden" eeprom bin
// Update it with CAL data
bool readCalDataFromFileBin(char *fileName, AR6003_EEPROM *eepromData)
{
FILE *fp;
bool rc=true;
uint32_t numBytes;
printf("readCalDataFromFile - reading EEPROM file %s\n",fileName);
if( (fp = fopen(fileName, "rb")) == NULL) {
_printf("Could not open %s to read\n", fileName);
return false;
}
if (AR6K_EEPROM_SIZE_LARGEST == (numBytes = fread((uint8_t *)eepromData, 1, AR6K_EEPROM_SIZE_LARGEST, fp))) {
printf("Read %d from %s\n", numBytes, fileName);
rc = true;
}
else {
if (feof(fp)) {
printf("good Read %d from %s\n", numBytes, fileName);
rc = true;
}
else if (ferror(fp)) {
_printf("Error reading %s\n", fileName);
rc = false;
}
else { _printf("Unknown fread rc\n"); rc = false; }
}
if (fp) fclose(fp);
if (rc) {
if ((eepromData->baseEepHeader.version & AR6003_EEP_VER_MINOR_MASK) >= AR6003_EEP_MINOR_VER10) {
if (AR6K_EEPROM_SIZE_LARGEST != numBytes) {
printf("Num of bytes read %d mismatch expected %d\n", numBytes, AR6K_EEPROM_SIZE_LARGEST);
rc = false;
}
else {
AR6K_EEPROM_SIZE = AR6003_EEPROM_SIZE = AR6K_EEPROM_SIZE_LARGEST;
printf("New TPC scheme selected! %x %d\n", eepromData->baseEepHeader.version, AR6K_EEPROM_SIZE);
}
}
else {
_printf("EEPROM file version %d not supported, please re-calibrate it.\n", eepromData->baseEepHeader.version);
rc = false;
}
}
return rc;
}
#define _PSAT_COMMON_4_HOST
// if host doesn't support math.h, this section can be skipped, it is purely for data gathering
static double cmacPwr(double cmac)
{
double pwr;
double vfull=1.0, cycles = -15.0;
pwr = 10*log10(4*((double)cmac)*((double)pow(2.0, cycles))*((double)pow(vfull/512, 2)));
return(pwr);
}
static bool dumpPSATCharResult2File(TC_MSG *pTCMsg)
{
FILE *dbgFp;
int i;
uint32_t cmac_i;
#ifdef ANDROID
if ( (dbgFp = fopen("/persist/psatCharData.csv", "a+")) == NULL) {
printf("Error: open _psatCharData.csv\n");
return(false);
}
#else
if ( (dbgFp = fopen("_psatCharData.csv", "a+")) == NULL) {
printf("Error: open _psatCharData.csv\n");
return(false);
}
#endif
fprintf(dbgFp, "%d, %d, %d, %d, %d, %d, %d, %d\n",
pTCMsg->msg.psatCharResults.freq,
pTCMsg->msg.psatCharResults.an_txrf3_rdiv2g,
pTCMsg->msg.psatCharResults.an_txrf3_pdpredist2g,
pTCMsg->msg.psatCharResults.an_rxtx2_mxrgain,
pTCMsg->msg.psatCharResults.an_rxrf_bias1_pwd_ic25mxr2gh,
pTCMsg->msg.psatCharResults.an_bias2_pwd_ic25rxrf,
pTCMsg->msg.psatCharResults.an_bb1_i2v_curr2x,
pTCMsg->msg.psatCharResults.an_txrf3_capdiv2g);
for (i=0;i<_MAX_TX_GAIN_ENTRIES;i++) {
cmac_i = pTCMsg->msg.psatCharResults.cmac_i[i];
fprintf(dbgFp, "%d, %d, %f, %d\n", pTCMsg->msg.psatCharResults.pcdac[i], cmac_i, cmacPwr(cmac_i), cmac2Pwr_t10(cmac_i));
}
if (dbgFp) fclose(dbgFp);
return(true);
}
uint16_t computeChecksumOnly(uint16_t *pHalf, uint16_t length)
{
uint16_t sum = 0, i;
for (i = 0; i < length; i++) { sum ^= *pHalf++; }
return(sum);
}
void computeChecksum(AR6003_EEPROM *pEepStruct)
{
uint16_t sum, *pHalf;
uint8_t eepromVersion;
eepromVersion = pEepStruct->baseEepHeader.version & AR6003_EEP_VER_MINOR_MASK;
if (eepromVersion >= AR6003_EEP_MINOR_VER5) {
// first checksum
pEepStruct->baseEepHeader.checksum = 0x0000;
pHalf = (uint16_t *)pEepStruct;
sum = computeChecksumOnly(pHalf, AR6K_EEPROM_SIZE_PRIOR_VER4/2);
pEepStruct->baseEepHeader.checksum = 0xFFFF ^ sum;
// second (expanded checksum)
pEepStruct->checksumExpanded = 0x0000;
pHalf = (uint16_t *)pEepStruct;
pHalf += AR6K_EEPROM_SIZE_PRIOR_VER4/2;
sum = computeChecksumOnly(pHalf, (AR6003_EEPROM_SIZE - AR6K_EEPROM_SIZE_PRIOR_VER4)/2);
pEepStruct->checksumExpanded = 0xFFFF ^ sum;
_printf("--computeChecksum old 0x%x expanded 0x%x\n", pEepStruct->baseEepHeader.checksum, pEepStruct->checksumExpanded);
}
else {
pEepStruct->baseEepHeader.checksum = 0x0000;
pHalf = (uint16_t *)pEepStruct;
sum = computeChecksumOnly(pHalf, AR6K_EEPROM_SIZE_PRIOR_VER4/2);
pEepStruct->baseEepHeader.checksum = 0xFFFF ^ sum;
_printf("--computeChecksum old 0x%x\n", pEepStruct->baseEepHeader.checksum);
}
}
bool genEepromBinFile(char *fileName, AR6003_EEPROM *pEepStruct)
{
FILE *fp;
// re-computing checksum
pEepStruct->baseEepHeader.checksum = 0;
computeChecksum(pEepStruct);
if ( (fp = fopen(fileName, "wb")) == NULL) {
_printf("Error: open to write eeprom bin %s \n", fileName);
return false;
}
if (sizeof(AR6003_EEPROM) != fwrite((uint8_t *)pEepStruct, 1, sizeof(AR6003_EEPROM), fp)) {
_printf("Error: writing to %s\n", fileName);
}
if (fp) fclose(fp);
return(true);
}
static void updateCALData(_CAL_SETUP *pCalSetup, TC_MSG *pTCMsg)
{
bool rc;
AR6003_EEPROM eepromData, *pEeprom=&eepromData;
AR6003_BASE_EEP_HEADER *pBase;
AR6003_CAL_DATA_PER_FREQ_OLPC_EXPANDED *pRawDataSet2G_ext, *pRawDataSet5G_ext;
uint8_t *pCalChans2G, *pCalChans5G;
uint32_t numPiers2G, numPiers5G;
uint32_t i;
// read in golden bin
rc = readCalDataFromFileBin(pCalSetup->goldenBinFilename, pEeprom);
assert(rc);
printf("Read %s\n", pCalSetup->goldenBinFilename);
numPiers2G = numPiers5G = 0;
pBase = &(pEeprom->baseEepHeader);
{
if (pBase->opCapFlags & WLAN_11G_CAPABILITY) {
pRawDataSet2G_ext = pEeprom->calPierData2GExpanded;
pCalChans2G = pEeprom->calFreqPier2GExpanded;
for (numPiers2G = 0; numPiers2G < AR6003_NUM_2G_CAL_PIERS_EXPANDED; numPiers2G++) {
if (pCalChans2G[numPiers2G] == AR6003_BCHAN_UNUSED) {
break;
}
}
}
if (pBase->opCapFlags & WLAN_11A_CAPABILITY) {
pRawDataSet5G_ext = pEeprom->calPierData5GExpanded;
pCalChans5G = pEeprom->calFreqPier5GExpanded;
for (numPiers5G = 0; numPiers5G < AR6003_NUM_5G_CAL_PIERS_EXPANDED; numPiers5G++) {
if (pCalChans5G[numPiers5G] == AR6003_BCHAN_UNUSED) {
break;
}
}
}
}
PSAT_CAL_RESULTS *pPsatCalResults = &(pTCMsg->msg.psatCalResults);
for (i=0;i<numPiers2G;i++) {
printf("%d %d %d %d %d %.2f %.2f %d %d 0x%x %d %d 0x%x\n", pPsatCalResults->olpcGainTherm2G[i].olpcGainDelta_diff, pPsatCalResults->olpcGainTherm2G[i].olpcGainDelta_abs, pPsatCalResults->olpcGainTherm2G[i].thermCalVal,
pPsatCalResults->olpcGainTherm2G[i].cmac_psat, pPsatCalResults->olpcGainTherm2G[i].cmac_olpc,
cmacPwr(pPsatCalResults->olpcGainTherm2G[i].cmac_psat), cmacPwr(pPsatCalResults->olpcGainTherm2G[i].cmac_olpc),
pPsatCalResults->olpcGainTherm2G[i].cmac_psat_pcdac, pPsatCalResults->olpcGainTherm2G[i].cmac_olpc_pcdac,
pPsatCalResults->olpcGainTherm2G[i].numTryBF,
pPsatCalResults->olpcGainTherm2G[i].lineSlope, pPsatCalResults->olpcGainTherm2G[i].lineVariance,
pPsatCalResults->olpcGainTherm2G[i].psatParm);
//}
}
for (i=0;i<numPiers5G ;i++) {
printf("%d %d %d %d %d %.2f %.2f %d %d 0x%x\n", pPsatCalResults->olpcGainTherm5G[i].olpcGainDelta_diff, pPsatCalResults->olpcGainTherm5G[i].olpcGainDelta_abs, pPsatCalResults->olpcGainTherm5G[i].thermCalVal,
pPsatCalResults->olpcGainTherm5G[i].cmac_psat, pPsatCalResults->olpcGainTherm5G[i].cmac_olpc,
cmacPwr(pPsatCalResults->olpcGainTherm5G[i].cmac_psat), cmacPwr(pPsatCalResults->olpcGainTherm5G[i].cmac_olpc),
pPsatCalResults->olpcGainTherm5G[i].cmac_psat_pcdac, pPsatCalResults->olpcGainTherm5G[i].cmac_olpc_pcdac,
pPsatCalResults->olpcGainTherm5G[i].numTryBF);
//}
}
for (i=0;i<numPiers2G;i++) {
if (pEeprom->baseEepHeader.boardFlagsExt & AR6003_BOARDFLAGSEXT_PSAT_CAL_ABS) {
pRawDataSet2G_ext[i].olpcBasic.olpcGainDelta = (int8_t) (pPsatCalResults->olpcGainTherm2G[i].olpcGainDelta_abs);
pRawDataSet2G_ext[i].olpcGainDelta_t10 = (int16_t) (pPsatCalResults->olpcGainTherm2G[i].olpcGainDelta_abs *5);
}
else {
pRawDataSet2G_ext[i].olpcBasic.olpcGainDelta = (int8_t) (pPsatCalResults->olpcGainTherm2G[i].olpcGainDelta_diff);
pRawDataSet2G_ext[i].olpcGainDelta_t10 = (int16_t) (pPsatCalResults->olpcGainTherm2G[i].olpcGainDelta_diff *5);
}
pRawDataSet2G_ext[i].olpcBasic.thermCalVal = (uint8_t) pPsatCalResults->olpcGainTherm2G[i].thermCalVal;
}
for (i=0;i<numPiers5G;i++) {
if (pEeprom->baseEepHeader.boardFlagsExt & AR6003_BOARDFLAGSEXT_PSAT_CAL_ABS) {
pRawDataSet5G_ext[i].olpcBasic.olpcGainDelta = (int8_t)pPsatCalResults->olpcGainTherm5G[i].olpcGainDelta_abs;
}
else {
pRawDataSet5G_ext[i].olpcBasic.olpcGainDelta = (int8_t)pPsatCalResults->olpcGainTherm5G[i].olpcGainDelta_diff;
}
pRawDataSet5G_ext[i].olpcBasic.thermCalVal = (uint8_t)pPsatCalResults->olpcGainTherm5G[i].thermCalVal;
pRawDataSet5G_ext[i].olpcGainDelta_t10 = (int16_t)(pPsatCalResults->olpcGainTherm5G[i].olpcGainDelta_diff * 5);
}
memcpy((void*)&(pEeprom->baseEepHeader.custData[0]), pCalSetup->label, sizeof(pCalSetup->label));
// Generate bin
if (pEeprom->baseEepHeader.boardFlagsExt & AR6003_BOARDFLAGSEXT_PSAT_CAL_GEN_EEPROM) {
rc = genEepromBinFile(pCalSetup->outputBinFilename, pEeprom);
assert(rc);
}
return;
}