Example #1
0
/**@brief Function for handling the Application's BLE Stack events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 */
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
    uint32_t        err_code      = NRF_SUCCESS;
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            led_stop();
            
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            
            // Initialize the current heart rate to the average of max and min values. So that
            // everytime a new connection is made, the heart rate starts from the same value.
            m_cur_heart_rate = (MAX_HEART_RATE + MIN_HEART_RATE) / 2;

            // Start timers used to generate battery and HR measurements.
            application_timers_start();

            // Start handling button presses
            err_code = app_button_enable();
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            // Since we are not in a connection and have not started advertising, store bonds
            err_code = ble_bondmngr_bonded_masters_store();
            APP_ERROR_CHECK(err_code);

            // Go to system-off mode, should not return from this function, wakeup will trigger
            // a reset.
            system_off_mode_enter();
            break;

        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
            err_code = sd_ble_gap_sec_params_reply(m_conn_handle, 
                                                BLE_GAP_SEC_STATUS_SUCCESS, 
                                                &m_sec_params);
            break;

        case BLE_GAP_EVT_TIMEOUT:
            if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT)
            {
                led_stop();
                GPIO_WAKEUP_BUTTON_CONFIG(HR_INC_BUTTON_PIN_NO);
                GPIO_WAKEUP_BUTTON_CONFIG(HR_DEC_BUTTON_PIN_NO);
                system_off_mode_enter();
            }
            break;

        default:
            break;
    }

    APP_ERROR_CHECK(err_code);
}
Example #2
0
/**@brief Function for handling the Application's BLE Stack events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 */
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
    uint32_t        err_code;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            led_stop();
            
            // Initialize the current heart rate to the average of max and min values. So that
            // everytime a new connection is made, the heart rate starts from the same value.
            m_cur_heart_rate = (MAX_HEART_RATE + MIN_HEART_RATE) / 2;

            // Start timers used to generate battery and HR measurements.
            application_timers_start();

            // Start handling button presses
            err_code = app_button_enable();
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GAP_EVT_DISCONNECTED:            
            // @note Flash access may not be complete on return of this API. System attributes are now
            // stored to flash when they are updated to ensure flash access on disconnect does not
            // result in system powering off before data was successfully written.

            // Go to system-off mode, should not return from this function, wakeup will trigger
            // a reset.
            system_off_mode_enter();
            break;

        case BLE_GAP_EVT_TIMEOUT:
            if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT)
            {
                led_stop();
                
                nrf_gpio_cfg_sense_input(HR_INC_BUTTON_PIN_NO,
                                         BUTTON_PULL, 
                                         NRF_GPIO_PIN_SENSE_LOW);

                nrf_gpio_cfg_sense_input(HR_DEC_BUTTON_PIN_NO,
                                         BUTTON_PULL, 
                                         NRF_GPIO_PIN_SENSE_LOW);

                system_off_mode_enter();
            }
            break;

        default:
            // No implementation needed.
            break;
    }
}
Example #3
0
/**@brief Application's BLE Stack event handler.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 */
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
    uint32_t        err_code      = NRF_SUCCESS;
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;

    switch (p_ble_evt->header.evt_id)
    {
    case BLE_GAP_EVT_CONNECTED:
        led_stop();
        led1_on();
        connected = true;

        m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;

        // Start handling button presses
        //err_code = app_button_enable();
        break;

    case BLE_GAP_EVT_DISCONNECTED:
        // Since we are not in a connection and have not started advertising, store bonds
        err_code = ble_bondmngr_bonded_masters_store();
        APP_ERROR_CHECK(err_code);

        led1_off();
        connected = false;

        // Go to system-off mode, should not return from this function, wakeup will trigger
        // a reset.
        //system_off_mode_enter();
        break;

    case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
        err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
                                               BLE_GAP_SEC_STATUS_SUCCESS,
                                               &m_sec_params);
        break;

    case BLE_GAP_EVT_TIMEOUT:
        if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT)
        {
            led_stop();
            //system_off_mode_enter();
        }
        break;

    default:
        break;
    }

    APP_ERROR_CHECK(err_code);
}
Example #4
0
/**@brief Button event handler.
 *
 * @param[in]   pin_no   The pin number of the button pressed.
 */
static void button_event_handler(uint8_t pin_no)
{
    switch (pin_no)
    {
    case EVAL_BOARD_BUTTON_0:
        mlog_str("button 0 pressed\r\n");

        if (connected)
            ble_oto_send_step_count(&m_oto, get_step_count());

        motor_off();
        led_stop();
        break;

    case EVAL_BOARD_BUTTON_1:
        mlog_str("button 1 pressed\r\n");

        if (!connected)
            advertising_start();
        break;

    default:
        APP_ERROR_HANDLER(pin_no);
    }
}
void led_network_state_observer(device_network_state_t state)
{
    switch(state) {
        case WAIT_SMT_TRIGGER:
			semnetnotify=1;
            if(is_provisioned()) {
                led_connecting();
#ifdef MIIO_COMMANDS
                mcmd_enqueue_raw("MIIO_net_change offline");
#endif
            } else {
                led_waiting_trigger();
#ifdef MIIO_COMMANDS
                mcmd_enqueue_raw("MIIO_net_change unprov");
#endif
            }
            break;
        case UAP_WAIT_SMT:
			semnetnotify=1;
            led_diagnosing();
#ifdef MIIO_COMMANDS
            mcmd_enqueue_raw("MIIO_net_change uap");
#endif
            break;
        case SMT_CONNECTING:
			semnetnotify=1;
            led_connecting();
#ifdef MIIO_COMMANDS
            mcmd_enqueue_raw("MIIO_net_change offline");
#endif
            break;
        case GOT_IP_NORMAL_WORK:
			semnetnotify=1;
            led_connected();
#ifdef MIIO_COMMANDS
            mcmd_enqueue_raw("MIIO_net_change local");
#endif
            break;
        case SMT_CFG_STOP:
			semnetnotify=1;
            led_stop();
#ifdef MIIO_COMMANDS
            mcmd_enqueue_raw("MIIO_net_change stop");
#endif
            break;        
    }
	state_config = state;
}
Example #6
0
/**@brief Function for handling the Application's BLE Stack events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 */
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
    uint32_t        err_code = NRF_SUCCESS;
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
    
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            led_stop();
            err_code = app_button_enable();
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            break;
            
        case BLE_GAP_EVT_DISCONNECTED:
            m_conn_handle = BLE_CONN_HANDLE_INVALID;
            
            // Stop detecting button presses when not connected.
            err_code = app_button_disable();
            APP_ERROR_CHECK(err_code);
            
            err_code = ble_ams_c_service_store();
            APP_ERROR_CHECK(err_code);
            
            advertising_start();
            break;
            
        case BLE_GAP_EVT_TIMEOUT:
            if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT)
            {
                advertising_start();
            }
            break;
            
        case BLE_GATTC_EVT_TIMEOUT:
        case BLE_GATTS_EVT_TIMEOUT:
            // Disconnect on GATT Server and Client timeout events.
            err_code = sd_ble_gap_disconnect(m_conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
            break;
            
        default:
            // No implementation needed.
            break;
    }
    APP_ERROR_CHECK(err_code);
}
Example #7
0
int32_t main (int32_t argc, char *argv[])
{
	int32_t i, j;
	prog_name = argv[0];
	if (pthread_key_create(&getclient, NULL)) {
		fprintf(stderr, "Could not create getclient, exiting...");
		exit(1);
	}

  void (*mod_def[])(struct s_module *)=
  {
#ifdef MODULE_MONITOR
           module_monitor,
#endif
#ifdef MODULE_CAMD33
           module_camd33,
#endif
#ifdef MODULE_CAMD35
           module_camd35,
#endif
#ifdef MODULE_CAMD35_TCP
           module_camd35_tcp,
#endif
#ifdef MODULE_NEWCAMD
           module_newcamd,
#endif
#ifdef MODULE_CCCAM
           module_cccam,
#endif
#ifdef MODULE_PANDORA
           module_pandora,
#endif
#ifdef MODULE_GHTTP
           module_ghttp,
#endif
#ifdef CS_CACHEEX
           module_csp,
#endif
#ifdef MODULE_GBOX
           module_gbox,
#endif
#ifdef MODULE_CONSTCW
           module_constcw,
#endif
#ifdef MODULE_RADEGAST
           module_radegast,
#endif
#ifdef MODULE_SERIAL
           module_serial,
#endif
#ifdef HAVE_DVBAPI
	   module_dvbapi,
#endif
           0
  };

  void (*cardsystem_def[])(struct s_cardsystem *)=
  {
#ifdef READER_NAGRA
	reader_nagra,
#endif
#ifdef READER_IRDETO
	reader_irdeto,
#endif
#ifdef READER_CONAX
	reader_conax,
#endif
#ifdef READER_CRYPTOWORKS
	reader_cryptoworks,
#endif
#ifdef READER_SECA
	reader_seca,
#endif
#ifdef READER_VIACCESS
	reader_viaccess,
#endif
#ifdef READER_VIDEOGUARD
	reader_videoguard1,
	reader_videoguard2,
	reader_videoguard12,
#endif
#ifdef READER_DRE
	reader_dre,
#endif
#ifdef READER_TONGFANG
	reader_tongfang,
#endif
#ifdef READER_BULCRYPT
	reader_bulcrypt,
#endif
#ifdef READER_GRIFFIN
	reader_griffin,
#endif
#ifdef READER_DGCRYPT
	reader_dgcrypt,
#endif
	0
  };

  void (*cardreader_def[])(struct s_cardreader *)=
  {
#ifdef CARDREADER_DB2COM
	cardreader_db2com,
#endif
#if defined(CARDREADER_INTERNAL_AZBOX)
	cardreader_internal_azbox,
#elif defined(CARDREADER_INTERNAL_COOLAPI)
	cardreader_internal_cool,
#elif defined(CARDREADER_INTERNAL_SCI)
	cardreader_internal_sci,
#endif
#ifdef CARDREADER_PHOENIX
	cardreader_mouse,
#endif
#ifdef CARDREADER_MP35
	cardreader_mp35,
#endif
#ifdef CARDREADER_PCSC
	cardreader_pcsc,
#endif
#ifdef CARDREADER_SC8IN1
	cardreader_sc8in1,
#endif
#ifdef CARDREADER_SMARGO
	cardreader_smargo,
#endif
#ifdef CARDREADER_SMART
	cardreader_smartreader,
#endif
#ifdef CARDREADER_STAPI
	cardreader_stapi,
#endif
	0
  };

  parse_cmdline_params(argc, argv);

  if (bg && do_daemon(1,0))
  {
    printf("Error starting in background (errno=%d: %s)", errno, strerror(errno));
    cs_exit(1);
  }

  get_random_bytes_init();

#ifdef WEBIF
  if (cs_restart_mode)
    restart_daemon();
#endif

  memset(&cfg, 0, sizeof(struct s_config));
  cfg.max_pending = max_pending;

  if (cs_confdir[strlen(cs_confdir) - 1] != '/') strcat(cs_confdir, "/");
  init_signal_pre(); // because log could cause SIGPIPE errors, init a signal handler first
  init_first_client();
  cs_lock_create(&system_lock, 5, "system_lock");
  cs_lock_create(&config_lock, 10, "config_lock");
  cs_lock_create(&gethostbyname_lock, 10, "gethostbyname_lock");
  cs_lock_create(&clientlist_lock, 5, "clientlist_lock");
  cs_lock_create(&readerlist_lock, 5, "readerlist_lock");
  cs_lock_create(&fakeuser_lock, 5, "fakeuser_lock");
  cs_lock_create(&ecmcache_lock, 5, "ecmcache_lock");
  cs_lock_create(&readdir_lock, 5, "readdir_lock");
  cs_lock_create(&cwcycle_lock, 5, "cwcycle_lock");
  cs_lock_create(&hitcache_lock, 5, "hitcache_lock");
  coolapi_open_all();
  init_config();
  cs_init_log();
  if (!oscam_pidfile && cfg.pidfile)
    oscam_pidfile = cfg.pidfile;
  if (!oscam_pidfile) {
    oscam_pidfile = get_tmp_dir_filename(default_pidfile, sizeof(default_pidfile), "oscam.pid");
  }
  if (oscam_pidfile)
    pidfile_create(oscam_pidfile);
  cs_init_statistics();
  init_check();
  init_stat();

  // These initializations *MUST* be called after init_config()
  // because modules depend on config values.
  for (i=0; mod_def[i]; i++)
  {
	struct s_module *module = &modules[i];
	mod_def[i](module);
  }
  for (i=0; cardsystem_def[i]; i++)
  {
	memset(&cardsystems[i], 0, sizeof(struct s_cardsystem));
	cardsystem_def[i](&cardsystems[i]);
  }
  for (i=0; cardreader_def[i]; i++)
  {
	memset(&cardreaders[i], 0, sizeof(struct s_cardreader));
	cardreader_def[i](&cardreaders[i]);
  }

  init_sidtab();
  init_readerdb();
  cfg.account = init_userdb();
  init_signal();
  init_srvid();
  init_tierid();
  init_provid();

  start_garbage_collector(gbdb);

  cacheex_init();

  init_len4caid();
  init_irdeto_guess_tab();

  write_versionfile(false);

  led_init();
  led_status_default();

  azbox_init();

  mca_init();

  global_whitelist_read();
  cacheex_load_config_file();

	for (i = 0; i < CS_MAX_MOD; i++) {
		struct s_module *module = &modules[i];
		if ((module->type & MOD_CONN_NET)) {
			for (j = 0; j < module->ptab.nports; j++) {
				start_listener(module, &module->ptab.ports[j]);
			}
		}
	}

	//set time for server to now to avoid 0 in monitor/webif
	first_client->last=time((time_t *)0);

	webif_init();

	start_thread((void *) &reader_check, "reader check");
	cw_process_thread_start();

	lcd_thread_start();

	do_report_emm_support();

	init_cardreader();

	cs_waitforcardinit();

	led_status_starting();

	ac_init();

	for (i = 0; i < CS_MAX_MOD; i++) {
		struct s_module *module = &modules[i];
		if ((module->type & MOD_CONN_SERIAL) && module->s_handler)
			module->s_handler(NULL, NULL, i);
	}

	// main loop function
	process_clients();

	cw_process_thread_wakeup(); // Stop cw_process thread
	pthread_cond_signal(&reader_check_sleep_cond); // Stop reader_check thread

	// Cleanup
	webif_close();
	azbox_close();
	coolapi_close_all();
	mca_close();

	led_status_stopping();
	led_stop();
	lcd_thread_stop();

	remove_versionfile();

	stat_finish();
	cccam_done_share();

	kill_all_clients();
	kill_all_readers();

	if (oscam_pidfile)
		unlink(oscam_pidfile);

	webif_tpls_free();
	init_free_userdb(cfg.account);
	cfg.account = NULL;
	init_free_sidtab();
	free_readerdb();
	free_irdeto_guess_tab();
	config_free();

	cs_log("cardserver down");
	log_free();

	stop_garbage_collector();

	free(first_client->account);
	free(first_client);

	// This prevents the compiler from removing config_mak from the final binary
	syslog_ident = config_mak;

	return exit_oscam;
}
Example #8
0
/**@brief Function for handling the Application's BLE Stack events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 */
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
    uint32_t        err_code;
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            led_stop();
            nrf_gpio_pin_set(CONNECTED_LED_PIN_NO); //GreenLED
            
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            
            // Initialize the current heart rate to the average of max and min values. So that
            // everytime a new connection is made, the heart rate starts from the same value.
            m_cur_heart_rate = (MAX_HEART_RATE + MIN_HEART_RATE) / 2;

            // Start timers used to generate battery and HR measurements.
            application_timers_start();

            // Start handling button presses
            err_code = app_button_enable();
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            // Since we are not in a connection and have not started advertising, store bonds
            err_code = ble_bondmngr_bonded_centrals_store();
            APP_ERROR_CHECK(err_code);

            nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO); //GreenLED
            
            m_storage_in_progress = true;
        
            // @note Flash access may not be complete on return of this API. System attributes are now
            // stored to flash when they are updated to ensure flash access on disconnect does not
            // result in system powering off before data was successfully written.

            // Go to system-off mode, should not return from this function, wakeup will trigger
            // a reset.
            system_off_mode_enter();
            break;

        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
            err_code = sd_ble_gap_sec_params_reply(m_conn_handle, 
                                                   BLE_GAP_SEC_STATUS_SUCCESS, 
                                                   &m_sec_params);
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GAP_EVT_TIMEOUT:
            if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT)
            {
                led_stop();
                
                nrf_gpio_cfg_sense_input(HR_INC_BUTTON_PIN_NO,
                                         BUTTON_PULL, 
                                         NRF_GPIO_PIN_SENSE_LOW);

                nrf_gpio_cfg_sense_input(HR_DEC_BUTTON_PIN_NO,
                                         BUTTON_PULL, 
                                         NRF_GPIO_PIN_SENSE_LOW);

                system_off_mode_enter();
            }
            break;

        default:
            // No implementation needed.
            break;
    }
}
Example #9
0
int32_t main(int32_t argc, char *argv[])
{
	fix_stacksize();
		
	run_tests();
	int32_t i, j;
	prog_name = argv[0];
	struct timespec start_ts;
	cs_gettime(&start_ts); // Initialize clock_type

	if(pthread_key_create(&getclient, NULL))
	{
		fprintf(stderr, "Could not create getclient, exiting...");
		exit(1);
	}

	void (*mod_def[])(struct s_module *) =
	{
#ifdef MODULE_MONITOR
		module_monitor,
#endif
#ifdef MODULE_CAMD33
		module_camd33,
#endif
#ifdef MODULE_CAMD35
		module_camd35,
#endif
#ifdef MODULE_CAMD35_TCP
		module_camd35_tcp,
#endif
#ifdef MODULE_NEWCAMD
		module_newcamd,
#endif
#ifdef MODULE_CCCAM
		module_cccam,
#endif
#ifdef MODULE_PANDORA
		module_pandora,
#endif
#ifdef MODULE_GHTTP
		module_ghttp,
#endif
#ifdef CS_CACHEEX
		module_csp,
#endif
#ifdef MODULE_GBOX
		module_gbox,
#endif
#ifdef MODULE_CONSTCW
		module_constcw,
#endif
#ifdef MODULE_RADEGAST
		module_radegast,
#endif
#ifdef MODULE_SCAM
		module_scam,
#endif
#ifdef MODULE_SERIAL
		module_serial,
#endif
#ifdef HAVE_DVBAPI
		module_dvbapi,
#endif
		0
	};
	
	find_conf_dir();

	parse_cmdline_params(argc, argv);

	if(bg && do_daemon(1, 0))
	{
		printf("Error starting in background (errno=%d: %s)", errno, strerror(errno));
		cs_exit(1);
	}

	get_random_bytes_init();

#ifdef WEBIF
	if(cs_restart_mode)
		{ restart_daemon(); }
#endif

	memset(&cfg, 0, sizeof(struct s_config));
	cfg.max_pending = max_pending;

	if(cs_confdir[strlen(cs_confdir) - 1] != '/') { strcat(cs_confdir, "/"); }
	init_signal_pre(); // because log could cause SIGPIPE errors, init a signal handler first
	init_first_client();
	cs_lock_create(__func__, &system_lock, "system_lock", 5000);
	cs_lock_create(__func__, &config_lock, "config_lock", 10000);
	cs_lock_create(__func__, &gethostbyname_lock, "gethostbyname_lock", 10000);
	cs_lock_create(__func__, &clientlist_lock, "clientlist_lock", 5000);
	cs_lock_create(__func__, &readerlist_lock, "readerlist_lock", 5000);
	cs_lock_create(__func__, &fakeuser_lock, "fakeuser_lock", 5000);
	cs_lock_create(__func__, &ecmcache_lock, "ecmcache_lock", 5000);
	cs_lock_create(__func__, &ecm_pushed_deleted_lock, "ecm_pushed_deleted_lock", 5000);
	cs_lock_create(__func__, &readdir_lock, "readdir_lock", 5000);
	cs_lock_create(__func__, &cwcycle_lock, "cwcycle_lock", 5000);
	init_cache();
	cacheex_init_hitcache();
	init_config();
	cs_init_log();
	init_machine_info();
	init_check();
	if(!oscam_pidfile && cfg.pidfile)
		{ oscam_pidfile = cfg.pidfile; }
	if(!oscam_pidfile)
	{
		oscam_pidfile = get_tmp_dir_filename(default_pidfile, sizeof(default_pidfile), "oscam.pid");
	}
	if(oscam_pidfile)
		{ pidfile_create(oscam_pidfile); }
	cs_init_statistics();
	coolapi_open_all();
	init_stat();
	ssl_init();

	// These initializations *MUST* be called after init_config()
	// because modules depend on config values.
	for(i = 0; mod_def[i]; i++)
	{
		struct s_module *module = &modules[i];
		mod_def[i](module);
	}

	init_sidtab();
	init_readerdb();
	cfg.account = init_userdb();
	init_signal();
	init_provid();
	init_srvid();
	init_tierid();
	init_fakecws();

	start_garbage_collector(gbdb);

	cacheex_init();

	init_len4caid();
	init_irdeto_guess_tab();

	write_versionfile(false);

	led_init();
	led_status_default();

	azbox_init();

	mca_init();

	global_whitelist_read();
	ratelimit_read();

	for(i = 0; i < CS_MAX_MOD; i++)
	{
		struct s_module *module = &modules[i];
		if((module->type & MOD_CONN_NET))
		{
			for(j = 0; j < module->ptab.nports; j++)
			{
				start_listener(module, &module->ptab.ports[j]);
			}
		}
	}

	//set time for server to now to avoid 0 in monitor/webif
	first_client->last = time((time_t *)0);

	webif_init();

	start_thread("reader check", (void *) &reader_check, NULL, NULL, 1, 1);
	cw_process_thread_start();
	checkcache_process_thread_start();

	lcd_thread_start();

	do_report_emm_support();

	init_cardreader();

	cs_waitforcardinit();
	
	emm_load_cache();
	load_emmstat_from_file();

	led_status_starting();

	ac_init();

	start_thread("card poll", (void *) &card_poll, NULL, NULL, 1, 1);

	for(i = 0; i < CS_MAX_MOD; i++)
	{
		struct s_module *module = &modules[i];
		if((module->type & MOD_CONN_SERIAL) && module->s_handler)
			{ module->s_handler(NULL, NULL, i); }
	}

	// main loop function
	process_clients();

	SAFE_COND_SIGNAL(&card_poll_sleep_cond); // Stop card_poll thread
	cw_process_thread_wakeup(); // Stop cw_process thread
	SAFE_COND_SIGNAL(&reader_check_sleep_cond); // Stop reader_check thread

	// Cleanup
#ifdef MODULE_GBOX	
	stop_sms_sender();
#endif
	webif_close();
	azbox_close();
	coolapi_close_all();
	mca_close();

	led_status_stopping();
	led_stop();
	lcd_thread_stop();

	remove_versionfile();

	stat_finish();
	dvbapi_stop_all_descrambling();
	dvbapi_save_channel_cache();
	emm_save_cache();
	save_emmstat_to_file();
	
	cccam_done_share();
	gbox_send_good_night(); 

	kill_all_clients();
	kill_all_readers();
	for(i = 0; i < CS_MAX_MOD; i++)
	{
		struct s_module *module = &modules[i];
		if((module->type & MOD_CONN_NET))
		{
			for(j = 0; j < module->ptab.nports; j++)
			{
				struct s_port *port = &module->ptab.ports[j];
				if(port->fd)
				{
					shutdown(port->fd, SHUT_RDWR);
					close(port->fd);
					port->fd = 0;
				}
			}
		}
	}

	if(oscam_pidfile)
		{ unlink(oscam_pidfile); }

	// sleep a bit, so hopefully all threads are stopped when we continue
	cs_sleepms(200);

	free_cache();
	cacheex_free_hitcache();
	webif_tpls_free();
	init_free_userdb(cfg.account);
	cfg.account = NULL;
	init_free_sidtab();
	free_readerdb();
	free_irdeto_guess_tab();
	config_free();
	ssl_done();

	detect_valgrind();
	if (!running_under_valgrind)
		cs_log("cardserver down");
	else
		cs_log("running under valgrind, waiting 5 seconds before stopping cardserver");
	log_free();

	if (running_under_valgrind) sleep(5); // HACK: Wait a bit for things to settle

	stop_garbage_collector();

	NULLFREE(first_client->account);
	NULLFREE(first_client);
	free(stb_boxtype);
	free(stb_boxname);

	// This prevents the compiler from removing config_mak from the final binary
	syslog_ident = config_mak;

	return exit_oscam;
}