/* * Hamlib Interface - toolbox * Copyright (c) 2000-2002 by Stephane Fillod and Frank Singleton * * $Id: misc.c,v 1.19 2002-07-08 22:20:15 fillods Exp $ * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include /* Standard input/output definitions */ #include /* String function definitions */ #include /* UNIX standard function definitions */ #include /* File control definitions */ #include /* Error number definitions */ #include #include #include #include "misc.h" static int rig_debug_level = RIG_DEBUG_TRACE; /* * Do a hex dump of the unsigned char array. */ #define DUMP_HEX_WIDTH 16 void dump_hex(const unsigned char ptr[], size_t size) { int i; char buf[DUMP_HEX_WIDTH+1]; if (!rig_need_debug(RIG_DEBUG_TRACE)) return; buf[DUMP_HEX_WIDTH] = '\0'; for(i=0; i= ' ' && ptr[i] < 0x7f) buf[i%DUMP_HEX_WIDTH] = ptr[i]; else buf[i%DUMP_HEX_WIDTH] = '.'; if (i % DUMP_HEX_WIDTH == DUMP_HEX_WIDTH-1) rig_debug(RIG_DEBUG_TRACE,"\t%s\n",buf); } /* Add some spaces in order to align right ASCII dump column */ if ((i / DUMP_HEX_WIDTH) > 0) { int j; for (j = i % DUMP_HEX_WIDTH; j < DUMP_HEX_WIDTH; j++) rig_debug(RIG_DEBUG_TRACE," "); } if (i % DUMP_HEX_WIDTH != DUMP_HEX_WIDTH-1) { buf[i % DUMP_HEX_WIDTH] = '\0'; rig_debug(RIG_DEBUG_TRACE,"\t%s\n",buf); } } /* * Convert a long long (eg. frequency in Hz) to 4-bit BCD digits, * packed two digits per octet, in little-endian order. * bcd_len is the number of BCD digits, usually 10 or 8 in 1-Hz units, * and 6 digits in 100-Hz units for Tx offset data. * * Hope the compiler will do a good job optimizing it (esp. w/ the 64bit freq) */ unsigned char * to_bcd(unsigned char bcd_data[], unsigned long long freq, int bcd_len) { int i; unsigned char a; /* '450'-> 0,5;4,0 */ for (i=0; i < bcd_len/2; i++) { a = freq%10; freq /= 10; a |= (freq%10)<<4; freq /= 10; bcd_data[i] = a; } if (bcd_len&1) { bcd_data[i] &= 0xf0; bcd_data[i] |= freq%10; /* NB: high nibble is left uncleared */ } return bcd_data; } /* * Convert BCD digits to a long long (eg. frequency in Hz) * bcd_len is the number of BCD digits. * * Hope the compiler will do a good job optimizing it (esp. w/ the 64bit freq) */ unsigned long long from_bcd(const unsigned char bcd_data[], int bcd_len) { int i; freq_t f = 0; if (bcd_len&1) f = bcd_data[bcd_len/2] & 0x0f; for (i=(bcd_len/2)-1; i >= 0; i--) { f *= 10; f += bcd_data[i]>>4; f *= 10; f += bcd_data[i] & 0x0f; } return f; } /* * Same as to_bcd, but in Big Endian mode */ unsigned char * to_bcd_be(unsigned char bcd_data[], unsigned long long freq, int bcd_len) { int i; unsigned char a; /* '450'-> 0,4;5,0 */ for (i=(bcd_len/2)-1; i >= 0; i--) { a = freq%10; freq /= 10; a |= (freq%10)<<4; freq /= 10; bcd_data[i] = a; } if (bcd_len&1) { bcd_data[0] &= 0xf0; bcd_data[0] |= freq%10; /* NB: high nibble is left uncleared */ } return bcd_data; } /* * Same as from_bcd, but in Big Endian mode */ unsigned long long from_bcd_be(const unsigned char bcd_data[], int bcd_len) { int i; freq_t f = 0; if (bcd_len&1) f = bcd_data[0] & 0x0f; for (i=bcd_len&1; i < (bcd_len+1)/2; i++) { f *= 10; f += bcd_data[i]>>4; f *= 10; f += bcd_data[i] & 0x0f; } return f; } /* * rig_set_debug * Change the current debug level */ void rig_set_debug(enum rig_debug_level_e debug_level) { rig_debug_level = debug_level; } /* * rig_need_debug * Usefull for dump_hex, etc. */ int rig_need_debug(enum rig_debug_level_e debug_level) { return (debug_level <= rig_debug_level); } /* * rig_debug * Debugging messages are done through stderr * TODO: add syslog support if needed */ void rig_debug(enum rig_debug_level_e debug_level, const char *fmt, ...) { va_list ap; if (debug_level <= rig_debug_level) { va_start(ap, fmt); /* * Who cares about return code? */ vfprintf (stderr, fmt, ap); va_end(ap); } } #define llabs(a) ((a)<0?-(a):(a)) /* * rig_freq_snprintf? * pretty print frequencies * str must be long enough. max can be as long as 17 chars */ int sprintf_freq(char *str, freq_t freq) { double f; char *hz; if (llabs(freq) >= GHz(1)) { hz = "GHz"; f = (double)freq/GHz(1); } else if (llabs(freq) >= MHz(1)) { hz = "MHz"; f = (double)freq/MHz(1); } else if (llabs(freq) >= kHz(1)) { hz = "kHz"; f = (double)freq/kHz(1); } else { hz = "Hz"; f = (double)freq; } return sprintf (str, "%g %s", f, hz); } const char * strmode(rmode_t mode) { switch (mode) { case RIG_MODE_AM: return "AM"; case RIG_MODE_CW: return "CW"; case RIG_MODE_USB: return "USB"; case RIG_MODE_LSB: return "LSB"; case RIG_MODE_RTTY: return "RTTY"; case RIG_MODE_FM: return "FM"; case RIG_MODE_WFM: return "WFM"; case RIG_MODE_NONE: return ""; } return NULL; } /* * shouldn't this use the same table as parse_vfo()? * It already caused me one bug. :) --Dale */ const char *strvfo(vfo_t vfo) { switch (vfo) { case RIG_VFO_A: return "VFOA"; case RIG_VFO_B: return "VFOB"; case RIG_VFO_C: return "VFOC"; case RIG_VFO_CURR: return "currVFO"; case RIG_VFO_MEM: return "MEM"; case RIG_VFO_VFO: return "VFO"; case RIG_VFO_MAIN: return "Main"; case RIG_VFO_SUB: return "Sub"; } return NULL; } const char *strfunc(setting_t func) { switch (func) { case RIG_FUNC_FAGC: return "FAGC"; case RIG_FUNC_NB: return "NB"; case RIG_FUNC_COMP: return "COMP"; case RIG_FUNC_VOX: return "VOX"; case RIG_FUNC_TONE: return "TONE"; case RIG_FUNC_TSQL: return "TSQL"; case RIG_FUNC_SBKIN: return "SBKIN"; case RIG_FUNC_FBKIN: return "FBKIN"; case RIG_FUNC_ANF: return "ANF"; case RIG_FUNC_NR: return "NR"; case RIG_FUNC_AIP: return "AIP"; case RIG_FUNC_APF: return "APF"; case RIG_FUNC_MON: return "MON"; case RIG_FUNC_MN: return "MN"; case RIG_FUNC_RNF: return "RNF"; case RIG_FUNC_ARO: return "ARO"; case RIG_FUNC_LOCK: return "LOCK"; case RIG_FUNC_MUTE: return "MUTE"; case RIG_FUNC_VSC: return "VSC"; case RIG_FUNC_REV: return "REV"; case RIG_FUNC_SQL: return "SQL"; case RIG_FUNC_BC: return "BC"; case RIG_FUNC_MBC: return "MBC"; case RIG_FUNC_LMP: return "LMP"; case RIG_FUNC_AFC: return "AFC"; case RIG_FUNC_SATMODE: return "SATMODE"; case RIG_FUNC_SCOPE: return "SCOPE"; case RIG_FUNC_RESUME: return "RESUME"; case RIG_FUNC_NONE: return ""; } return NULL; } const char *strlevel(setting_t level) { switch (level) { case RIG_LEVEL_PREAMP: return "PREAMP"; case RIG_LEVEL_ATT: return "ATT"; case RIG_LEVEL_VOX: return "VOX"; case RIG_LEVEL_AF: return "AF"; case RIG_LEVEL_RF: return "RF"; case RIG_LEVEL_SQL: return "SQL"; case RIG_LEVEL_IF: return "IF"; case RIG_LEVEL_APF: return "APF"; case RIG_LEVEL_NR: return "NR"; case RIG_LEVEL_PBT_IN: return "PBT_IN"; case RIG_LEVEL_PBT_OUT: return "PBT_OUT"; case RIG_LEVEL_CWPITCH: return "CWPITCH"; case RIG_LEVEL_RFPOWER: return "RFPOWER"; case RIG_LEVEL_MICGAIN: return "MICGAIN"; case RIG_LEVEL_KEYSPD: return "KEYSPD"; case RIG_LEVEL_NOTCHF: return "NOTCHF"; case RIG_LEVEL_COMP: return "COMP"; case RIG_LEVEL_AGC: return "AGC"; case RIG_LEVEL_BKINDL: return "BKINDL"; case RIG_LEVEL_BALANCE: return "BALANCE"; case RIG_LEVEL_METER: return "METER"; case RIG_LEVEL_VOXGAIN: return "VOXGAIN"; case RIG_LEVEL_ANTIVOX: return "ANTIVOX"; case RIG_LEVEL_SWR: return "SWR"; case RIG_LEVEL_ALC: return "ALC"; case RIG_LEVEL_SQLSTAT: return "SQLSTAT"; case RIG_LEVEL_STRENGTH: return "STRENGTH"; case RIG_LEVEL_NONE: return ""; } return NULL; } const char *strparm(setting_t parm) { switch (parm) { case RIG_PARM_ANN: return "ANN"; case RIG_PARM_APO: return "APO"; case RIG_PARM_BACKLIGHT: return "BACKLIGHT"; case RIG_PARM_BEEP: return "BEEP"; case RIG_PARM_TIME: return "TIME"; case RIG_PARM_BAT: return "BAT"; case RIG_PARM_NONE: return ""; } return NULL; } const char *strptrshift(rptr_shift_t shift) { switch (shift) { case RIG_RPT_SHIFT_MINUS: return "+"; case RIG_RPT_SHIFT_PLUS: return "-"; case RIG_RPT_SHIFT_NONE: return "None"; } return NULL; } const char *strvfop(vfo_op_t op) { switch (op) { case RIG_OP_CPY: return "CPY"; case RIG_OP_XCHG: return "XCHG"; case RIG_OP_FROM_VFO: return "FROM_VFO"; case RIG_OP_TO_VFO: return "TO_VFO"; case RIG_OP_MCL: return "MCL"; case RIG_OP_UP: return "UP"; case RIG_OP_DOWN: return "DOWN"; case RIG_OP_BAND_UP: return "BAND_UP"; case RIG_OP_BAND_DOWN: return "BAND_DOWN"; case RIG_OP_LEFT: return "LEFT"; case RIG_OP_RIGHT: return "RIGHT"; case RIG_OP_NONE: return ""; } return NULL; } const char *strscan(scan_t rscan) { switch (rscan) { case RIG_SCAN_STOP: return "STOP"; case RIG_SCAN_MEM: return "MEM"; case RIG_SCAN_SLCT: return "SLCT"; case RIG_SCAN_PRIO: return "PRIO"; case RIG_SCAN_PROG: return "PROG"; case RIG_SCAN_DELTA: return "DELTA"; case RIG_SCAN_VFO: return "VFO"; } return NULL; } const char *strstatus(enum rig_status_e status) { switch (status) { case RIG_STATUS_ALPHA: return "Alpha"; case RIG_STATUS_UNTESTED: return "Untested"; case RIG_STATUS_BETA: return "Beta"; case RIG_STATUS_STABLE: return "Stable"; case RIG_STATUS_BUGGY: return "Buggy"; case RIG_STATUS_NEW: return "New"; } return ""; } int sprintf_mode(char *str, rmode_t mode) { int i, len=0; *str = '\0'; if (mode == RIG_MODE_NONE) return 0; for (i = 0; i < 30; i++) { const char *ms = strmode(mode & (1UL<