connections.c

Go to the documentation of this file.
00001 /*
00002  * File name: connections.c
00003  */
00004 
00005 /*
00006  * This file is part of sysd.
00007  *
00008  * sysd is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * sysd is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /*
00023  * Copyright (C) 2009 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 //----------------------------------------------------------------------------
00028 // Include Files
00029 //----------------------------------------------------------------------------
00030 
00031 #include "config.h"
00032 
00033 // system include files, between < >
00034 #include <glib.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <dirent.h>
00038 #include <sys/time.h>
00039 #include <sys/types.h>
00040 #include <sys/wait.h>
00041 #include <sys/stat.h>
00042 #include <utime.h>
00043 
00044 // ereader include files, between < >
00045 
00046 // local include files, between " "
00047 #include "log.h"
00048 #include "busy.h"
00049 #include "conf.h"
00050 #include "connections.h"
00051 #include "ipc.h"
00052 #include "process.h"
00053 
00054 #define UNUSED(x) (void)(x)
00055     
00056 
00057 //----------------------------------------------------------------------------
00058 // Type Declarations
00059 //----------------------------------------------------------------------------
00060  
00061 enum state_conn
00062 {
00063     CONN_STATE_OFF = 0,         // module in low power mode (but initialised)
00064     CONN_STATE_FLIGHTMODE,
00065     CONN_STATE_LOWBATT,
00066     CONN_STATE_LOADING,
00067     CONN_STATE_UNLOADING,
00068     CONN_STATE_CONNECTING,
00069     CONN_STATE_CONNECTED,
00070     CONN_STATE_DISCONNECTING,
00071     CONN_STATE_DISCONNECTED,
00072     CONN_STATE_INITIALISING,    // we've just returned from standby and are initialising
00073     CONN_STATE_INIT_WAITING,    // like initialising, but we must connect when done
00074 };
00075 
00076 typedef struct 
00077 {
00078     const gchar *medium;        // connection medium
00079     const gchar *application;   // command line to start the conn-mgr application
00080 } medium_t;
00081 
00082 
00083 //----------------------------------------------------------------------------
00084 // Global Constants
00085 //----------------------------------------------------------------------------
00086 
00087 static const gint TIMEOUT_STARTUP_COMPLETED  = 40; // seconds
00088 static const gint MIN_BATTERY_LEVEL_3G_START = 25; // minimum battery level (%) to *start* connection
00089 static const gint MIN_BATTERY_LEVEL_3G_KEEP  = 20; // minimum battery level (%) to *keep* connection
00090 
00091 
00092 #if WARNING_ON
00093 static const gchar *conn_state_str[] =
00094         {
00095             [CONN_STATE_OFF]           = "OFF",
00096             [CONN_STATE_FLIGHTMODE]    = "FLIGHTMODE",
00097             [CONN_STATE_LOWBATT]       = "LOWBATT",
00098             [CONN_STATE_LOADING]       = "LOADING",
00099             [CONN_STATE_UNLOADING]     = "UNLOADING",
00100             [CONN_STATE_CONNECTING]    = "CONNECTING",
00101             [CONN_STATE_CONNECTED]     = "CONNECTED",
00102             [CONN_STATE_DISCONNECTING] = "DISCONNECTING",
00103             [CONN_STATE_DISCONNECTED]  = "DISCONNECTED",
00104             [CONN_STATE_INITIALISING]  = "INITIALISING",      
00105             [CONN_STATE_INIT_WAITING]  = "INITWAITING",
00106         };
00107 #endif
00108 
00109 static const medium_t media_list[] =
00110     {
00111         // medium,      application
00112 #if MACHINE_IS_DR1000SW || MACHINE_IS_DR800SW
00113         { "wifi",      "/usr/bin/conn_wifi --background" },
00114         { "bluetooth", "/usr/bin/conn_blue --background" },
00115 #elif MACHINE_IS_DR800SG
00116         { "3g",        "/usr/bin/conn_3g --background"   },
00117 #endif
00118         { NULL, NULL }
00119     };
00120 
00121 
00122 typedef enum { REQ_CONNECT = 0, REQ_DISCONNECT, REQ_FLIGHTMODE, REQ_LOWBATT } Request;
00123 
00124 #if (LOGGING_ON)
00125 static const char* req_names[] =
00126         {
00127             [REQ_CONNECT]    = "REQ_CONNECT",
00128             [REQ_DISCONNECT] = "REQ_DISCONNECT",
00129             [REQ_FLIGHTMODE] = "REQ_FLIGHTMODE",
00130             [REQ_LOWBATT]    = "REQ_LOWBATT"
00131         };
00132 #endif
00133 
00134 //----------------------------------------------------------------------------
00135 // Static Variables
00136 //----------------------------------------------------------------------------
00137 
00138 static enum state_conn       g_conn_state            = CONN_STATE_OFF;
00139 static Request               g_request               = REQ_DISCONNECT;    // direction to go
00140 static proc_t                *g_service              = NULL;
00141 static gchar                 *g_medium               = "3g";
00142 static gchar                 *g_profile              = NULL;
00143 static gchar                 *g_disconnect_reason    = NULL;
00144 static guint                 g_starting_source       = 0;
00145 static GSList                *g_app_list             = NULL;
00146 
00147 
00148 //============================================================================
00149 // Local Function Definitions
00150 //============================================================================
00151 
00152 static void start_medium(const char *medium);
00153 static void stop_medium(void);
00154 static gboolean on_service_starting_timeout(gpointer data);
00155 static void enter_disconnected_state();
00156 static void enter_off_state();
00157 static void conn_enable_lowbatt();
00158 static void conn_disable_lowbatt();
00159 static void conn_set_lowbatt(gboolean is_enabled);
00160 
00161 #define set_string( str, val ) { g_free(str); str = g_strdup(val); }
00162 
00163 
00164 //============================================================================
00165 // Local Function Implementation
00166 //============================================================================
00167 
00168 #define EPA_INFO_FILE "/home/root/epa.txt"
00169 
00170 static gint get_cooloff()
00171 {
00172     float level;
00173     gint cooloff = 0;
00174     gint sec2wait = 0;
00175     
00176     FILE *f = fopen(EPA_INFO_FILE, "rb");
00177     if (f)
00178     {
00179         fscanf(f, "level: %f %%\n", &level);
00180         fscanf(f, "cool-off: %d sec", &cooloff);
00181         LOGPRINTF("level: %f, cool-off: %d", level, cooloff);
00182         fclose(f);
00183     }
00184 
00185     if (cooloff > 0)
00186     {
00187         struct stat st;
00188         struct timeval now;
00189         stat(EPA_INFO_FILE, &st);
00190         gettimeofday(&now, NULL);
00191         
00192         if (st.st_mtime > now.tv_sec)
00193         {
00194             // clock was set back after EPA_INFO_FILE was written,
00195             // touch file to make sure the cool off time will be reached
00196             utime(EPA_INFO_FILE, NULL);
00197             sec2wait = cooloff;
00198         }
00199         else
00200         {
00201             sec2wait = (st.st_mtime + cooloff) - now.tv_sec;
00202             if (sec2wait < 0)
00203             {
00204                 // cooloff time has already passed
00205                 sec2wait = 0;
00206             }
00207         }
00208         LOGPRINTF("now: %ld, file: %ld, sec2wait: %d", now.tv_sec, st.st_mtime, sec2wait);
00209     }
00210 
00211     return sec2wait;
00212 }
00213 
00214 
00215 static gint app_count()
00216 {
00217     return g_slist_length(g_app_list);
00218 }
00219 
00220 
00221 static void app_add(const char *ipc_service)
00222 {
00223     LOGPRINTF("entry: %s", ipc_service);
00224 
00225     GSList *li = g_app_list;
00226     
00227     while ( (li != NULL) && (li->data != NULL) )
00228     {
00229         if (strcmp(li->data, ipc_service) == 0)
00230         {
00231             return;
00232         }
00233         li = li->next;
00234     }
00235 
00236     // not found, add to list
00237     g_app_list = g_slist_prepend(g_app_list, g_strdup(ipc_service));
00238 }
00239 
00240 
00241 static void app_remove_all()
00242 {
00243     LOGPRINTF("entry");
00244     g_slist_free(g_app_list);
00245     g_app_list = NULL;
00246 }
00247 
00248 
00249 static void app_remove(const char *ipc_service)
00250 {
00251     LOGPRINTF("entry: %s", ipc_service);
00252 
00253     GSList *li = g_app_list;
00254     
00255     while ( (li != NULL) && (li->data != NULL) )
00256     {
00257         if (strcmp(li->data, ipc_service) == 0)
00258         {
00259             // app found, delete from list
00260             g_free(li->data);
00261             g_app_list = g_slist_delete_link(g_app_list, li);
00262             return;
00263         }
00264         li = li->next;
00265     }
00266 }
00267 
00268 
00269 static const gchar *medium_application(const char *medium)
00270 {
00271     const medium_t *p_medlst;   // pointer in media_list[]
00272 
00273     LOGPRINTF("entry: %s", medium);
00274     
00275     for (p_medlst = media_list ; p_medlst->medium ; p_medlst++)
00276     {
00277         if (strcmp(p_medlst->medium, medium) == 0)
00278         {
00279             return p_medlst->application;
00280         }
00281     }
00282     return NULL;
00283 }
00284 
00285 
00286 #if MACHINE_IS_DR800SG
00287 static void on_3g_ready(GPid pid, gint status, gpointer data)
00288 {
00289     if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
00290     {
00291         LOGPRINTF("3G should be ready");
00292         conn_set_initialising(FALSE);
00293     }
00294     else
00295     {
00296         LOGPRINTF("abnormal exit status, ignore 3G ready");
00297     }
00298 }
00299 #endif
00300 
00301 
00302 void conn_on_enter_standby(void)
00303 {
00304 #if MACHINE_IS_DR800SG
00305     if (g_conn_state != CONN_STATE_FLIGHTMODE) {
00306         LOGPRINTF("Disabling 3g");
00307         sys_spawn_sync("3g_off.sh");
00308     }
00309 #endif
00310 }
00311 
00312 
00313 void conn_on_leave_standby(void)
00314 {
00315 #if MACHINE_IS_DR800SG
00316     if (g_conn_state != CONN_STATE_FLIGHTMODE) {
00317         LOGPRINTF("Enabling 3g");
00318         conn_set_initialising(TRUE);
00319         sys_spawn_async_with_callback("3g_boot.sh", on_3g_ready, NULL);
00320     }
00321 #endif
00322 }
00323 
00324 
00325 static void set_request(Request req)
00326 {
00327     LOGPRINTF("from %s -> %s", req_names[g_request], req_names[req]);
00328     g_request = req;
00329 }
00330 
00331 
00332 static void set_conn_state(enum state_conn new_state)
00333 {
00334     LOGPRINTF("changing state %s -> %s", conn_state_str[g_conn_state], conn_state_str[new_state]);
00335     g_conn_state = new_state;
00336 }
00337 
00338 
00339 gboolean conn_is_online(void)
00340 {
00341     return (g_conn_state == CONN_STATE_CONNECTED);
00342 }
00343 
00344 
00345 gboolean conn_is_initialising(void)
00346 {
00347     return (g_conn_state == CONN_STATE_INITIALISING || 
00348             g_conn_state == CONN_STATE_INIT_WAITING);
00349 }
00350 
00351 
00352 gboolean conn_is_stopped()
00353 {
00354     return (g_conn_state == CONN_STATE_OFF || 
00355             g_conn_state == CONN_STATE_FLIGHTMODE || 
00356             g_conn_state == CONN_STATE_LOWBATT || 
00357             g_conn_state == CONN_STATE_INITIALISING ||
00358             g_conn_state == CONN_STATE_INIT_WAITING);
00359 }
00360 
00361 
00362 void conn_check_battery(gint level)
00363 {
00364     static gboolean warning_shown = FALSE;
00365 
00366     if (level < MIN_BATTERY_LEVEL_3G_KEEP)
00367     {
00368         conn_enable_lowbatt();
00369     }
00370     else if ((level <= MIN_BATTERY_LEVEL_3G_KEEP) && conn_is_online())
00371     {
00372         if (!warning_shown)
00373         {
00374             // show pre warning when nearing minimum battery level
00375             ipc_show_message("3glowwarning", NULL, NULL);
00376             warning_shown = TRUE;
00377         }
00378     }
00379     else
00380     {
00381         conn_disable_lowbatt();
00382         if (warning_shown)
00383         {
00384             warning_shown = FALSE;
00385         }
00386     }
00387 }
00388 
00389 
00390 static void clear_starting_source()
00391 {
00392     if (g_starting_source > 0)
00393     {
00394         g_source_remove(g_starting_source);
00395         g_starting_source = 0;
00396     }
00397 }
00398 
00399 
00400 static void on_medium_started(void)
00401 {
00402     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
00403     
00404     if (!g_service)
00405     {
00406         ERRORPRINTF("Huh? startupComplete received but no service running. Ignored.");
00407         return;
00408     }
00409     if (g_starting_source == 0)
00410     {
00411         ERRORPRINTF("Huh? startupComplete received but no timer running. Timed out?");
00412         return;
00413     }
00414 
00415     g_assert(g_conn_state == CONN_STATE_LOADING);
00416     clear_starting_source();
00417     enter_disconnected_state();
00418 
00419 }
00420 
00421 
00422 static void on_medium_exited(void)
00423 {
00424     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
00425     
00426     clear_starting_source();
00427 
00428     // service (process) not present anymore
00429     g_service = NULL;
00430 
00431 #if MACHINE_IS_DR800SG
00432     {
00433         // callout to bring down medium (unload modules, suspend or disable power)
00434         gchar *command = g_strconcat(g_medium, "_stop.sh", NULL);
00435         sys_spawn_sync(command);
00436         g_free(command);
00437     }
00438 #endif
00439     
00440     switch (g_conn_state)
00441     {
00442         case CONN_STATE_OFF:
00443         case CONN_STATE_LOWBATT:
00444             LOGPRINTF("already in state %s", conn_state_str[g_conn_state]);
00445             break;
00446         
00447         case CONN_STATE_FLIGHTMODE:
00448             // turn off power to module in flightmode (same is in device standby)
00449             conn_on_enter_standby();
00450             break;
00451 
00452         case CONN_STATE_INITIALISING:
00453         case CONN_STATE_INIT_WAITING:
00454         case CONN_STATE_LOADING:
00455         case CONN_STATE_CONNECTING:
00456         case CONN_STATE_CONNECTED:
00457         case CONN_STATE_DISCONNECTING:
00458         case CONN_STATE_DISCONNECTED:
00459             WARNPRINTF("Medium EXITED unexpectedly, turning off");
00460             set_string(g_disconnect_reason, "connect-failed");
00461             if (g_request == REQ_CONNECT) set_request(REQ_DISCONNECT);
00462             enter_off_state();
00463             break;
00464 
00465         case CONN_STATE_UNLOADING:
00466             enter_off_state();
00467             break;
00468     }
00469 }
00470 
00471 
00472 static void start_medium(const char *medium)
00473 {
00474     LOGPRINTF("entry - medium [%s]", medium);
00475     
00476     g_assert(medium);
00477     if (g_service)
00478     {
00479         ERRORPRINTF("Huh? A service (%s) is still running. Ignored.", g_service->command);
00480         return;
00481     }
00482 
00483     // callout to bring up medium (load modules, wakeup or enable power)
00484     gchar *command = g_strconcat(g_medium, "_start.sh", NULL);
00485     sys_spawn_sync(command);
00486     g_free(command);
00487     
00488     // start connection manager for medium
00489     g_service = process_start( medium_application(g_medium),
00490                                NULL,
00491                                G_CALLBACK(on_medium_started),
00492                                G_CALLBACK(on_medium_exited),
00493                                PS_WAIT_STARTED );
00494     if (g_service != NULL) {
00495         g_starting_source = g_timeout_add_seconds(TIMEOUT_STARTUP_COMPLETED, on_service_starting_timeout, NULL);
00496     } else {
00497         ERRORPRINTF("cannot start medium %s", medium_application(g_medium));
00498     }
00499 }
00500 
00501 
00502 static void stop_medium(void)
00503 {
00504     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
00505     
00506     clear_starting_source();
00507 
00508     app_remove_all();
00509 
00510     if (g_service)
00511     {
00512         LOGPRINTF("stopping g_medium [%s] pid [%d]", g_medium, g_service->pid);
00513         process_stop(g_service);
00514     }
00515 }
00516 
00517 
00518 static gboolean on_service_starting_timeout(gpointer data)
00519 {
00520     UNUSED(data);
00521     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
00522     g_assert(g_conn_state == CONN_STATE_LOADING);
00523     stop_medium();
00524     set_request(REQ_DISCONNECT);
00525     set_conn_state(CONN_STATE_UNLOADING);
00526 
00527     return FALSE;  // don't call again
00528 }
00529 
00530 static void force_statusbar_state(char *state)
00531 {
00532     gchar *icon = g_strdup_printf("statusbar_%s", g_medium);
00533     ipc_menu_set_statusitem_state(icon, state);
00534     g_free(icon);
00535 }
00536 
00537 
00538 void conn_update_statusbar()
00539 {
00540     const char* state = NULL;
00541     switch (g_conn_state) {
00542     case CONN_STATE_INITIALISING:
00543     case CONN_STATE_INIT_WAITING:
00544         state = "disabled";
00545         break;
00546     case CONN_STATE_FLIGHTMODE:
00547         state = "flightmode";
00548         break;
00549     case CONN_STATE_CONNECTED:
00550         state = "connected";
00551         break;
00552     case CONN_STATE_OFF:
00553     case CONN_STATE_LOWBATT:
00554     case CONN_STATE_LOADING:
00555     case CONN_STATE_UNLOADING:
00556     case CONN_STATE_CONNECTING:
00557     case CONN_STATE_DISCONNECTED:
00558     case CONN_STATE_DISCONNECTING:
00559         state = "disconnected";
00560         break;
00561     }
00562     gchar *icon = g_strdup_printf("statusbar_%s", g_medium);
00563     ipc_menu_set_statusitem_state(icon, state);
00564     g_free(icon);
00565 }
00566 
00567 
00568 void conn_set_initialising(gboolean is_init)
00569 {
00570     LOGPRINTF("entry [%d]", is_init);
00571 
00572     if (is_init) {
00573         // if we're initialising, just set the state
00574         set_conn_state(CONN_STATE_INITIALISING);
00575     } else {
00576         if (g_request == REQ_FLIGHTMODE) {
00577             // flight mode was enabled during init, shut it down
00578             WARNPRINTF("Flightmode was requested, but we were initialising. Shutting down");
00579             conn_on_enter_standby();
00580             set_conn_state(CONN_STATE_FLIGHTMODE);
00581             conn_update_statusbar();
00582         } else if (g_conn_state==CONN_STATE_INIT_WAITING) {
00583             // connection requested, go immediately to connecting
00584             LOGPRINTF("3G now ready, starting");
00585             busy_remove_foreground(0);
00586             set_conn_state(CONN_STATE_LOADING);
00587             set_request(REQ_CONNECT);
00588             start_medium("3g");
00589         } else {
00590             // no connection requested, just go to off
00591             LOGPRINTF("3G now ready");
00592             set_conn_state(CONN_STATE_OFF);
00593         }
00594     }
00595 }
00596 
00597 
00598 static void enter_connected_state()
00599 {
00600     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
00601     set_conn_state(CONN_STATE_CONNECTED);
00602     set_string(g_disconnect_reason, NULL);
00603 
00604     switch (g_request) {
00605     case REQ_FLIGHTMODE:
00606         LOGPRINTF("got flightmode request while connecting...disconnecting");
00607         set_conn_state(CONN_STATE_DISCONNECTING);
00608         ipc_disconnect(g_service->ipc_service);
00609         break;
00610     case REQ_LOWBATT:
00611         LOGPRINTF("got lowbattery request while connecting...disconnecting");
00612         set_conn_state(CONN_STATE_DISCONNECTING);
00613         ipc_disconnect(g_service->ipc_service);
00614         break;
00615     case REQ_CONNECT:
00616         // goal achieved, done
00617         ipc_broadcast_conn_status(TRUE, g_medium, g_profile, NULL);
00618         sys_update_rgb_led();
00619         conn_update_statusbar();
00620         break;
00621     case REQ_DISCONNECT:
00622         LOGPRINTF("got disconnect request while connecting...disconnecting");
00623         set_conn_state(CONN_STATE_DISCONNECTING);
00624         ipc_disconnect(g_service->ipc_service);
00625         break;
00626     }
00627 }
00628 
00629 
00630 static void enter_disconnected_state()
00631 {
00632     LOGPRINTF("state=%s  req=%s  g_medium=%s", conn_state_str[g_conn_state],
00633             req_names[g_request], g_medium ? g_medium : "NULL");
00634     set_conn_state(CONN_STATE_DISCONNECTED);
00635     conn_update_statusbar();
00636     sys_update_rgb_led();
00637 
00638     switch (g_request) {
00639     case REQ_CONNECT:
00640         set_conn_state(CONN_STATE_CONNECTING);
00641         ipc_connect(g_service->ipc_service, g_medium, g_profile);
00642         break;
00643     case REQ_FLIGHTMODE:
00644     case REQ_LOWBATT:
00645     case REQ_DISCONNECT:
00646         set_conn_state(CONN_STATE_UNLOADING);
00647         stop_medium();
00648         break;
00649     }
00650 }
00651 
00652 
00653 static void enter_off_state()
00654 {
00655     LOGPRINTF("state=%s  req=%s  g_medium=%s", conn_state_str[g_conn_state],
00656             req_names[g_request], g_medium ? g_medium : "NULL");
00657 
00658     enum state_conn old_state = g_conn_state;
00659     set_conn_state(CONN_STATE_OFF);
00660     conn_update_statusbar();
00661     sys_update_rgb_led();
00662     if (old_state != CONN_STATE_FLIGHTMODE)
00663     {
00664         ipc_broadcast_conn_status(FALSE, g_medium, g_profile, "connect-failed");
00665     }
00666     else if (g_request==REQ_DISCONNECT)
00667     {
00668         LOGPRINTF("old state is flight mode and disconnect request -> reenable 3g");
00669         conn_on_leave_standby();
00670     }
00671 
00672     switch (g_request) {
00673     case REQ_DISCONNECT:
00674         LOGPRINTF("unloading done, state is OFF -- reason [%s]", g_disconnect_reason);
00675         if (g_disconnect_reason && strcmp(g_disconnect_reason, "sar-limit-reached")==0)
00676         {
00677             ipc_show_message("3gsarlimit", NULL, NULL);
00678         }
00679         break;
00680     case REQ_LOWBATT:
00681         LOGPRINTF("unloading done, state lowbatt");
00682         conn_set_lowbatt(TRUE);
00683         break;
00684     case REQ_FLIGHTMODE:
00685         LOGPRINTF("unloading done, setting flightmode");
00686         conn_set_flightmode(TRUE);
00687         break;
00688     case REQ_CONNECT:
00689         LOGPRINTF("connect request during unloading, loading");
00690         set_conn_state(CONN_STATE_LOADING);
00691         // NOTE: hardcoded
00692         start_medium("3g");
00693         break;
00694     }
00695 }
00696 
00697 
00698 //============================================================================
00699 // Function Implementation
00700 //============================================================================
00701 
00702 static void on_flightmode_dialog_return(eripc_context_t *context,
00703                                         const eripc_event_info_t *info,
00704                                         void  *user_data)
00705 {
00706     UNUSED(context);
00707     UNUSED(info);
00708     LOGPRINTF("entry");
00709     gchar *ipc_service = user_data;
00710     ipc_send_conn_status(ipc_service, FALSE, g_medium, g_profile, "flightmode");
00711     g_free(ipc_service);
00712 }
00713 
00714 
00715 static void on_lowbatt_dialog_return(eripc_context_t *context,
00716                                      const eripc_event_info_t *info,
00717                                      void  *user_data)
00718 {
00719     UNUSED(context);
00720     UNUSED(info);
00721     LOGPRINTF("entry");
00722     gchar *ipc_service = user_data;
00723     ipc_send_conn_status(ipc_service, FALSE, g_medium, g_profile, "lowbattery");
00724     g_free(ipc_service);
00725 }
00726 
00727 
00728 // received connConnect from application
00729 gboolean conn_connect(const char *ipc_service, const char *medium, const char *profile)
00730 {
00731     gboolean retval = FALSE;
00732     int cooloff = get_cooloff();
00733 
00734     LOGPRINTF("state=%s  req=%s  medium=[%s]  profile=[%s]", conn_state_str[g_conn_state],
00735             req_names[g_request], medium ? medium : "NULL", profile ? profile : "NULL");
00736         
00737     if (g_conn_state==CONN_STATE_INITIALISING)
00738     {
00739         LOGPRINTF("Connection still initialising, waiting until complete");
00740         busy_add_foreground(0, BUSY_DIALOG_DIRECT, NULL);
00741         set_conn_state(CONN_STATE_INIT_WAITING);
00742         return TRUE;
00743     }
00744 
00745     // it's possible to open new connections when already online
00746     // but don't start new connections when OFFLINE and below MIN_BATTERY_LEVEL_3G_START
00747     if (g_conn_state == CONN_STATE_OFF && sys_battery_level() < MIN_BATTERY_LEVEL_3G_START)
00748     {
00749         ipc_show_message("3glowconnect", on_lowbatt_dialog_return, g_strdup(ipc_service));
00750         return FALSE;
00751     }
00752 
00753     if (cooloff > 0)
00754     {
00755         LOGPRINTF("Need to cool off for another %d minutes [%d]", (cooloff+60-1) / 60, cooloff);
00756         gchar *message = g_strdup_printf("3gcooloff_%d", (cooloff+60-1) / 60);
00757         ipc_show_message(message, on_lowbatt_dialog_return, g_strdup(ipc_service));
00758         g_free(message);
00759         return FALSE;
00760     }
00761     
00762     if (g_conn_state != CONN_STATE_FLIGHTMODE) {
00763         app_add(ipc_service);
00764         set_string(g_profile, profile);     // not used
00765     }
00766 
00767     // on emulator: always return connected
00768     if (sys_is_emulator() && g_conn_state != CONN_STATE_FLIGHTMODE) {
00769         WARNPRINTF("emulator mode");
00770         ipc_send_conn_status(ipc_service, TRUE, medium, profile, NULL);
00771         return TRUE;
00772     }
00773 
00774     switch (g_conn_state) {
00775     case CONN_STATE_INITIALISING:
00776     case CONN_STATE_INIT_WAITING:
00777         break;
00778     case CONN_STATE_OFF:
00779         set_conn_state(CONN_STATE_LOADING);
00780         set_request(REQ_CONNECT);
00781         start_medium(medium);
00782         retval = TRUE;
00783         break;
00784     case CONN_STATE_LOWBATT:
00785         ipc_show_message("3glowconnect", on_lowbatt_dialog_return, g_strdup(ipc_service));
00786         break;
00787     case CONN_STATE_FLIGHTMODE:
00788         ipc_show_message("flightmode", on_flightmode_dialog_return, g_strdup(ipc_service));
00789         break;
00790     case CONN_STATE_DISCONNECTED:
00791         set_conn_state(CONN_STATE_CONNECTING);
00792         set_request(REQ_CONNECT);
00793         ipc_connect(g_service->ipc_service, medium, profile);
00794         retval = TRUE;
00795         break;
00796     case CONN_STATE_CONNECTED:
00797         ipc_send_conn_status(ipc_service, TRUE, medium, profile, NULL);
00798         retval = TRUE;
00799         break;
00800     case CONN_STATE_LOADING:
00801     case CONN_STATE_UNLOADING:
00802     case CONN_STATE_CONNECTING:
00803     case CONN_STATE_DISCONNECTING:
00804         set_request(REQ_CONNECT);
00805         retval = TRUE;
00806         break;
00807     default:
00808         WARNPRINTF("unhandled state [%d]", g_conn_state);
00809         break;
00810     }
00811     return retval;
00812 }
00813 
00814 
00815 // received connDisconnect from application
00816 gboolean conn_disconnect(const char *ipc_service)
00817 {
00818     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
00819     
00820     app_remove(ipc_service);
00821 
00822     if (sys_is_emulator()) {
00823         WARNPRINTF("emulator mode");
00824         ipc_send_conn_status(ipc_service, FALSE, g_medium, g_profile, NULL);
00825         return TRUE;
00826     }
00827 
00828     switch (g_conn_state) {
00829     case CONN_STATE_INITIALISING:
00830     case CONN_STATE_INIT_WAITING:
00831     case CONN_STATE_OFF:
00832     case CONN_STATE_FLIGHTMODE:
00833     case CONN_STATE_LOWBATT:
00834     case CONN_STATE_DISCONNECTED:
00835         LOGPRINTF("got disconnect request in state %s - cleanup", conn_state_str[g_conn_state]);
00836         return FALSE;
00837     case CONN_STATE_CONNECTED:
00838         if (app_count() == 0) {
00839             // no applications using connection, disconnect
00840             set_conn_state(CONN_STATE_DISCONNECTING);
00841             set_request(REQ_DISCONNECT);
00842             ipc_disconnect(g_service->ipc_service);
00843         }
00844         break;
00845     case CONN_STATE_LOADING:
00846     case CONN_STATE_UNLOADING:
00847     case CONN_STATE_CONNECTING:
00848         if (app_count() == 0) {
00849             set_request(REQ_DISCONNECT);
00850         }
00851         return TRUE;
00852     case CONN_STATE_DISCONNECTING:
00853         if (app_count() == 0) {
00854             set_request(REQ_DISCONNECT);
00855             // try to cancel connecting by sending disconnect to ConnMgr
00856             LOGPRINTF("trying to cancel conn. mgr");
00857             ipc_disconnect(g_service->ipc_service);
00858         }
00859         return TRUE;
00860     }
00861     return FALSE;
00862 }
00863 
00864 
00865 static gboolean handle_connected_event(const char* medium, const char* profile)
00866 {
00867     LOGPRINTF("state=%s  req=%s  medium=[%s]  profile=[%s]", conn_state_str[g_conn_state],
00868             req_names[g_request], medium ? medium : "NULL", profile ? profile : "NULL");
00869     g_assert(g_service);
00870     int rc = FALSE;
00871 
00872     switch (g_conn_state) {
00873         case CONN_STATE_INITIALISING:
00874         case CONN_STATE_INIT_WAITING:
00875         case CONN_STATE_OFF:
00876         case CONN_STATE_FLIGHTMODE:
00877         case CONN_STATE_LOWBATT:
00878         case CONN_STATE_DISCONNECTED:
00879         case CONN_STATE_CONNECTED:
00880         case CONN_STATE_LOADING:
00881         case CONN_STATE_UNLOADING:
00882         case CONN_STATE_DISCONNECTING:
00883             WARNPRINTF("received status CONNECTED %s/%s but state is %s. Ignored.", medium, profile, conn_state_str[g_conn_state]);
00884             return FALSE;
00885             break;
00886         case CONN_STATE_CONNECTING:
00887             enter_connected_state();
00888             rc = TRUE;
00889             break;
00890     }
00891     return rc;
00892 }
00893 
00894 
00895 static gboolean handle_disconnected_event(const char* medium, const char* profile, const char* reason)
00896 {
00897     LOGPRINTF("state=%s  req=%s  reason=%s", conn_state_str[g_conn_state],
00898             req_names[g_request], reason ? reason : "NULL");
00899     int rc = FALSE;
00900 
00901     set_string(g_disconnect_reason, reason);
00902     switch (g_conn_state) {
00903         case CONN_STATE_INITIALISING:
00904         case CONN_STATE_INIT_WAITING:
00905         case CONN_STATE_OFF:
00906         case CONN_STATE_FLIGHTMODE:
00907         case CONN_STATE_LOWBATT:
00908         case CONN_STATE_DISCONNECTED:
00909         case CONN_STATE_LOADING:
00910         case CONN_STATE_UNLOADING:
00911             WARNPRINTF("received status DISCONNECTED %s/%s but state is %s. Ignored.", medium, profile, conn_state_str[g_conn_state]);
00912             break;
00913         case CONN_STATE_CONNECTED:
00914             set_request(REQ_DISCONNECT);
00915             enter_disconnected_state();
00916             break;
00917         case CONN_STATE_DISCONNECTING:
00918             enter_disconnected_state();
00919             rc = TRUE;
00920             break;
00921         case CONN_STATE_CONNECTING:
00922             WARNPRINTF("connecting failed, request disconnect");
00923             set_request(REQ_DISCONNECT);
00924             enter_disconnected_state();
00925             break;
00926     }
00927     return rc;
00928 }
00929 
00930 
00931 // received connConnectionStatus from connection manager
00932 gboolean conn_set_status(gboolean is_connected, const char *medium, const char *profile, const char* reason)
00933 {
00934     int rc = FALSE;
00935     if (is_connected) {
00936         rc = handle_connected_event(medium, profile);
00937     } else {
00938         rc = handle_disconnected_event(medium, profile, reason);
00939     }
00940     return rc;
00941 }
00942 
00943 
00944 // received connConnectionStatusRequest from application
00945 gboolean conn_status_request(const char *ipc_service)
00946 {
00947     gboolean rc = FALSE;
00948     
00949     LOGPRINTF("entry");
00950 
00951     switch (g_conn_state)
00952     {
00953         case CONN_STATE_CONNECTED:
00954             ipc_send_conn_status(ipc_service, TRUE, g_medium, g_profile, "");
00955             rc = TRUE;
00956             break;
00957                    
00958         case CONN_STATE_INITIALISING:
00959         case CONN_STATE_INIT_WAITING:
00960         case CONN_STATE_OFF:
00961         case CONN_STATE_FLIGHTMODE:
00962         case CONN_STATE_LOWBATT:
00963         case CONN_STATE_DISCONNECTED:
00964             ipc_send_conn_status(ipc_service, FALSE, NULL, NULL, g_disconnect_reason);
00965             rc = TRUE;
00966             break;
00967 
00968         case CONN_STATE_LOADING:
00969         case CONN_STATE_UNLOADING:
00970         case CONN_STATE_CONNECTING:
00971         case CONN_STATE_DISCONNECTING:
00972             WARNPRINTF("Received status request but state is %s. Status will follow", conn_state_str[g_conn_state]);
00973             break;
00974     }
00975     return rc;
00976 }
00977 
00978 
00979 // received connAddProfile from application
00980 gboolean conn_add_profile(const char *medium)
00981 {
00982     UNUSED(medium);
00983     LOGPRINTF("entry");
00984     return FALSE;
00985 }
00986 
00987 
00988 // received connEditProfile from application
00989 gboolean conn_edit_profile(const char *medium, const char *profile)
00990 {
00991     UNUSED(medium);
00992     UNUSED(profile);
00993     LOGPRINTF("entry");
00994     return FALSE;
00995 }
00996 
00997 
00998 static void conn_enable_lowbatt()
00999 {
01000     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
01001     switch (g_conn_state)
01002     {
01003         case CONN_STATE_OFF:
01004             set_request(REQ_LOWBATT);
01005             set_conn_state(CONN_STATE_LOWBATT);
01006             conn_update_statusbar();
01007             break;
01008         case CONN_STATE_FLIGHTMODE:
01009             LOGPRINTF("flightmode has preference over lowbatt. Ignoring");
01010             break;
01011         case CONN_STATE_LOWBATT:
01012             LOGPRINTF("already in state %s", conn_state_str[g_conn_state]);
01013             break;
01014         case CONN_STATE_INITIALISING:
01015         case CONN_STATE_INIT_WAITING:
01016         case CONN_STATE_LOADING:
01017         case CONN_STATE_UNLOADING:
01018         case CONN_STATE_DISCONNECTING:
01019         case CONN_STATE_CONNECTING:
01020             set_request(REQ_LOWBATT);
01021             break;
01022         case CONN_STATE_CONNECTED:
01023             set_request(REQ_LOWBATT);
01024             set_conn_state(CONN_STATE_DISCONNECTING);
01025             ipc_show_message("3glowdisconnected", NULL, NULL);
01026             ipc_disconnect(g_service->ipc_service);
01027             break;
01028         case CONN_STATE_DISCONNECTED:
01029             set_request(REQ_LOWBATT);
01030             set_conn_state(CONN_STATE_UNLOADING);
01031             stop_medium();
01032             break;
01033     }
01034 }
01035 
01036 
01037 static void conn_disable_lowbatt()
01038 {
01039     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
01040     switch (g_conn_state)
01041     {
01042         case CONN_STATE_OFF:
01043         case CONN_STATE_FLIGHTMODE:
01044             LOGPRINTF("already in state %s", conn_state_str[g_conn_state]);
01045             break;
01046         case CONN_STATE_LOWBATT:
01047             set_request(REQ_DISCONNECT);
01048             enter_off_state();
01049             break;
01050         case CONN_STATE_INITIALISING:
01051         case CONN_STATE_INIT_WAITING:
01052         case CONN_STATE_LOADING:
01053         case CONN_STATE_CONNECTING:
01054         case CONN_STATE_CONNECTED:
01055         case CONN_STATE_DISCONNECTED:
01056             LOGPRINTF("cannot disable lowbatt in state %s. Ignoring", conn_state_str[g_conn_state]);
01057             break;
01058         case CONN_STATE_UNLOADING:
01059             set_request(REQ_DISCONNECT);
01060             break;
01061         case CONN_STATE_DISCONNECTING:
01062             // TODO check if there are connections
01063             break;
01064     }
01065 }
01066 
01067 
01068 // lowbatt mode changed
01069 void conn_set_lowbatt(gboolean is_enabled)
01070 {
01071     LOGPRINTF("entry: is_enabled [%d]", is_enabled);
01072 
01073     if (is_enabled) {
01074         conn_enable_lowbatt();
01075     } else {
01076         conn_disable_lowbatt();
01077     }
01078 }
01079 
01080 
01081 static void conn_enable_flightmode()
01082 {
01083     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
01084     switch (g_conn_state)
01085     {
01086         case CONN_STATE_OFF:
01087         case CONN_STATE_LOWBATT:
01088             conn_on_enter_standby();
01089             set_request(REQ_FLIGHTMODE);
01090             set_conn_state(CONN_STATE_FLIGHTMODE);
01091             conn_update_statusbar();
01092             break;
01093         case CONN_STATE_FLIGHTMODE:
01094             LOGPRINTF("already in state %s", conn_state_str[g_conn_state]);
01095             break;
01096         case CONN_STATE_INITIALISING:
01097         case CONN_STATE_INIT_WAITING:
01098             /* we use force_statusbar_state here because conn_disable_flightmode 
01099              * updates based on g_conn_state and the state will remain ..._INIT* for
01100              * the entire 5-10 seconds of modem init 
01101              */
01102             force_statusbar_state("flightmode");
01103             set_request(REQ_FLIGHTMODE);
01104             break;
01105         case CONN_STATE_LOADING:
01106         case CONN_STATE_UNLOADING:
01107         case CONN_STATE_DISCONNECTING:
01108         case CONN_STATE_CONNECTING:
01109             set_request(REQ_FLIGHTMODE);
01110             break;
01111         case CONN_STATE_CONNECTED:
01112             set_request(REQ_FLIGHTMODE);
01113             set_conn_state(CONN_STATE_DISCONNECTING);
01114             ipc_disconnect(g_service->ipc_service);
01115             break;
01116         case CONN_STATE_DISCONNECTED:
01117             set_request(REQ_FLIGHTMODE);
01118             set_conn_state(CONN_STATE_UNLOADING);
01119             stop_medium();
01120             break;
01121     }
01122 }
01123 
01124 
01125 static void conn_disable_flightmode()
01126 {
01127     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
01128     switch (g_conn_state)
01129     {
01130         case CONN_STATE_OFF:
01131         case CONN_STATE_LOWBATT:
01132             LOGPRINTF("already in state %s", conn_state_str[g_conn_state]);
01133             break;
01134         case CONN_STATE_FLIGHTMODE:
01135             set_request(REQ_DISCONNECT);
01136             enter_off_state();
01137             break;
01138         case CONN_STATE_INITIALISING:
01139         case CONN_STATE_INIT_WAITING:
01140             force_statusbar_state("disconnected");
01141             set_request(REQ_DISCONNECT);
01142             break;
01143         case CONN_STATE_LOADING:
01144         case CONN_STATE_CONNECTING:
01145         case CONN_STATE_CONNECTED:
01146         case CONN_STATE_DISCONNECTED:
01147             LOGPRINTF("cannot disable flightmode in state %s. Ignoring", conn_state_str[g_conn_state]);
01148             break;
01149         case CONN_STATE_UNLOADING:
01150             set_request(REQ_DISCONNECT);
01151             break;
01152         case CONN_STATE_DISCONNECTING:
01153             // TODO check if there are connections
01154             break;
01155     }
01156 }
01157 
01158 
01159 // flight mode changed
01160 void conn_set_flightmode (gboolean is_enabled)
01161 {
01162     LOGPRINTF("entry: is_enabled [%d]", is_enabled);
01163 
01164     if (is_enabled) {
01165         conn_enable_flightmode();
01166     } else {
01167         conn_disable_flightmode();
01168     }
01169 }
01170 
01171 
01172 // statusbar icon clicked
01173 void conn_on_statusitem_activated (void)
01174 {
01175     if (g_conn_state == CONN_STATE_FLIGHTMODE)
01176     {
01177         conf_set_flightmode(FALSE);
01178     }
01179 }
01180 
01181 
01182 void conn_stop(void)
01183 {
01184     LOGPRINTF("state=%s  req=%s", conn_state_str[g_conn_state], req_names[g_request]);
01185     switch (g_conn_state)
01186     {
01187         case CONN_STATE_OFF:
01188         case CONN_STATE_FLIGHTMODE:
01189         case CONN_STATE_LOWBATT:
01190             // already unloaded
01191             break;
01192         case CONN_STATE_INIT_WAITING:
01193             set_request(REQ_DISCONNECT);
01194             // NOTE: cancel connect request by sending disconnect
01195             //       even though medium is not running yet
01196             busy_remove_foreground(0);
01197             enter_off_state();
01198             break;
01199         case CONN_STATE_INITIALISING:
01200         case CONN_STATE_LOADING:
01201         case CONN_STATE_UNLOADING:
01202         case CONN_STATE_DISCONNECTING:
01203             set_request(REQ_DISCONNECT);
01204             break;
01205         case CONN_STATE_CONNECTING:
01206             set_request(REQ_DISCONNECT);
01207             // NOTE: cancel connect request by sending disconnect
01208             ipc_disconnect(g_service->ipc_service);
01209             break;
01210         case CONN_STATE_CONNECTED:
01211             set_request(REQ_DISCONNECT);
01212             set_conn_state(CONN_STATE_DISCONNECTING);
01213             ipc_disconnect(g_service->ipc_service);
01214             break;
01215         case CONN_STATE_DISCONNECTED:
01216             set_request(REQ_DISCONNECT);
01217             set_conn_state(CONN_STATE_UNLOADING);
01218             stop_medium();
01219             break;
01220     }
01221 }
Generated by  doxygen 1.6.2-20100208