diff options
-rw-r--r-- | src/util/Makefile.am | 7 | ||||
-rw-r--r-- | src/util/cell_log.c | 434 |
2 files changed, 440 insertions, 1 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 90d1d80..3d87a32 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -1,11 +1,16 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS = -std=gnu99 -bin_PROGRAMS = libgsmd-tool +bin_PROGRAMS = libgsmd-tool cell_log libgsmd_tool_SOURCES = libgsmd-tool.c shell.c event.c pin.c atcmd.c \ $(top_srcdir)/src/gsmd/talloc.c libgsmd_tool_LDADD = $(top_builddir)/src/libgsmd/libgsmd.la libgsmd_tool_LDFLAGS = -dynamic +cell_log_SOURCES = cell_log.c \ + $(top_srcdir)/src/gsmd/talloc.c +cell_log_LDADD = $(top_builddir)/src/libgsmd/libgsmd.la +cell_log_LDFLAGS = -dynamic + noinst_HEADERS = atcmd.h event.h pin.h shell.h diff --git a/src/util/cell_log.c b/src/util/cell_log.c new file mode 100644 index 0000000..59d8942 --- /dev/null +++ b/src/util/cell_log.c @@ -0,0 +1,434 @@ +/* libgsmd tool + * + * (C) 2006-2007 by OpenMoko, Inc. + * Written by Harald Welte <laforge@openmoko.org> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <syslog.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <libgsmd/libgsmd.h> +#include <libgsmd/voicecall.h> +#include <libgsmd/misc.h> +#include <libgsmd/phonebook.h> +#include <libgsmd/sms.h> +#include <libgsmd/pin.h> +#include <gsmd/usock.h> +#include <gsmd/ts0705.h> +#include <common/linux_list.h> + +#ifndef __GSMD__ +#define __GSMD__ +#include <gsmd/talloc.h> +#undef __GSMD__ +#endif + +#define STDIN_BUF_SIZE 1024 + +static int pending_responses = 0; + + + +/* BTS RF_LOCK */ + +#define MIN_NO_NET_SECS 60 +#define OUR_MCC 901 +#define OUR_MNC 99 +#define LOCK_PATH "/var/lock/bts_rf_lock" + +static time_t last_network_seen; +unsigned int rf_lock_active = 0; + +static void bts_rf_lock(int on) +{ + int fd; + + /* only print message on status change */ + if (rf_lock_active != on) + syslog(LOG_NOTICE, "RF_LOCK: %sabling lock\n", on ? "En" : "Dis"); + + /* for safety, always update the actual file on disk */ + if (on == 1) { + struct stat st; + if (stat(LOCK_PATH, &st) != 0) { + fd = open(LOCK_PATH, O_WRONLY|O_CREAT, 0664); + if (fd >= 0) + close(fd); + } + } else + unlink(LOCK_PATH); + + rf_lock_active = on; +} + + +static void we_have_seen_network(unsigned int mcc, unsigned int mnc) +{ + /* ignore our own network */ + if (mcc == OUR_MCC && mnc == OUR_MNC) + return; + + /* update timestamp at which we have last seen the network */ + last_network_seen = time(NULL); + bts_rf_lock(1); +} + +static int network_long_ago() +{ + time_t now = time(NULL); + + if (now - last_network_seen > MIN_NO_NET_SECS) + return 1; + + return 0; +} + +static void rf_lock_timer_check() +{ + if (network_long_ago()) + bts_rf_lock(0); + else + bts_rf_lock(1); +} + +/* OPERATOR QUEUE */ + +static LLIST_HEAD(opq); + +struct opq_entry { + struct llist_head list; + char opname_num[32]; +}; + +static void *opq_ctx = NULL; + +static void opq_enqueue(const char *opname_num) +{ + struct opq_entry *e = talloc_zero(opq_ctx, struct opq_entry); + unsigned int mcc = 0, mnc = 0; + + syslog(LOG_DEBUG, "OPQ: Adding operator `%s'\n", opname_num); + strncpy(e->opname_num, opname_num, sizeof(e->opname_num)); + llist_add_tail(&e->list, &opq); + + sscanf(opname_num, "%03u%02u", &mcc, &mnc); + we_have_seen_network(mcc, mnc); +} + +static void opq_next_operator(struct lgsm_handle *lgsmh) +{ + struct opq_entry *e; + + if (llist_empty(&opq)) { + syslog(LOG_DEBUG, "OPQ: No more operators in queue, re-scanning\n"); + lgsm_opers_get(lgsmh); + return; + } + + e = llist_entry(opq.next, struct opq_entry, list); + syslog(LOG_DEBUG, "OPQ: Selectiong Operator %s\n", e->opname_num); + llist_del(&e->list); + lgsm_netreg_register(lgsmh, e->opname_num); + talloc_free(e); +} + + + + +/* this is the handler for receiving passthrough responses */ +static int pt_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh) +{ + char *payload = (char *)gmh + sizeof(*gmh); + printf("RSTR=`%s'\n", payload); + return 0; +} + +/* this is the handler for responses to network/operator commands */ +static int net_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh) +{ + const struct gsmd_signal_quality *sq = (struct gsmd_signal_quality *) + ((void *) gmh + sizeof(*gmh)); + const char *oper = (char *) gmh + sizeof(*gmh); + const struct gsmd_msg_oper *opers = (struct gsmd_msg_oper *) + ((void *) gmh + sizeof(*gmh)); + const struct gsmd_own_number *num = (struct gsmd_own_number *) + ((void *) gmh + sizeof(*gmh)); + const struct gsmd_voicemail *vmail = (struct gsmd_voicemail *) + ((void *) gmh + sizeof(*gmh)); + enum gsmd_netreg_state state = *(enum gsmd_netreg_state *) gmh->data; + int result = *(int *) gmh->data; + static const char *oper_stat[] = { + [GSMD_OPER_UNKNOWN] = "of unknown status", + [GSMD_OPER_AVAILABLE] = "available", + [GSMD_OPER_CURRENT] = "our current operator", + [GSMD_OPER_FORBIDDEN] = "forbidden", + }; + static const char *srvname[] = { + [GSMD_SERVICE_ASYNC_MODEM] = "asynchronous modem", + [GSMD_SERVICE_SYNC_MODEM] = "synchronous modem", + [GSMD_SERVICE_PAD_ACCESS] = "PAD Access (asynchronous)", + [GSMD_SERVICE_PACKET_ACCESS] = "Packet Access (synchronous)", + [GSMD_SERVICE_VOICE] = "voice", + [GSMD_SERVICE_FAX] = "fax", + }; + + switch (gmh->msg_subtype) { + case GSMD_NETWORK_SIGQ_GET: + if (sq->rssi == 99) + printf("Signal undetectable\n"); + else + printf("Signal quality %i dBm\n", -113 + sq->rssi * 2); + if (sq->ber == 99) + printf("Error rate undetectable\n"); + else + printf("Bit error rate %i\n", sq->ber); + pending_responses --; + break; + case GSMD_NETWORK_OPER_GET: + case GSMD_NETWORK_OPER_N_GET: + if (oper[0]) + printf("Our current operator is %s\n", oper); + else + printf("No current operator\n"); + pending_responses --; + break; + case GSMD_NETWORK_OPER_LIST: + for (; !opers->is_last; opers ++) { + syslog(LOG_INFO, "OPER: %8.*s %16.*s, %.*s for short, is %s\n", + sizeof(opers->opname_num), + opers->opname_num, + sizeof(opers->opname_longalpha), + opers->opname_longalpha, + sizeof(opers->opname_shortalpha), + opers->opname_shortalpha, + oper_stat[opers->stat]); + opq_enqueue(opers->opname_num); + } + opq_next_operator(lh); + pending_responses --; + break; + case GSMD_NETWORK_GET_NUMBER: + printf("\t%s\t%10s%s%s%s\n", num->addr.number, num->name, + (num->service == GSMD_SERVICE_UNKNOWN) ? + "" : " related to ", + (num->service == GSMD_SERVICE_UNKNOWN) ? + "" : srvname[num->service], + (num->service == GSMD_SERVICE_UNKNOWN) ? + "" : " services"); + pending_responses --; + break; + case GSMD_NETWORK_VMAIL_SET: + if (result) + printf("Set voicemail error %i\n", result); + else + printf("Set voicemail OK \n"); + pending_responses --; + break; + case GSMD_NETWORK_VMAIL_GET: + if(vmail->addr.number) + printf ("voicemail number is %s \n",vmail->addr.number); + pending_responses --; + break; + case GSMD_NETWORK_QUERY_REG: + switch (state) { + case GSMD_NETREG_UNREG: + printf("not searching for network \n"); + break; + case GSMD_NETREG_REG_HOME: + printf("registered (home network) \n"); + break; + case GSMD_NETREG_UNREG_BUSY: + printf("searching for network \n"); + break; + case GSMD_NETREG_DENIED: + printf("registration denied \n"); + break; + case GSMD_NETREG_REG_ROAMING: + printf("registered (roaming) \n"); + break; + default: + break; + } + pending_responses --; + break; + default: + return -EINVAL; + } + return 0; +} + +static int phone_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh) +{ + char *payload = (char *)gmh + sizeof(*gmh); + int *intresult = (void *)gmh + sizeof(*gmh); + const struct gsmd_battery_charge *bc = (struct gsmd_battery_charge *) + ((void *) gmh + sizeof(*gmh)); + + switch (gmh->msg_subtype) { + case GSMD_PHONE_GET_IMSI: + printf("imsi <%s>\n", payload); + break; + case GSMD_PHONE_GET_MANUF: + printf("manufacturer: %s\n", payload); + break; + case GSMD_PHONE_GET_MODEL: + printf("model: %s\n", payload); + break; + case GSMD_PHONE_GET_REVISION: + printf("revision: %s\n", payload); + break; + case GSMD_PHONE_GET_SERIAL: + printf("serial: %s\n", payload); + break; + case GSMD_PHONE_POWERUP: + if (*intresult) + printf("Modem power-up failed: %i\n", *intresult); + else + printf("Modem powered-up okay\n"); + break; + case GSMD_PHONE_POWERDOWN: + if (*intresult) + printf("Modem power-down failed: %i\n", *intresult); + else + printf("Modem down\n"); + break; + case GSMD_PHONE_POWER_STATUS: + printf("Antenna Status: %s\n", payload); + break; + case GSMD_PHONE_GET_BATTERY: + printf("<BCS>: %d <BCL>: %d \n", bc->bcs, bc->bcl); + break; + case GSMD_PHONE_VIB_ENABLE: + if(*intresult) + printf("Vibrator enable failed: %i\n", *intresult); + else + printf("Vibrator enabled\n"); + break; + case GSMD_PHONE_VIB_DISABLE: + if(*intresult) + printf("Vibrator disable failed: %i\n", *intresult); + else + printf("VIbrator disabled\n"); + break; + default: + return -EINVAL; + } + pending_responses --; + return 0; +} + +static const struct msghandler_s { + int type; + lgsm_msg_handler *fn; +} msghandlers[] = { + { GSMD_MSG_PASSTHROUGH, pt_msghandler }, + { GSMD_MSG_NETWORK, net_msghandler }, + { GSMD_MSG_PHONE, phone_msghandler }, + + { 0, 0 } +}; + +int celllog_main(struct lgsm_handle *lgsmh) +{ + int rc; + char buf[STDIN_BUF_SIZE+1]; + fd_set readset; + char *ptr, *fcomma, *lcomma; + int gsm_fd = lgsm_fd(lgsmh); + const struct msghandler_s *hndl; + + for (hndl = msghandlers; hndl->fn; hndl ++) + lgsm_register_handler(lgsmh, hndl->type, hndl->fn); + + fcntl(gsm_fd, F_SETFD, O_NONBLOCK); + FD_ZERO(&readset); + + struct timeval tv = { .tv_sec = 30 }; + + while (1) { + fd_set readset; + FD_SET(gsm_fd, &readset); + + rc = select(gsm_fd+1, &readset, NULL, NULL, &tv); + if (rc < 0) + break; + + /* Timeout: Iterate to next operator */ + if (rc == 0) { + opq_next_operator(lgsmh); + tv.tv_sec = 30; + rf_lock_timer_check(); + } + + if (FD_ISSET(gsm_fd, &readset)) { + /* we've received something on the gsmd socket, pass it + * on to the library */ + rc = read(gsm_fd, buf, sizeof(buf)); + if (rc <= 0) { + syslog(LOG_ERR, "ERROR reading from gsm_fd\n"); + break; + } + rc = lgsm_handle_packet(lgsmh, buf, rc); + if (rc < 0) + syslog(LOG_ERR, "ERROR processing packet: %d(%s)\n", rc, strerror(-rc)); + } + fflush(stdout); + } + return 0; +} + +static int cinfo_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux) +{ + syslog(LOG_INFO, "EVENT: Cell Info: %03u-%03u-%04x-%04x @ %04u (%02u)\n", + aux->u.cell_info.mcc, aux->u.cell_info.mnc, aux->u.cell_info.lac, + aux->u.cell_info.ci, aux->u.cell_info.arfcn, aux->u.cell_info.rxlev); + we_have_seen_network(aux->u.cell_info.mcc, aux->u.cell_info.mnc); + return 0; +} + + +int main(int argc, char **argv) +{ + static struct lgsm_handle *lgsmh; + printf("cell_log - (C) 2012 by Harald Welte <laforge@gnumonks.org>.\n" + "This program is Free Software and has ABSOLUTELY NO WARRANTY\n\n"); + + openlog("cell_log", 0, LOG_LOCAL0); + + lgsmh = lgsm_init(LGSMD_DEVICE_GSMD); + if (!lgsmh) { + fprintf(stderr, "Can't connect to gsmd\n"); + exit(1); + } + + lgsm_evt_handler_register(lgsmh, GSMD_EVT_CELLINFO, &cinfo_handler); + we_have_seen_network(23, 42); + + celllog_main(lgsmh); + + exit(0); +} |