Compare commits

..

12 Commits

Author SHA1 Message Date
Slava Monich
50a5f2547e Merge branch 'hfp' into 'master'
Register HandsfreeAudioManager straight away at startup

See merge request mer-core/ofono!277
2020-11-19 22:36:22 +00:00
Slava Monich
d682fcd5fe [ofono] Request D-Bus name after initializing all plugins. JB#52107
To ensure that all D-Bus objects which should be available straight
after startup are there when the first incoming D-Bus call arrives.
2020-11-19 20:18:23 +02:00
Slava Monich
5799320480 [ril] Took out erroneous assert 2020-11-19 20:09:35 +02:00
Slava Monich
3eea7c868e [hfp_hf_bluez5] Removed __ofono_handsfree_audio_manager_ calls
Those functions are called by ofono_handsfree_audio_ref/unref which
ensure that initialization is only done once.
2020-11-19 19:20:50 +02:00
Slava Monich
4844fc6cf9 [hfp_ag_bluez5] Register HandsfreeAudioManager straight away at startup. JB#52107
Otherwise it's not clear how the client is supposed to wait for
org.ofono.HandsfreeAudioManager to appear and how to figure out
whether it's ever going to appear.
2020-11-19 17:06:05 +02:00
Juho Hamalainen
6976366051 Merge branch 'jb48911' into 'master'
Don't try to connect HFP AG if bluetooth service is not available.

See merge request mer-core/ofono!276
2020-11-12 08:15:36 +00:00
Juho Hämäläinen
d3d776837b [hfp_ag_bluez5] Don't try to connect if bluetooth service is not available. JB#48911
Trying to connect too soon will result in profile interface registration
failure with timeout error, effectively blocking for dbus timeout (25s
by default).
2020-11-12 10:13:44 +02:00
Slava Monich
f56c8a33b0 Merge branch 'jb50995' into 'master'
[ril] Calculate signal strength based on rsrp value correctly. JB#50995.

See merge request mer-core/ofono!275
2020-09-15 10:46:22 +00:00
Aleksei Berman
ed2f625b8b [ril] Calculate signal strength based on rsrp value correctly. JB#50995.
All the dBm values are converted to qdbm (multiply by 4) but rsrp which
results in incorrect signal strength representation on some devices.
2020-08-28 15:57:33 +03:00
Slava Monich
ed62d38632 Merge branch 'jb50608' into 'master'
[ril] Add config options for cell info update interval. JB#50608

See merge request mer-core/ofono!273
2020-07-27 22:12:17 +00:00
Denis Grigorev
3f433c97c5 [ril] Add config options for cell info update interval. JB#50608 2020-07-28 00:18:52 +03:00
Denis Grigorev
86d8149c79 [ril] Allow setting cell info update period to 0. JB#50608
According to ril.h, a value of 0 means invoke RIL_UNSOL_CELL_INFO_LIST when
any of the reported information changes.
2020-07-27 21:33:03 +03:00
13 changed files with 140 additions and 44 deletions

View File

@@ -373,7 +373,7 @@ static void ril_cell_info_query(struct ril_cell_info *self)
static void ril_cell_info_set_rate(struct ril_cell_info *self)
{
GRilIoRequest *req = grilio_request_array_int32_new(1,
(self->update_rate_ms > 0) ? self->update_rate_ms : INT_MAX);
(self->update_rate_ms >= 0) ? self->update_rate_ms : INT_MAX);
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_request_set_retry_func(req, ril_cell_info_retry);

View File

@@ -34,33 +34,29 @@ struct ril_devmon {
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
};
/* Cell info update intervals */
#define RIL_CELL_INFO_INTERVAL_SHORT_MS (2000) /* 2 sec */
#define RIL_CELL_INFO_INTERVAL_LONG_MS (30000) /* 30 sec */
/*
* Legacy Device Monitor uses RIL_REQUEST_SCREEN_STATE to tell
* the modem when screen turns on and off.
*/
struct ril_devmon *ril_devmon_ss_new(void);
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config);
/*
* This Device Monitor uses RIL_REQUEST_SEND_DEVICE_STATE to let
* the modem choose the right power saving strategy. It basically
* mirrors the logic of Android's DeviceStateMonitor class.
*/
struct ril_devmon *ril_devmon_ds_new(void);
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config);
/*
* This Device Monitor implementation controls network state updates
* by sending SET_UNSOLICITED_RESPONSE_FILTER.
*/
struct ril_devmon *ril_devmon_ur_new(void);
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config);
/*
* This one selects the type based on the RIL version.
*/
struct ril_devmon *ril_devmon_auto_new(void);
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config);
/*
* This one combines several methods. Takes ownership of ril_devmon objects.

View File

@@ -65,7 +65,7 @@ static void ril_devmon_auto_free(struct ril_devmon *devmon)
g_free(self);
}
struct ril_devmon *ril_devmon_auto_new()
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
@@ -78,8 +78,8 @@ struct ril_devmon *ril_devmon_auto_new()
*/
self->pub.free = ril_devmon_auto_free;
self->pub.start_io = ril_devmon_auto_start_io;
self->ss = ril_devmon_ss_new();
self->ds = ril_devmon_ds_new();
self->ss = ril_devmon_ss_new(config);
self->ds = ril_devmon_ds_new(config);
return &self->pub;
}

View File

@@ -65,6 +65,8 @@ typedef struct ril_devmon_ds {
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMon;
typedef struct ril_devmon_ds_io {
@@ -86,6 +88,8 @@ typedef struct ril_devmon_ds_io {
gulong charger_event_id[CHARGER_EVENT_COUNT];
gulong display_event_id[DISPLAY_EVENT_COUNT];
guint req_id;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMonIo;
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
@@ -201,8 +205,8 @@ static void ril_devmon_ds_io_set_cell_info_update_interval(DevMonIo *self)
(ril_devmon_ds_display_on(self->display) &&
(ril_devmon_ds_charging(self->charger) ||
ril_devmon_ds_battery_ok(self->battery))) ?
RIL_CELL_INFO_INTERVAL_SHORT_MS :
RIL_CELL_INFO_INTERVAL_LONG_MS);
self->cell_info_interval_short_ms :
self->cell_info_interval_long_ms);
}
static void ril_devmon_ds_io_connman_cb(struct ril_connman *connman,
@@ -303,6 +307,11 @@ static struct ril_devmon_io *ril_devmon_ds_start_io(struct ril_devmon *devmon,
mce_display_add_state_changed_handler(self->display,
ril_devmon_ds_io_display_cb, self);
self->cell_info_interval_short_ms =
ds->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
ds->cell_info_interval_long_ms;
ril_devmon_ds_io_update_low_data(self);
ril_devmon_ds_io_update_charging(self);
ril_devmon_ds_io_set_cell_info_update_interval(self);
@@ -320,7 +329,7 @@ static void ril_devmon_ds_free(struct ril_devmon *devmon)
g_free(self);
}
struct ril_devmon *ril_devmon_ds_new()
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
@@ -330,6 +339,10 @@ struct ril_devmon *ril_devmon_ds_new()
self->battery = mce_battery_new();
self->charger = mce_charger_new();
self->display = mce_display_new();
self->cell_info_interval_short_ms =
config->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
config->cell_info_interval_long_ms;
return &self->pub;
}

View File

@@ -50,6 +50,8 @@ typedef struct ril_devmon_ss {
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMon;
typedef struct ril_devmon_ss_io {
@@ -65,6 +67,8 @@ typedef struct ril_devmon_ss_io {
gulong charger_event_id[CHARGER_EVENT_COUNT];
gulong display_event_id[DISPLAY_EVENT_COUNT];
guint req_id;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMonIo;
inline static DevMon *ril_devmon_ss_cast(struct ril_devmon *pub)
@@ -130,8 +134,8 @@ static void ril_devmon_ss_io_set_cell_info_update_interval(DevMonIo *self)
sailfish_cell_info_set_update_interval(self->cell_info,
(self->display_on && (ril_devmon_ss_charging(self->charger) ||
ril_devmon_ss_battery_ok(self->battery))) ?
RIL_CELL_INFO_INTERVAL_SHORT_MS :
RIL_CELL_INFO_INTERVAL_LONG_MS);
self->cell_info_interval_short_ms :
self->cell_info_interval_long_ms);
}
static void ril_devmon_ss_io_battery_cb(MceBattery *battery, void *user_data)
@@ -212,6 +216,11 @@ static struct ril_devmon_io *ril_devmon_ss_start_io(struct ril_devmon *devmon,
mce_display_add_state_changed_handler(self->display,
ril_devmon_ss_io_display_cb, self);
self->cell_info_interval_short_ms =
ss->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
ss->cell_info_interval_long_ms;
ril_devmon_ss_io_send_screen_state(self);
ril_devmon_ss_io_set_cell_info_update_interval(self);
return &self->pub;
@@ -227,7 +236,7 @@ static void ril_devmon_ss_free(struct ril_devmon *devmon)
g_free(self);
}
struct ril_devmon *ril_devmon_ss_new()
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
@@ -236,6 +245,10 @@ struct ril_devmon *ril_devmon_ss_new()
self->battery = mce_battery_new();
self->charger = mce_charger_new();
self->display = mce_display_new();
self->cell_info_interval_short_ms =
config->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
config->cell_info_interval_long_ms;
return &self->pub;
}

View File

@@ -55,6 +55,8 @@ typedef struct ril_devmon_ur {
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMon;
typedef struct ril_devmon_ur_io {
@@ -70,6 +72,8 @@ typedef struct ril_devmon_ur_io {
gulong charger_event_id[CHARGER_EVENT_COUNT];
gulong display_event_id[DISPLAY_EVENT_COUNT];
guint req_id;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMonIo;
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
@@ -136,8 +140,8 @@ static void ril_devmon_ur_io_set_cell_info_update_interval(DevMonIo *self)
sailfish_cell_info_set_update_interval(self->cell_info,
(self->display_on && (ril_devmon_ur_charging(self->charger) ||
ril_devmon_ur_battery_ok(self->battery))) ?
RIL_CELL_INFO_INTERVAL_SHORT_MS :
RIL_CELL_INFO_INTERVAL_LONG_MS);
self->cell_info_interval_short_ms :
self->cell_info_interval_long_ms);
}
static void ril_devmon_ur_io_battery_cb(MceBattery *battery, void *user_data)
@@ -218,6 +222,11 @@ static struct ril_devmon_io *ril_devmon_ur_start_io(struct ril_devmon *devmon,
mce_display_add_state_changed_handler(self->display,
ril_devmon_ur_io_display_cb, self);
self->cell_info_interval_short_ms =
ur->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
ur->cell_info_interval_long_ms;
ril_devmon_ur_io_set_unsol_response_filter(self);
ril_devmon_ur_io_set_cell_info_update_interval(self);
return &self->pub;
@@ -233,7 +242,7 @@ static void ril_devmon_ur_free(struct ril_devmon *devmon)
g_free(self);
}
struct ril_devmon *ril_devmon_ur_new()
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
@@ -242,6 +251,10 @@ struct ril_devmon *ril_devmon_ur_new()
self->battery = mce_battery_new();
self->charger = mce_charger_new();
self->display = mce_display_new();
self->cell_info_interval_short_ms =
config->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
config->cell_info_interval_long_ms;
return &self->pub;
}

View File

@@ -503,7 +503,7 @@ static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
signal.qdbm = -4 * tdscdma_dbm;
} else if (signal.lte == 99 && rsrp >= 44 && rsrp <= 140) {
/* RSRP range: 44 to 140 dBm per 3GPP TS 36.133 */
signal.qdbm = -rsrp;
signal.qdbm = -4 * rsrp;
}
}

View File

@@ -100,6 +100,8 @@
#define RILMODEM_DEFAULT_USE_DATA_PROFILES FALSE
#define RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID RIL_DATA_PROFILE_IMS
#define RILMODEM_DEFAULT_SLOT_FLAGS SAILFISH_SLOT_NO_FLAGS
#define RILMODEM_DEFAULT_CELL_INFO_INTERVAL_SHORT_MS (2000) /* 2 sec */
#define RILMODEM_DEFAULT_CELL_INFO_INTERVAL_LONG_MS (30000) /* 30 sec */
/* RIL socket transport name and parameters */
#define RIL_TRANSPORT_MODEM "modem"
@@ -158,6 +160,8 @@
#define RILCONF_USE_DATA_PROFILES "useDataProfiles"
#define RILCONF_MMS_DATA_PROFILE_ID "mmsDataProfileId"
#define RILCONF_DEVMON "deviceStateTracking"
#define RILCONF_CELL_INFO_INTERVAL_SHORT_MS "cellInfoIntervalShortMs"
#define RILCONF_CELL_INFO_INTERVAL_LONG_MS "cellInfoIntervalLongMs"
/* Modem error ids */
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
@@ -1230,6 +1234,10 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
RILMODEM_DEFAULT_FORCE_GSM_WHEN_RADIO_OFF;
config->use_data_profiles = RILMODEM_DEFAULT_USE_DATA_PROFILES;
config->mms_data_profile_id = RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID;
config->cell_info_interval_short_ms =
RILMODEM_DEFAULT_CELL_INFO_INTERVAL_SHORT_MS;
config->cell_info_interval_long_ms =
RILMODEM_DEFAULT_CELL_INFO_INTERVAL_LONG_MS;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
slot->slot_flags = RILMODEM_DEFAULT_SLOT_FLAGS;
@@ -1241,8 +1249,7 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT;
slot->data_opt.data_call_retry_delay_ms =
RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY;
slot->devmon = ril_devmon_auto_new();
slot->devmon = ril_devmon_auto_new(config);
slot->watch = ofono_watch_new(dbus_path);
slot->watch_event_id[WATCH_EVENT_MODEM] =
ofono_watch_add_modem_changed_handler(slot->watch,
@@ -1742,6 +1749,26 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
slot->legacy_imei_query ? "on" : "off");
}
/* cellInfoIntervalShortMs */
if (ril_config_get_integer(file, group,
RILCONF_CELL_INFO_INTERVAL_SHORT_MS,
&config->cell_info_interval_short_ms)) {
DBG("%s: " RILCONF_CELL_INFO_INTERVAL_SHORT_MS " %d", group,
config->cell_info_interval_short_ms);
}
/* cellInfoIntervalLongMs */
if (ril_config_get_integer(file, group,
RILCONF_CELL_INFO_INTERVAL_LONG_MS,
&config->cell_info_interval_long_ms)) {
DBG("%s: " RILCONF_CELL_INFO_INTERVAL_LONG_MS " %d",
group, config->cell_info_interval_long_ms);
}
/* Replace devmon with a new one with applied settings */
ril_devmon_free(slot->devmon);
slot->devmon = NULL;
/* deviceStateTracking */
if (ril_config_get_mask(file, group, RILCONF_DEVMON, &ival,
"ds", RIL_DEVMON_DS,
@@ -1750,11 +1777,16 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
int n = 0;
struct ril_devmon *devmon[3];
if (ival & RIL_DEVMON_DS) devmon[n++] = ril_devmon_ds_new();
if (ival & RIL_DEVMON_SS) devmon[n++] = ril_devmon_ss_new();
if (ival & RIL_DEVMON_UR) devmon[n++] = ril_devmon_ur_new();
if (ival & RIL_DEVMON_DS) {
devmon[n++] = ril_devmon_ds_new(config);
}
if (ival & RIL_DEVMON_SS) {
devmon[n++] = ril_devmon_ss_new(config);
}
if (ival & RIL_DEVMON_UR) {
devmon[n++] = ril_devmon_ur_new(config);
}
DBG("%s: " RILCONF_DEVMON " 0x%x", group, ival);
ril_devmon_free(slot->devmon);
slot->devmon = ril_devmon_combine(devmon, n);
} else {
/* Try special values */
@@ -1762,13 +1794,14 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
if (sval) {
if (!g_ascii_strcasecmp(sval, "none")) {
DBG("%s: " RILCONF_DEVMON " %s", group, sval);
ril_devmon_free(slot->devmon);
slot->devmon = NULL;
} else if (!g_ascii_strcasecmp(sval, "auto")) {
DBG("%s: " RILCONF_DEVMON " %s", group, sval);
/* This is the default */
slot->devmon = ril_devmon_auto_new(config);
}
g_free(sval);
} else {
/* This is the default */
slot->devmon = ril_devmon_auto_new(config);
}
}
@@ -2336,7 +2369,6 @@ static int ril_plugin_init(void)
static void ril_plugin_exit(void)
{
DBG("");
GASSERT(ril_driver);
ofono_ril_transport_unregister(&ril_socket_transport);
ofono_modem_driver_unregister(&ril_modem_driver);

View File

@@ -339,3 +339,29 @@ socket=/dev/socket/rild
# Default true (false for MTK RILs)
#
#forceGsmWhenRadioOff=true
# Configures a period between RIL_UNSOL_CELL_INFO_LIST events when the device
# is awake. Possible values are:
#
# 0 = invoke RIL_UNSOL_CELL_INFO_LIST when any of the reported information
# changes
# 1..INT_MAX-1 (2147483646) = sets update period in milliseconds
# negative value or INT_MAX = never issue a RIL_UNSOL_CELL_INFO_LIST
#
# On MediaTek devices the period of RIL_UNSOL_CELL_INFO_LIST events can't be
# configured. The parameter RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE has
# non-standard meaning:
#
# 0 = enable RIL_UNSOL_CELL_INFO_LIST
# any other value = disable RIL_UNSOL_CELL_INFO_LIST
#
# Default 2000
#
#cellInfoIntervalShortMs=2000
# Configures period between RIL_UNSOL_CELL_INFO_LIST events when the device is
# in a power saving mode. For possible values, look cellInfoIntervalShortMs.
#
# Default 30000
#
#cellInfoIntervalLongMs=30000

View File

@@ -79,6 +79,8 @@ struct ril_slot_config {
guint mms_data_profile_id;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
};
#endif /* RIL_TYPES_H */

View File

@@ -495,8 +495,6 @@ static void hfp_ag_enable(DBusConnection *conn)
connection_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, connection_destroy);
ofono_handsfree_audio_ref();
hfp_ag_enabled = TRUE;
}
@@ -525,7 +523,6 @@ static void hfp_ag_disable(DBusConnection *conn)
g_dbus_unregister_interface(conn, HFP_AG_EXT_PROFILE_PATH,
BLUEZ_PROFILE_INTERFACE);
ofono_handsfree_card_driver_unregister(&hfp_ag_driver);
ofono_handsfree_audio_unref();
}
hfp_ag_enabled = FALSE;
@@ -545,13 +542,14 @@ static int hfp_ag_init(void)
{
DBusConnection *conn = ofono_dbus_get_connection();
hfp_ag_enable(conn);
/* g_dbus_add_service_watch immediately checks for bluetooth service
* and calls connect callback if the service exists. */
service_watch_id = g_dbus_add_service_watch(conn, "org.bluez",
bluez_connect_cb,
bluez_disconnect_cb,
NULL, NULL);
ofono_handsfree_audio_ref();
return 0;
}
@@ -565,6 +563,7 @@ static void hfp_ag_exit(void)
}
hfp_ag_disable(conn);
ofono_handsfree_audio_unref();
}
OFONO_PLUGIN_DEFINE(hfp_ag_bluez5, "Hands-Free Audio Gateway Profile Plugins",

View File

@@ -49,7 +49,6 @@
#include <ofono/handsfree.h>
#include <ofono/handsfree-audio.h>
#include <ofono/siri.h>
#include <ofono.h>
#include <drivers/atmodem/atutil.h>
#include <drivers/hfpmodem/slc.h>
@@ -833,8 +832,6 @@ static int hfp_init(void)
if (DBUS_TYPE_UNIX_FD < 0)
return -EBADF;
__ofono_handsfree_audio_manager_init();
/* Registers External Profile handler */
if (!g_dbus_register_interface(conn, HFP_EXT_PROFILE_PATH,
BLUEZ_PROFILE_INTERFACE,
@@ -890,8 +887,6 @@ static void hfp_exit(void)
g_dbus_client_unref(bluez);
ofono_handsfree_audio_unref();
__ofono_handsfree_audio_manager_cleanup();
}
OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION,

View File

@@ -3,6 +3,8 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -281,7 +283,7 @@ int main(int argc, char **argv)
dbus_error_init(&error);
conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, OFONO_SERVICE, &error);
conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &error);
if (conn == NULL) {
if (dbus_error_is_set(&error) == TRUE) {
ofono_error("Unable to hop onto D-Bus: %s",
@@ -308,7 +310,12 @@ int main(int argc, char **argv)
g_free(option_plugin);
g_free(option_noplugin);
if (g_dbus_request_name(conn, OFONO_SERVICE, &error)) {
g_main_loop_run(event_loop);
} else {
ofono_error("Unable to register D-Bus name: %s", error.message);
dbus_error_free(&error);
}
__ofono_plugin_cleanup();