戒八 发表于 2013-1-3 16:54:33

C 简单实现LBS基站定位

C 简单实现LBS基站定位

<div id="cnblogs_post_body">   目前移动设备定位基本使用GPS的定位方式,使用基站定位的比较少,但是有些设备对定位要求不是很高或者需要节省掉gps芯片带来的成本,那么就可以考虑使用基站定位了。
   基站定位的原理很简单:就是访问Google服务器,告诉它我们的基站信息,服务器就会返回经纬度信息实现定位。那么我们只要知道基站信息是由什么组成的、如何组织Google服务器需要的基站信息,然后发送给Google服务器就好了。
    基站信息简单的说是由LAI(Location Area Identification) + CID(Cell Identity)组成的, LAI由(MCC +MNC+LAC)组成其中MCC全名Mobile Country Code,移动国家码,三位数,如中国为460。MNC全名Mobile Network Code,移动网络号,两位数。LAC全名Location Area Code,是一个2个字节长的十六进制BCD码(不包括0000和FFFE)。Cell Identity 小区码,同样是2个字节长的十六进制BCD码。我们只需要知道LAC和CID就可以完成定位。
    组消息发送给Google服务器时应注意要使用POST的方式向www.google.com/glm/mmap 提交请求内容,内容类型必须是Binary,其次内容格式是必须按照google规定的方式填充没什么好说的,注意网络字节序即可。
    在获取Google服务器返回的内容时,offset=7后的4个字节是latitude,offset=11后4个字节是longitude。
    下面是用C语言实现只依赖于C库很方便移植,本人在ARM平台及X86 linux下均测可用,同样可用于Android JNI。
<div class="cnblogs_Highlighter">/* * Copyright(c) 2010-2015 Beck. All rights reserved. * * Function : get latitude and longitude using cell identity and location area code * Author   : Beck <becklc@163.com> **/#include <stdio.h>#include <string.h>#include <netdb.h>#include <errno.h>#include <sys/socket.h>#define   HOSTNAME                  "www.google.com"#define   RequestHttpHeader         "POST /glm/mmap HTTP/1.1\x0D\x0A"\                                        "Content-Type: application/binary\x0D\x0A"\                                        "Host: www.google.com\x0D\x0A"\                                        "Content-Length: 55\x0D\x0A"\                                        "Expect: 100-continue\x0D\x0A"\                                        "Connection: Close\x0D\x0A\x0D\x0A"#define   ContentLenFlag            "\x0D\x0A""Content-Length:\x20"#define   SIZE_REQDATA    55typedef struct {    uint32_t cti;               /* Cell Identity */    uint32_t lac;               /* Location Area Code */    uint32_t mcc;               /* Mobile Country Code */    uint32_t mnc;               /* Mobile Network Code */} bsi_t;typedef struct {    bsi_t bsi;    uint8_t reqdata;    double latitude;    double longitude;} infos_t;static infos_t infos;int is_little_endian(){    int i = 1;    return (*(char *) &i == 1) ? 1 : 0;}static char *str2hex(const char *src, char *dec, int len){    char *hex = "0123456789ABCDEF";    char *ret = dec;    int i = 0;    if (NULL == src || NULL == dec)      return NULL;    for (i = 0; i < len; i++) {      *ret++ = hex[((*(src + i) & 0xF0) >> 4) & 0x0F];      *ret++ = hex[*(src + i) & 0x0F];      *ret++ = ' ';    }    return ret = dec;}static int connect_to_server(const char *strhost, uint16_t port){    struct hostent *host;    struct sockaddr_in serv_addr;    int hsocket = -1;    if ((host = gethostbyname(strhost)) == NULL) {      printf("%s, gethostbyname error, %s\n", __func__, strerror(errno));      return -1;    }    if ((hsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {      printf("%s, socket error, %s\n", __func__, strerror(errno));      return -1;    }    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(port);    serv_addr.sin_addr = *((struct in_addr *) host->h_addr);    memset(&(serv_addr.sin_zero), 0x0, 8);    if (connect(hsocket, (struct sockaddr *) &serv_addr,         sizeof(struct sockaddr)) == -1) {      printf("%s, connect error, %s\n", __func__, strerror(errno));      return -1;    }    return hsocket;}/* get the size of content from HttpServer */static int get_content_size(const char *recvdata, int recvdatalen){    /* check status is ok */    char *pok = NULL;    char *p = NULL, *end = NULL;    int value = 0, valuelen = 0, c;    if (NULL == (pok = strstr(recvdata, "OK"))) {      printf("Not find 'OK' flag in recv data.\n");      return -1;    }    /* find the flag Content-Length: in recvdata */    if (NULL == (p = strstr(recvdata, ContentLenFlag))) {      printf("Not find 'Content_Length' flag in recv data.\n");      return -1;    }    p = p + sizeof(ContentLenFlag) - 1;    /* find the end of Content-Length: */    if (NULL == (end = strstr(p, "\x0D\x0A"))) {      printf("Not find the end of 'Content_Length' in recv data.\n");      return -1;    }    /* str2int */    value = 0;    valuelen = end - p;    for (; valuelen > 0; valuelen--) {      if ((c = *p++ - '0') >= 10)            return -1;      value = value * 10 + c;    }    /* check the third number in content is 0x00 */    if (0x00 != recvdata) {      printf("the content in recv data is invalid.\n");      return -1;    }    return value;}static double getdata(uint8_t * pdata, int pos){    if (NULL == pdata)      return -1;    if (is_little_endian()) {      return ((double)((pdata << 24) | (pdata << 16) |               (pdata << 8) | (pdata))) / 1000000;    } else {      return ((double) (*(uint32_t *) & pdata)) / 1000000;    }}static int get_latitude_longitude(infos_t * p){    int hsocket = -1;    int pos = 0, len = 0, ret = 0;    int contentSize = 0;    char recvRsp = { 0 };    if ((hsocket = connect_to_server(HOSTNAME, 80)) == -1) {      printf("%s, connect to server error, %s\n", __func__,               strerror(errno));      ret = -1;      goto err;    }    if (-1 == send(hsocket, RequestHttpHeader, strlen(RequestHttpHeader), 0)) {      printf("%s, send RequestHttpHeader error, %s\n", __func__,               strerror(errno));      ret = -1;      goto err;    }    if (-1 == send(hsocket, p->reqdata, SIZE_REQDATA, 0)) {      printf("%s, send reqdata error, %s\n", __func__, strerror(errno));      ret = -1;      goto err;    }    while ((pos = recv(hsocket, recvRsp + len, sizeof(recvRsp) - len, 0)) > 0) {      len += pos;    }    contentSize = get_content_size(recvRsp, len);    p->latitude = getdata((uint8_t *) (recvRsp + len - contentSize), 7);    p->longitude = getdata((uint8_t *) (recvRsp + len - contentSize), 11);err:    close(hsocket);    return ret;}static int reqdata_init(infos_t * p){    p->reqdata= 0x0e;    p->reqdata = 0x1b;    /* wcdma unsame to gsm */    p->reqdata = ((uint64_t) p->bsi.cti > 65536) ? 5 : 3;    p->bsi.cti = htonl(p->bsi.cti);    p->bsi.lac = htonl(p->bsi.lac);    p->bsi.mcc = htonl(p->bsi.mcc);    p->bsi.mnc = htonl(p->bsi.mnc);    memcpy(p->reqdata + 17, &p->bsi.mnc, 4);    memcpy(p->reqdata + 21, &p->bsi.mcc, 4);    memcpy(p->reqdata + 31, &p->bsi.cti, 4);    memcpy(p->reqdata + 35, &p->bsi.lac, 4);    memcpy(p->reqdata + 39, &p->bsi.mnc, 4);    memcpy(p->reqdata + 43, &p->bsi.mcc, 4);    memset(p->reqdata + 47, 0xff, 4);    return 0;}int main(int argc, char *argv[]){    if (argc != 3) {      printf("usage <%s> : %s <CellTowerId> <LocationAreaCode>\n",               argv, argv);      return 0;    }    infos_t *p = infos;    memset(p, 0x0, sizeof(infos_t));    p->bsi.cti = (uint32_t) atoi(argv);    p->bsi.lac = (uint32_t) atoi(argv);    reqdata_init(p);    if (0 == get_latitude_longitude(p)) {      printf("latitude : %g, longitude : %g\n", p->latitude, p->longitude);    } else      printf("failed.\n");    return 0;}
页: [1]
查看完整版本: C 简单实现LBS基站定位