00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 #include "config.h"
00032 
00033 
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 
00045 
00046 
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 
00059 
00060  
00061 enum state_conn
00062 {
00063     CONN_STATE_OFF = 0,         
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,    
00073     CONN_STATE_INIT_WAITING,    
00074 };
00075 
00076 typedef struct 
00077 {
00078     const gchar *medium;        
00079     const gchar *application;   
00080 } medium_t;
00081 
00082 
00083 
00084 
00085 
00086 
00087 static const gint TIMEOUT_STARTUP_COMPLETED  = 40; 
00088 static const gint MIN_BATTERY_LEVEL_3G_START = 25; 
00089 static const gint MIN_BATTERY_LEVEL_3G_KEEP  = 20; 
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         
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 
00136 
00137 
00138 static enum state_conn       g_conn_state            = CONN_STATE_OFF;
00139 static Request               g_request               = REQ_DISCONNECT;    
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 
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 
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             
00195             
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                 
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     
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             
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;   
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             
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     
00429     g_service = NULL;
00430 
00431 #if MACHINE_IS_DR800SG
00432     {
00433         
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             
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     
00484     gchar *command = g_strconcat(g_medium, "_start.sh", NULL);
00485     sys_spawn_sync(command);
00486     g_free(command);
00487     
00488     
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;  
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         
00574         set_conn_state(CONN_STATE_INITIALISING);
00575     } else {
00576         if (g_request == REQ_FLIGHTMODE) {
00577             
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             
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             
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         
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         
00692         start_medium("3g");
00693         break;
00694     }
00695 }
00696 
00697 
00698 
00699 
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 
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     
00746     
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);     
00765     }
00766 
00767     
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 
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             
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             
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 
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 
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 
00980 gboolean conn_add_profile(const char *medium)
00981 {
00982     UNUSED(medium);
00983     LOGPRINTF("entry");
00984     return FALSE;
00985 }
00986 
00987 
00988 
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             
01063             break;
01064     }
01065 }
01066 
01067 
01068 
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             
01099 
01100 
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             
01154             break;
01155     }
01156 }
01157 
01158 
01159 
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 
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             
01191             break;
01192         case CONN_STATE_INIT_WAITING:
01193             set_request(REQ_DISCONNECT);
01194             
01195             
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             
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 }