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 }