Changeset 2713


Ignore:
Timestamp:
08/16/07 07:48:59 (6 years ago)
Author:
laforge
Message:

Operator Selection (Andrzej Zaborowski)

This adds gsmd/libgsmd/libgmsd-tool commands to:

  • query available operators,
  • register to given operator,
  • register automatically (like gsmd did until now),
  • deregister,
  • get current operator name,
  • query signal quality,
  • query current connection state (a bit hacky, but it's the only way I found to satisfy the synchronous prototype in misc.h).

The operator cache is not used as it wouldn't give any benefit here. Retrieving
the list of present operators takes very long but there doesn't seem to exist
any way around it and all other phones I used also take that long.

The libgmsd call for registration to an automatically chosen operator now takes
a parameter of a different type so all libgsmd clients need to be updated (this
patch updates libgsmd-tool already, but not libmokogsmd which is not a part of
gsmd project).

Location:
trunk/src/target/gsm
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/target/gsm/include/gsmd/usock.h

    r2711 r2713  
    6767        GSMD_NETWORK_VMAIL_SET  = 4, 
    6868        GSMD_NETWORK_OPER_GET   = 5, 
    69         GSMD_NETWORK_CIND_GET   = 6, 
     69        GSMD_NETWORK_OPER_LIST  = 6, 
     70        GSMD_NETWORK_CIND_GET   = 7, 
     71        GSMD_NETWORK_DEREGISTER = 8, 
    7072}; 
    7173 
     
    359361} __attribute__ ((packed)); 
    360362 
     363/* Operator status from 3GPP TS 07.07, Clause 7.3 */ 
     364enum gsmd_oper_status { 
     365        GSMD_OPER_UNKNOWN, 
     366        GSMD_OPER_AVAILABLE, 
     367        GSMD_OPER_CURRENT, 
     368        GSMD_OPER_FORBIDDEN, 
     369}; 
     370 
     371/* Theoretically numeric operator code is five digits long but some 
     372 * operators apparently use six digit codes.  */ 
     373typedef char gsmd_oper_numeric[6]; 
     374 
     375struct gsmd_msg_oper { 
     376        enum gsmd_oper_status stat; 
     377        int is_last; 
     378        char opname_longalpha[16]; 
     379        char opname_shortalpha[8]; 
     380        gsmd_oper_numeric opname_num; 
     381}; 
     382 
    361383struct gsmd_msg_hdr { 
    362384        u_int8_t version; 
  • trunk/src/target/gsm/include/libgsmd/misc.h

    r1765 r2713  
    1010 
    1111extern int lgsm_phone_power(struct lgsm_handle *lh, int power); 
    12  
    13 enum lgsm_netreg_state { 
    14         LGSM_NETREG_ST_NOTREG           = 0, 
    15         LGSM_NETREG_ST_REG_HOME         = 1, 
    16         LGSM_NETREG_ST_NOTREG_SEARCH    = 2, 
    17         LGSM_NETREG_ST_DENIED           = 3, 
    18         LGSM_NETREG_ST_UNKNOWN          = 4, 
    19         LGSM_NETREG_ST_REG_ROAMING      = 5, 
    20 }; 
    21  
    22 /* Get the current network registration status */ 
    23 extern int lgsm_get_netreg_state(struct lgsm_handle *lh, 
    24                                  enum lgsm_netreg_state *state); 
    25  
    26 extern int lgsm_netreg_register(struct lgsm_handle *lh, int oper); 
    2712 
    2813enum lgsm_info_type { 
     
    5944 
    6045/* Operator Selection, Network Registration */ 
    61 /* TBD */ 
     46extern int lgsm_oper_get(struct lgsm_handle *lh); 
     47extern int lgsm_opers_get(struct lgsm_handle *lh); 
     48extern int lgsm_netreg_register(struct lgsm_handle *lh, 
     49                gsmd_oper_numeric oper); 
     50extern int lgsm_netreg_deregister(struct lgsm_handle *lh); 
    6251 
     52enum lgsm_netreg_state { 
     53        LGSM_NETREG_ST_NOTREG           = 0, 
     54        LGSM_NETREG_ST_REG_HOME         = 1, 
     55        LGSM_NETREG_ST_NOTREG_SEARCH    = 2, 
     56        LGSM_NETREG_ST_DENIED           = 3, 
     57        LGSM_NETREG_ST_UNKNOWN          = 4, 
     58        LGSM_NETREG_ST_REG_ROAMING      = 5, 
     59}; 
     60 
     61/* Get the current network registration status */ 
     62extern int lgsm_get_netreg_state(struct lgsm_handle *lh, 
     63                                 enum lgsm_netreg_state *state); 
    6364 
    6465/* CLIP, CLIR, COLP, Call Forwarding, Call Waiting, Call Deflecting */ 
  • trunk/src/target/gsm/src/gsmd/usock.c

    r2711 r2713  
    350350         
    351351        gsq = (struct gsmd_signal_quality *) ucmd->buf; 
    352         gsq->rssi = atoi(resp); 
     352        gsq->rssi = atoi(resp + 6); 
    353353        comma = strchr(resp, ','); 
    354354        if (!comma) { 
     
    363363} 
    364364 
    365 #define GSMD_OPER_MAXLEN        16 
    366365static int network_oper_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) 
    367366{ 
    368367        struct gsmd_user *gu = ctx; 
    369368        struct gsmd_ucmd *ucmd; 
    370         char *comma, *opname; 
    371          
    372         ucmd = gsmd_ucmd_fill(GSMD_OPER_MAXLEN+1, GSMD_MSG_NETWORK, 
    373                               GSMD_NETWORK_OPER_GET, 0); 
    374         if (!ucmd) 
    375                 return -ENOMEM; 
    376  
    377         /* Format: <mode>[, <format>, <oper>] */ 
    378         comma = strchr(resp, ','); 
    379         if (!comma) 
    380                 goto out_err; 
    381  
    382         if (atoi(comma+1) != 0) { 
    383                 gsmd_log(GSMD_NOTICE, "COPS format !=0 not supported yet!\n"); 
    384                 goto out_err; 
    385         } 
    386         comma = strchr(resp, ','); 
    387         if (!comma || *(comma+1) != '"') 
    388                 goto out_err; 
    389         opname = comma+2; 
    390  
    391         memcpy(ucmd->buf, opname, strlen(opname-1)); 
    392         ucmd->buf[strlen(opname)] = '\0'; 
    393  
    394         usock_cmd_enqueue(ucmd, gu); 
    395  
    396         return 0; 
    397  
    398 out_err: 
    399         talloc_free(ucmd); 
    400         return -EIO; 
     369        const char *end, *opname; 
     370        int format, s; 
     371 
     372        /* Format: <mode>[,<format>,<oper>] */ 
     373        /* In case we're not registered, return an empty string.  */ 
     374        if (sscanf(resp, "+COPS: %*i,%i,\"%n", &format, &s) <= 0) 
     375                end = opname = resp; 
     376        else { 
     377                /* If the phone returned the opname in a short or numeric 
     378                 * format, then it probably doesn't know the operator's full 
     379                 * name or doesn't support it.  Return any information we 
     380                 * have in this case.  */ 
     381                if (format != 0) 
     382                        gsmd_log(GSMD_NOTICE, "+COPS response in a format " 
     383                                        " different than long alphanumeric - " 
     384                                        " returning as is!\n"); 
     385                opname = resp + s; 
     386                end = strchr(opname, '"'); 
     387                if (!end) 
     388                        return -EINVAL; 
     389        } 
     390 
     391        ucmd = gsmd_ucmd_fill(end - opname + 1, GSMD_MSG_NETWORK, 
     392                        GSMD_NETWORK_OPER_GET, 0); 
     393        if (!ucmd) 
     394                return -ENOMEM; 
     395 
     396        memcpy(ucmd->buf, opname, end - opname); 
     397        ucmd->buf[end - opname] = '\0'; 
     398 
     399        usock_cmd_enqueue(ucmd, gu); 
     400 
     401        return 0; 
     402} 
     403 
     404static int network_opers_parse(const char *str, struct gsmd_msg_oper out[]) 
     405{ 
     406        int len = 0; 
     407        int stat, n; 
     408        if (strncmp(str, "+COPS: ", 7)) 
     409                goto final; 
     410        str += 7; 
     411 
     412        while (*str == '(') { 
     413                if (out) { 
     414                        out->is_last = 0; 
     415                        if (sscanf(str, 
     416                                                "(%i,\"%16[^\"]\"," 
     417                                                "\"%8[^\"]\",\"%6[0-9]\")%n", 
     418                                                &stat, 
     419                                                out->opname_longalpha, 
     420                                                out->opname_shortalpha, 
     421                                                out->opname_num, 
     422                                                &n) < 4) 
     423                                goto final; 
     424                        out->stat = stat; 
     425                } else 
     426                        if (sscanf(str, 
     427                                                "(%*i,\"%*[^\"]\"," 
     428                                                "\"%*[^\"]\",\"%*[0-9]\")%n", 
     429                                                &n) < 0) 
     430                                goto final; 
     431                if (n < 10 || str[n - 1] != ')') 
     432                        goto final; 
     433                if (str[n] == ',') 
     434                        n ++; 
     435                str += n; 
     436                len ++; 
     437                if (out) 
     438                        out ++; 
     439        } 
     440final: 
     441        if (out) 
     442                out->is_last = 1; 
     443        return len; 
     444} 
     445 
     446static int network_opers_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) 
     447{ 
     448        struct gsmd_user *gu = ctx; 
     449        struct gsmd_ucmd *ucmd; 
     450        int len; 
     451 
     452        len = network_opers_parse(resp, 0); 
     453 
     454        ucmd = gsmd_ucmd_fill(sizeof(struct gsmd_msg_oper) * (len + 1), 
     455                        GSMD_MSG_NETWORK, GSMD_NETWORK_OPER_LIST, 0); 
     456        if (!ucmd) 
     457                return -ENOMEM; 
     458 
     459        network_opers_parse(resp, (struct gsmd_msg_oper *) ucmd->buf); 
     460        usock_cmd_enqueue(ucmd, gu); 
     461 
     462        return 0; 
    401463} 
    402464 
     
    406468        struct gsmd_atcmd *cmd; 
    407469        struct gsmd_voicemail *vmail = (struct gsmd_voicemail *) gph->data; 
     470        gsmd_oper_numeric *oper = (gsmd_oper_numeric *) gph->data; 
     471        char buffer[15 + sizeof(gsmd_oper_numeric)]; 
     472        int cmdlen; 
    408473 
    409474        switch (gph->msg_subtype) { 
    410475        case GSMD_NETWORK_REGISTER: 
    411                 cmd = atcmd_fill("AT+COPS=0", 9+1, 
    412                                  &null_cmd_cb, gu, 0); 
     476                if ((*oper)[0]) 
     477                        cmdlen = sprintf(buffer, "AT+COPS=1,2,\"%.*s\"", 
     478                                        sizeof(gsmd_oper_numeric), oper); 
     479                else 
     480                        cmdlen = sprintf(buffer, "AT+COPS=0"); 
     481                cmd = atcmd_fill(buffer, cmdlen + 1, &null_cmd_cb, gu, 0); 
     482                break; 
     483        case GSMD_NETWORK_DEREGISTER: 
     484                cmd = atcmd_fill("AT+COPS=2", 9+1, &null_cmd_cb, gu, 0); 
    413485                break; 
    414486        case GSMD_NETWORK_VMAIL_GET: 
     
    422494                break; 
    423495        case GSMD_NETWORK_OPER_GET: 
     496                /* Set long alphanumeric format */ 
     497                atcmd_submit(gu->gsmd, atcmd_fill("AT+COPS=3,0", 11+1, 
     498                                        &null_cmd_cb, gu, 0)); 
    424499                cmd = atcmd_fill("AT+COPS?", 8+1, &network_oper_cb, gu, 0); 
     500                break; 
     501        case GSMD_NETWORK_OPER_LIST: 
     502                cmd = atcmd_fill("AT+COPS=?", 9+1, &network_opers_cb, gu, 0); 
    425503                break; 
    426504        default: 
  • trunk/src/target/gsm/src/libgsmd/lgsm_internals.h

    r114 r2713  
    33 
    44#include <gsmd/usock.h> 
     5#include <libgsmd/misc.h> 
    56 
    67struct lgsm_handle { 
    78        int fd; 
    89        lgsm_msg_handler *handler[__NUM_GSMD_MSGS]; 
     10        enum lgsm_netreg_state netreg_state; 
    911}; 
    1012 
  • trunk/src/target/gsm/src/libgsmd/libgsmd_event.c

    r546 r2713  
    6464                return -EINVAL; 
    6565 
     66        switch (gmh->msg_subtype) { 
     67        case GSMD_EVT_NETREG: 
     68                lh->netreg_state = aux->u.netreg.state; 
     69                break; 
     70        } 
     71 
    6672        if (evt_handlers[gmh->msg_subtype]) 
    6773                return evt_handlers[gmh->msg_subtype](lh, gmh->msg_subtype, aux); 
     
    7278int lgsm_evt_init(struct lgsm_handle *lh) 
    7379{ 
     80        lh->netreg_state = LGSM_NETREG_ST_NOTREG; 
    7481        return lgsm_register_handler(lh, GSMD_MSG_EVENT, &evt_demux_msghandler); 
    7582} 
  • trunk/src/target/gsm/src/libgsmd/libgsmd_network.c

    r547 r2713  
    3333#include "lgsm_internals.h" 
    3434 
    35 int lgsm_netreg_register(struct lgsm_handle *lh, int oper) 
     35/* Get the current network registration status */ 
     36int lgsm_get_netreg_state(struct lgsm_handle *lh, 
     37                enum lgsm_netreg_state *state) 
    3638{ 
    37         /* FIXME: implement oper selection */ 
    38         return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_REGISTER); 
     39        *state = lh->netreg_state; 
     40} 
     41 
     42int lgsm_oper_get(struct lgsm_handle *lh) 
     43{ 
     44        return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_OPER_GET); 
     45} 
     46 
     47int lgsm_opers_get(struct lgsm_handle *lh) 
     48{ 
     49        return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_OPER_LIST); 
     50} 
     51 
     52int lgsm_netreg_register(struct lgsm_handle *lh, gsmd_oper_numeric oper) 
     53{ 
     54        struct gsmd_msg_hdr *gmh; 
     55 
     56        gmh = lgsm_gmh_fill(GSMD_MSG_NETWORK, GSMD_NETWORK_REGISTER, 
     57                        sizeof(gsmd_oper_numeric)); 
     58        if (!gmh) 
     59                return -ENOMEM; 
     60 
     61        memcpy(gmh->data, oper, sizeof(gsmd_oper_numeric)); 
     62 
     63        if (lgsm_send(lh, gmh) < gmh->len + sizeof(*gmh)) { 
     64                lgsm_gmh_free(gmh); 
     65                return -EIO; 
     66        } 
     67 
     68        lgsm_gmh_free(gmh); 
     69        return 0; 
     70} 
     71 
     72int lgsm_netreg_deregister(struct lgsm_handle *lh) 
     73{ 
     74        return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_DEREGISTER); 
    3975} 
    4076 
     
    4379        return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_SIGQ_GET); 
    4480} 
    45  
    46 int lgsmd_operator_name(struct lgsm_handle *lh) 
    47 { 
    48         return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_OPER_GET); 
    49 } 
  • trunk/src/target/gsm/src/util/shell.c

    r2710 r2713  
    172172} 
    173173 
     174/* this is the handler for responses to network/operator commands */ 
     175static int net_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh) 
     176{ 
     177        const struct gsmd_signal_quality *sq = (struct gsmd_signal_quality *) 
     178                ((void *) gmh + sizeof(*gmh)); 
     179        const char *oper = (char *) gmh + sizeof(*gmh); 
     180        const struct gsmd_msg_oper *opers = (struct gsmd_msg_oper *) 
     181                ((void *) gmh + sizeof(*gmh)); 
     182        static const char *oper_stat[] = { 
     183                [GSMD_OPER_UNKNOWN] = "of unknown status", 
     184                [GSMD_OPER_AVAILABLE] = "available", 
     185                [GSMD_OPER_CURRENT] = "our current operator", 
     186                [GSMD_OPER_FORBIDDEN] = "forbidden", 
     187        }; 
     188 
     189        switch (gmh->msg_subtype) { 
     190        case GSMD_NETWORK_SIGQ_GET: 
     191                if (sq->rssi == 99) 
     192                        printf("Signal undetectable\n"); 
     193                else 
     194                        printf("Signal quality %i dBm\n", -113 + sq->rssi * 2); 
     195                if (sq->ber == 99) 
     196                        printf("Error rate undetectable\n"); 
     197                else 
     198                        printf("Bit error rate %i\n", sq->ber); 
     199                break; 
     200        case GSMD_NETWORK_OPER_GET: 
     201                if (oper[0]) 
     202                        printf("Our current operator is %s\n", oper); 
     203                else 
     204                        printf("No current operator\n"); 
     205                break; 
     206        case GSMD_NETWORK_OPER_LIST: 
     207                for (; !opers->is_last; opers ++) 
     208                        printf("%8.*s   %16.*s,   %.*s for short, is %s\n", 
     209                                        sizeof(opers->opname_num), 
     210                                        opers->opname_num, 
     211                                        sizeof(opers->opname_longalpha), 
     212                                        opers->opname_longalpha, 
     213                                        sizeof(opers->opname_shortalpha), 
     214                                        opers->opname_shortalpha, 
     215                                        oper_stat[opers->stat]); 
     216                break; 
     217        default: 
     218                return -EINVAL; 
     219        } 
     220} 
     221 
    174222static int shell_help(void) 
    175223{ 
     
    179227                "\tO\tPower On\n" 
    180228                "\to\tPower Off\n" 
    181                 "\tR\tRegister Network\n" 
     229                "\tr\tRegister to network\n" 
     230                "\tR\tRegister to given operator (R=number)\n" 
    182231                "\tU\tUnregister from netowrk\n" 
     232                "\tP\tPrint current operator\n" 
     233                "\tL\tDetect available operators\n" 
     234                "\tQ\tRead signal quality\n" 
    183235                "\tT\tSend DTMF Tone\n" 
    184236                "\tpd\tPB Delete (pb=index)\n" 
     
    209261        lgsm_register_handler(lgsmh, GSMD_MSG_PHONEBOOK, &pb_msghandler); 
    210262        lgsm_register_handler(lgsmh, GSMD_MSG_SMS, &sms_msghandler); 
     263        lgsm_register_handler(lgsmh, GSMD_MSG_NETWORK, &net_msghandler); 
    211264 
    212265        fcntl(0, F_SETFD, O_NONBLOCK); 
     
    273326                                printf("Power-Off\n"); 
    274327                                lgsm_phone_power(lgsmh, 0); 
    275                         } else if (!strcmp(buf, "R")) { 
     328                        } else if (!strcmp(buf, "r")) { 
    276329                                printf("Register\n"); 
    277                                 lgsm_netreg_register(lgsmh, 0); 
     330                                lgsm_netreg_register(lgsmh, "\0     "); 
     331                        } else if (buf[0] == 'R') { 
     332                                printf("Register to operator\n"); 
     333                                ptr = strchr(buf, '='); 
     334                                if (!ptr || strlen(ptr) < 6) 
     335                                        printf("No.\n"); 
     336                                else 
     337                                        lgsm_netreg_register(lgsmh, ptr + 1); 
    278338                        } else if (!strcmp(buf, "U")) { 
    279339                                printf("Unregister\n"); 
    280                                 lgsm_netreg_register(lgsmh, 2); 
     340                                lgsm_netreg_deregister(lgsmh); 
     341                        } else if (!strcmp(buf, "P")) { 
     342                                printf("Read current opername\n"); 
     343                                lgsm_oper_get(lgsmh); 
     344                        } else if (!strcmp(buf, "L")) { 
     345                                printf("List operators\n"); 
     346                                lgsm_opers_get(lgsmh); 
     347                        } else if (!strcmp(buf, "Q")) { 
     348                                printf("Signal strength\n"); 
     349                                lgsm_signal_quality(lgsmh); 
    281350                        } else if (!strcmp(buf, "q")) { 
    282351                                exit(0); 
Note: See TracChangeset for help on using the changeset viewer.