---
 drivers/ifxmodem/agps.c |  438 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 438 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ifxmodem/agps.c

diff --git a/drivers/ifxmodem/agps.c b/drivers/ifxmodem/agps.c
new file mode 100644
index 0000000..9b68b7e
--- /dev/null
+++ b/drivers/ifxmodem/agps.c
@@ -0,0 +1,438 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  Intel Corporation. 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 version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/agps.h>
+
+#include "util.h"
+#include "ifxmodem.h"
+
+struct agps_data {
+       GAtChat *chat;
+       unsigned int vendor;
+       enum ofono_access_technology rad_acc_tech;
+};
+
+struct ofono_agps;
+static enum ofono_access_technology rad_acc_tech;
+static const char *none_prefix[] = { NULL };
+
+#define FRAME_LEN 128
+
+static void pos_request_notify(GAtResult *result, gpointer user_data)
+{
+       struct ofono_agps *agps = user_data;
+       int framelen;
+       int frametype;
+       GAtResultIter iter;
+       struct ofono_lcs_frame lcsframe;
+       const char *messageframe;
+       unsigned char frame[FRAME_LEN];
+       long hexframelen;
+
+       /* Assuming Pos Req format: %XPOSR: <frametype>,<framelen>,<frame> */
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "%%XPOSR:"))
+               return;
+
+       if (!g_at_result_iter_next_number(&iter, &frametype))
+               return;
+
+       if (!g_at_result_iter_next_number(&iter, &framelen))
+               return;
+
+       if (framelen > FRAME_LEN) {
+               ofono_error("Got POS request msg more than max buffer size!");
+               return;
+       }
+
+       messageframe = g_at_result_pdu(result);
+
+       if (strlen(messageframe) > sizeof(frame) * 2) { /*Hex, 2 chars/byte*/
+               ofono_error("Message frame too long!");
+               return;
+       }
+
+       if (decode_hex_own_buf(messageframe, -1, &hexframelen, 0,
+                               frame) == NULL) {
+               ofono_error("Unable to hex-decode the AGPS frame");
+               return;
+       }
+
+       DBG("Got POS request data: %s, %ld", frame, hexframelen);
+
+       if (hexframelen != framelen) {
+               ofono_error("hexframelen not equal to reported framelen");
+               return;
+       }
+
+       lcsframe.lcs_frame_type = frametype;
+       lcsframe.frame_length = framelen;
+       lcsframe.raw_frame = (unsigned char *)frame;
+
+       ofono_agps_lcs_frame_notify(agps, lcsframe);
+}
+
+static void inj_time_notify(GAtResult *result, gpointer user_data)
+{
+
+       struct cb_data *cbd = user_data;
+       struct agps_data *agd = cbd->user;
+       ofono_agps_inject_time_cb_t cb = cbd->cb;
+       struct ofono_lcs_radio_fn rf;
+       struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
+       GAtResultIter iter;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "%%XFTI:"))
+               return;
+
+       if (RADIO_ACCESS_TECHNOLOGY_GSM == rad_acc_tech) {
+
+               int fn;         /* range 0 - 2715647 (2048*26*51) */
+               int ts;         /* range 0 - 7 */
+               int tsb;        /* range 0 - 156 */
+               int ta;         /* range 0 - 63 */
+               int ba;         /* range 0 - 1023 */
+               int bc;         /* range 0 - 64 */
+
+       /*       %XFTI:<frameNum>,<TimeSlot>,<TimeSlotBit>,<TimeAdv>,
+       *       <ChannelNum>,<ChannelId>
+       */
+               if (!g_at_result_iter_next_number(&iter, &fn))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &ts))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &tsb))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &ta))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &ba))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &bc))
+                       goto err;
+
+               DBG("GSM Inject Response: fn = %d ts = %d tsb = %d ta = %d"
+                               "ba = %d bc = %d ", fn, ts, tsb, ta, ba, bc);
+
+               rf.gsm_frame_number.TDMA_frame_number = fn;
+               rf.gsm_frame_number.TDMA_timeslot = ts;
+               rf.gsm_frame_number.timeslot_bit = tsb;
+               rf.gsm_frame_number.timing_advance = ta;
+               rf.gsm_frame_number.bcch_arfcn = ba;
+               rf.gsm_frame_number.bsic = bc;
+               rf.radio_access_technology = RADIO_ACCESS_TECHNOLOGY_GSM;
+
+       } else if (RADIO_ACCESS_TECHNOLOGY_UMTS == rad_acc_tech) {
+
+               int sfn;        /* range 0 - 4095 */
+               int rs;         /* enum ofono_rrc_state */
+               int rt;         /* range 0 - 32766 */
+
+               /* %XFTI:<frameNum>,<RadioState>,<TripTime> */
+               if (!g_at_result_iter_next_number(&iter, &sfn))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &rs))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &rt))
+                       goto err;
+
+               DBG("UMTS Inject Response: sfn = %d rs = %d tt = %d",
+                               sfn, rs, rt);
+
+               rf.utran_frame_number.sfn = sfn;
+               rf.utran_frame_number.rrc_state = rs;
+               rf.utran_frame_number.round_trip_time = rt;
+               rf.radio_access_technology = RADIO_ACCESS_TECHNOLOGY_UMTS;
+
+       } else
+               goto err;
+
+       cb(&error, &rf, cbd->data);
+       return;
+
+err:
+       CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+static int ifx_agps_probe(struct ofono_agps *agps,
+                                       unsigned int vendor, void *data)
+{
+       GAtChat *chat = data;
+       struct agps_data *agd = ofono_agps_get_data(agps);
+
+       agd = g_try_new0(struct agps_data, 1);
+       if (!agd)
+               return -ENOMEM;
+
+       agd->chat = g_at_chat_clone(chat);
+       agd->vendor = vendor;
+
+       ofono_agps_set_data(agps, agd);
+
+       g_at_chat_register(agd->chat, "%%XPOSR:", pos_request_notify, TRUE,
+                               agps, NULL);
+
+       ofono_agps_register(agps);
+
+       return 0;
+}
+
+static void ifx_agps_remove(struct ofono_agps *agps)
+{
+       struct agps_data *agd = ofono_agps_get_data(agps);
+
+       ofono_agps_remove(agps);
+       ofono_agps_set_data(agps, NULL);
+       g_at_chat_unref(agd->chat);
+       g_free(agd);
+}
+
+
+static void ifx_agps_receive_lcs_frame_cb(gboolean ok, GAtResult *result,
+                               gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_agps_receive_lcs_frame_cb_t cb = cbd->cb;
+       struct ofono_error error;
+
+       decode_at_error(&error, g_at_result_final_response(result));
+       cb(&error, cbd->data);
+}
+
+   /*
+       * The GPS manager can enable or disable AGPS manager  to receive
+       * lcs_frames from the Mobile network. If disabled, all Assistance Data
+       * and Position Requests from Mobile Network are not signalled to ofono.
+       */
+static void ifx_agps_receive_lcs_frames(struct ofono_agps *agps,
+                       int enabled, ofono_agps_receive_lcs_frame_cb_t cb,
+                       void *user_data)
+{
+       struct agps_data *data = ofono_agps_get_data(agps);
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       char *commbuf;
+       unsigned int id;
+
+       if (!cbd)
+               goto error;
+
+       commbuf = g_strdup_printf("AT%%XPOS=\"%d\"", enabled);
+
+       id = g_at_chat_send(data->chat, commbuf, none_prefix,
+                               ifx_agps_receive_lcs_frame_cb, cbd, g_free);
+
+       g_free(commbuf);
+
+       if (id > 0)
+               return;
+error:
+       if (cbd)
+               g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, user_data);
+}
+
+static void ifx_agps_send_lcs_frame_cb(gboolean ok, GAtResult *result,
+                               gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_agps_send_lcs_frame_cb_t cb = cbd->cb;
+       struct ofono_error error;
+
+       decode_at_error(&error, g_at_result_final_response(result));
+       cb(&error, cbd->data);
+}
+
+#define BUF_LEN 128
+
+       /* Assistance Data and Position Requests from the Mobile Network are
+        * signalled via the ofono_agps_lcs_frame_notify function and the
+        * oFono core to an external GPS manager. This GPS manager can reply
+        * to Position Requests with one or more Position Responses which
+        * are then send back to the modem via the send_lcs_frame function.
+        */
+static void ifx_agps_send_lcs_frame(struct ofono_agps *agps,
+                               struct ofono_lcs_frame *frame,
+                               ofono_agps_send_lcs_frame_cb_t cb,
+                               void *user_data)
+{
+       struct agps_data *data = ofono_agps_get_data(agps);
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       char buf[BUF_LEN * 2 + 1];
+       char *commbuf;
+       unsigned int id;
+       int buflen;
+
+       if (!cbd)
+               goto error;
+
+       if (!frame->frame_length) {
+               ofono_error("ifx_agps_send_lcs_frame: Frame length Invalid");
+               goto error;
+       }
+
+       if (frame->frame_length > BUF_LEN) {
+               ofono_error("ifx_agps_send_lcs_frame: Frame length too long!");
+               goto error;
+       }
+
+       encode_hex_own_buf(frame->raw_frame, frame->frame_length, 0, buf);
+       buflen = strlen(buf);
+       DBG("Encoded AGPS Frame = %s %d", buf, buflen);
+
+       commbuf = g_strdup_printf("AT%%XPOSR=%d,%d,\"%s\"",
+                       frame->lcs_frame_type, buflen, buf);
+
+       id = g_at_chat_send(data->chat, commbuf, none_prefix,
+                               ifx_agps_send_lcs_frame_cb, cbd, g_free);
+
+       g_free(commbuf);
+
+       if (id > 0)
+               return;
+error:
+       if (cbd)
+               g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, user_data);
+}
+
+static void ifx_agps_inject_time_cb(gboolean ok, GAtResult *result,
+                               gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       struct agps_data *data = cbd->user;
+       ofono_agps_inject_time_cb_t cb = cbd->cb;
+       struct ofono_error error;
+
+       decode_at_error(&error, g_at_result_final_response(result));
+
+       if (!ok)
+               goto err;
+
+       g_at_chat_register(agd->chat, "%%XFTI:",
+                                       inj_time_notify, FALSE,
+                                       data, g_free);
+       return;
+
+err:
+       cb(&error, NULL, cbd->data);
+       g_free(cbd);
+}
+
+       /* The GPS manager can ask the modem to generate a HW pulse (time
+        * stamp) with a defined length and the modem replies indicates when
+        * it generates the pulse. But as the modem has no precise idae of
+        * Universal Time, it indicates at which radio frame number itgc
+        * generated the pulse. The GPS manager which knows the link between
+        * Universal Time and the Radio Frame number knows very precisely at
+        * what time the pulse was generated and its duration.
+        *
+        * Timing accuracy is typically a few microseconds.
+        */
+static void ifx_agps_inject_time(struct ofono_agps *agps,
+                       int radio_access_technology,/* enum access_technology */
+                       int pulse_length,/* duration of pulse in radio slots */
+                       ofono_agps_inject_time_cb_t cb, void *user_data)
+{
+       struct agps_data *data = ofono_agps_get_data(agps);
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       char *buf;
+       unsigned int id;
+
+       if (!cbd)
+               goto error;
+
+       cbd->user = data;
+
+       if (radio_access_technology == RADIO_ACCESS_TECHNOLOGY_GSM) {
+               data->rad_acc_tech = radio_access_technology;
+               buf = g_strdup_printf("AT%%XFTI=\"%s%d\"", "GSM",
+                                               pulse_length);
+
+       } else if (radio_access_technology == RADIO_ACCESS_TECHNOLOGY_UMTS) {
+                       data->rad_acc_tech = radio_access_technology;
+                       buf = g_strdup_printf("AT%%XFTI=\"%s%d\"", "UMTS",
+                                               pulse_length);
+       } else
+               goto error;
+
+       id = g_at_chat_send(data->chat, buf, none_prefix,
+                   ifx_agps_inject_time_cb, cbd, g_free);
+
+       g_free(buf);
+
+       if (id > 0)
+               return;
+
+error:
+       if (cbd)
+               g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, NULL, user_data);
+}
+
+static struct ofono_agps_driver driver = {
+       .name                           = "ifxmodem",
+       .probe                          = ifx_agps_probe,
+       .remove                         = ifx_agps_remove,
+       .receive_lcs_frames             = ifx_agps_receive_lcs_frames,
+       .send_lcs_frame                 = ifx_agps_send_lcs_frame,
+       .inject_time                    = ifx_agps_inject_time
+};
+
+void ifx_agps_init()
+{
+       ofono_agps_driver_register(&driver);
+}
+
+void ifx_agps_exit()
+{
+       ofono_agps_driver_unregister(&driver);
+}
+
-- 
1.7.0.4

_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to