blob: ea605890937aa5782e2bd4fc6adf8e37f7fe94f3 [file] [log] [blame]
#include <core/Logger.h>
#include "../ui/StatusBar.h"
#include "../ui/HomeScreen.h"
#include "MGuiRil.h"
#define RIL_UBUS_ID "ril"
namespace MGUI
{
D_DEBUG_DOMAIN(MGUI_RIL, "Mgui/Ril", "Ril");
D_DEBUG_DOMAIN(MGUI_OPERATOR, "Mgui/Ril/Operator", "Operator");
D_DEBUG_DOMAIN(MGUI_SIMCARD, "Mgui/Ril/Sim", "Simcard");
D_DEBUG_DOMAIN(MGUI_REGISTRATION, "Mgui/Ril/Registration", "Registration");
D_DEBUG_DOMAIN(MGUI_RSSI, "Mgui/Ril/SignalStrength", "Signal Strength");
/***************************************************************************/
/** MGuiRil Class Implementation **/
/***************************************************************************/
const std::vector<std::string> MGuiRil:: _events({
"ril.unsol.cc",
"ril.unsol.dev",
"ril.unsol.mm",
"ril.unsol.msg",
"ril.unsol.ps",
"ril.unsol.sim",
"ril.unsol.ss",
"ril.unsol"
});
MGuiRil *MGuiRil:: _instance = 0;
static int ril_indication(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req,
const char *method, struct blob_attr *msg)
{
MGuiRil *__this = MGuiRil::Instance();
if (!__this) {
ILOG_ERROR(MGUI_RIL, "No instance, indication ignored!\n");
return -1;
}
return __this->Indication(ctx, obj, req, method, msg);
}
enum {
REQID,
ERRNO,
DATA,
_MAX
};
#undef blob_for_each_attr
#define blob_for_each_attr(pos, attr, rem) \
for (rem = attr ? blob_len(attr) : 0, \
pos = attr ? (blob_attr*)blob_data(attr) : 0; \
rem > 0 && (blob_pad_len(pos) <= rem) && \
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
rem -= blob_pad_len(pos), pos = blob_next(pos))
int MGuiRil:: parse_blobmsg(struct blob_attr *attr, struct blob_attr **tb)
{
blob_attr *pos = NULL;
blobmsg_hdr *hdr = NULL;
const char *policy[] = { "rilid", "resperrno" };
unsigned int rem = 0;
int i = 0;
blob_for_each_attr(pos, attr, rem) {
if (i > _MAX)
return 0;
hdr = (blobmsg_hdr *)blob_data(pos);
if (i == 0) {
if (strcmp(policy[i], (char *)hdr->name) != 0) {
ILOG_ERROR(MGUI_RIL, "format error\n");
return -1;
}
}
tb[i] = pos;
i++;
}
return 0;
}
int MGuiRil::Indication(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req,
const char *method, struct blob_attr *msg)
{
unsigned int id = 0;
unsigned int errcode = 0;
void *data = NULL;
int len = 0;
int ret = 0;
blob_attr *tb[_MAX] = { 0 };
ILOG_TRACE_F(MGUI_RIL);
ret = parse_blobmsg(msg, tb);
if (ret < 0) {
ILOG_ERROR(MGUI_RIL, "parse msg error\n");
return -1;
}
if (tb[REQID])
id = blobmsg_get_u32(tb[REQID]);
if (tb[ERRNO]) {
errcode = blobmsg_get_u32(tb[ERRNO]);
if (errcode) {
ILOG_ERROR(MGUI_RIL, "unsolicited id %d blobmsg err %d\n",
id, errcode);
return -1;
}
}
if (tb[DATA]) {
data = blob_data(tb[DATA]);
len = blobmsg_data_len(tb[DATA]);
}
ILOG_DEBUG(MGUI_RIL, "id is %d, data = %p, len = %d\n", id, data, len);
switch(id)
{
case RIL_UNSOL_SIGNAL_STRENGTH:
ILOG_DEBUG(MGUI_RIL,"Signal Strength indication\n");
SignalStrengthInd(data, len);
break;
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
ILOG_DEBUG(MGUI_RIL,"Sim state changed\n");
case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
ILOG_DEBUG(MGUI_RIL,"Radio state changed\n");
case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
ILOG_DEBUG(MGUI_RIL,"Voice registration status changed\n");
case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED:
ILOG_DEBUG(MGUI_RIL,"Radio technology changed\n");
SendRequests();
break;
default:
ILOG_DEBUG(MGUI_RIL, "id of %d is not supported\n",id);
ret = 0;
}
ILOG_DEBUG(MGUI_RIL, "%s exit\n", __FUNCTION__);
return 0;
}
MGuiRil* MGuiRil::Instance()
{
return _instance;
}
int MGuiRil::Create(ubus_context *ubus, StatusBar *bar, HomeScreen *home)
{
int ret;
ILOG_TRACE_F(MGUI_RIL);
if (_instance) {
ILOG_ERROR(MGUI_RIL, "Already created\n");
return -1;
}
_instance = new MGuiRil(ubus, bar, home);
ret = _instance->Register();
if (ret) {
ILOG_ERROR(MGUI_RIL, "Register failed (ret=%d)\n", ret);
goto out_error;
}
ILOG_DEBUG(MGUI_RIL, "%s exit\n", __FUNCTION__);
return 0;
out_error:
delete _instance;
_instance = NULL;
return -1;
}
void MGuiRil::Destroy()
{
ILOG_TRACE_F(MGUI_RIL);
if (_instance) {
_instance->UnRegister();
delete _instance->_operator;
delete _instance->_simcard;
delete _instance->_registration;
delete _instance->_screen;
delete _instance;
_instance = NULL;
}
}
MGuiRil::MGuiRil(ubus_context *ubus, StatusBar *bar, HomeScreen *home)
: UBusClient(ubus),
_bar(bar),
_home(home)
{
}
MGuiRil::~MGuiRil()
{
}
void MGuiRil::SendRequests()
{
ILOG_TRACE(MGUI_RIL);
if (_instance) {
_simcard->Request();
_operator->Request();
_registration->Request();
_screen->Request(1);
}
ILOG_DEBUG(MGUI_RIL, "%s exit\n", __FUNCTION__);
}
int MGuiRil::Register()
{
int ret;
ILOG_TRACE(MGUI_RIL);
ret = UBusClient::Register(ril_indication, RIL_UBUS_ID);
if (ret) {
ILOG_ERROR(MGUI_RIL, "Register failed %d\n", ret);
return ret;
}
ret = UBusClient::Subscribe(_events);
if (ret) {
ILOG_ERROR(MGUI_RIL, "Subscribe events failed %d\n", ret);
goto unregister;
}
_operator = new RilOperator(_subscriber, _id, _ubus);
_simcard = new RilSimcard(_subscriber, _id, _ubus);
_registration = new RilRegistration(_subscriber, _id, _ubus);
_screen = new RilScreen(_subscriber, _id, _ubus);
SendRequests();
ILOG_DEBUG(MGUI_RIL, "%s exit\n", __FUNCTION__);
return 0;
unregister:
UBusClient::UnRegister();
return ret;
}
int MGuiRil::UnRegister()
{
ILOG_TRACE(MGUI_RIL);
_screen->Request(0);
return UBusClient::UnRegister();
}
int MGuiRil::OperatorCallback(blob_attr *msg)
{
unsigned int requestid;
unsigned int rilerrno = 0;
void *data = NULL;
int datalen = 0;
int ret = 0;
ILOG_TRACE(MGUI_OPERATOR);
ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &data, &datalen);
rilutilstrings *resp = (rilutilstrings *)data;
if (ret || rilerrno) {
ILOG_ERROR(MGUI_OPERATOR, "RIL ERROR: ret=%d, requestid=%d, rilerrno=%d\n",
ret, requestid, rilerrno);
goto done;
}
if (!resp || resp->num != 3) {
ILOG_ERROR(MGUI_OPERATOR, "No operator found\n");
_home->SetCellularInfo("Operator Unknown");
} else {
/* operator present */
ILOG_DEBUG(MGUI_OPERATOR, "Operator = %s\n", resp->str[0]);
_home->SetCellularInfo(resp->str[0]);
}
done:
if (data)
rilutil_freeResponseData(requestid, data, datalen);
ILOG_DEBUG(MGUI_OPERATOR, "%s:%d: Exit\n", __FUNCTION__, __LINE__);
return ret;
}
int MGuiRil::SimCallback(blob_attr *msg)
{
unsigned int requestid;
unsigned int rilerrno = 0;
void *data = NULL;
int datalen = 0;
int ret = 0;
ILOG_TRACE(MGUI_SIMCARD);
ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &data, &datalen);
if (ret || rilerrno || !data) {
ILOG_ERROR(MGUI_SIMCARD, "RIL ERROR: ret=%d, requestid=%d, rilerrno=%d, data=%p\n",
ret, requestid, rilerrno, data);
goto done;
}
RIL_CardState SimStatus = ((RIL_CardStatus_v6 *)data)->card_state;
switch (SimStatus) {
case RIL_CARDSTATE_ABSENT:
_bar->setSimState(SimMissing);
ILOG_DEBUG(MGUI_SIMCARD, "Simcard absent\n");
break;
case RIL_CARDSTATE_PRESENT:
_bar->setSimState(SimActive);
ILOG_DEBUG(MGUI_SIMCARD, "Simcard present\n");
break;
case RIL_CARDSTATE_ERROR:
_bar->setSimState(SimUnknown);
ILOG_DEBUG(MGUI_SIMCARD, "Simcard error\n");
break;
}
done:
if (data)
rilutil_freeResponseData(requestid, data, datalen);
ILOG_DEBUG(MGUI_SIMCARD, "%s:%d: Exit\n", __FUNCTION__, __LINE__);
return ret;
}
int MGuiRil::RegistrationCallback(blob_attr *msg)
{
unsigned int requestid;
unsigned int rilerrno = 0;
void *data = NULL;
int datalen = 0;
int ret = 0;
RegState *result;
ILOG_TRACE(MGUI_REGISTRATION);
ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &data, &datalen);
rilutilstrings *resp = (rilutilstrings *)data;
if (ret || rilerrno || !data) {
ILOG_ERROR(MGUI_SIMCARD, "RIL ERROR: ret=%d, requestid=%d, rilerrno=%d, data=%p\n",
ret, requestid, rilerrno, data);
if (data)
rilutil_freeResponseData(requestid, data, datalen);
return ret;
}
if (resp->num < 2) {
ILOG_ERROR(MGUI_REGISTRATION, "wrong resp->num=%d\n", resp->num);
return -1;
}
result = (requestid == RIL_REQUEST_VOICE_REGISTRATION_STATE) ? &_voice : &_data;
sscanf(resp->str[0], "%d", &result->reg_state);
if (resp->num >= 5)
sscanf(resp->str[3], "%d", (int *)&result->radio_tech);
if (data)
rilutil_freeResponseData(requestid, data, datalen);
if (requestid == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
ILOG_DEBUG(MGUI_REGISTRATION, "Voice: %s registered\n", registered_voice() ? "" : "not");
_bar->setCellularState(Cellular0NoData);
}
if (requestid == RIL_REQUEST_DATA_REGISTRATION_STATE) {
ILOG_DEBUG(MGUI_REGISTRATION, "Data: %s registered\n", registered_data() ? "" : "not");
_bar->setCellularState(Cellular0);
}
_bar->setCellularTechState(tech());
ILOG_DEBUG(MGUI_REGISTRATION, "Radio Technology: %s\n", tech_to_str());
ILOG_DEBUG(MGUI_REGISTRATION, "%s:%d: Exit\n", __FUNCTION__, __LINE__);
return 0;
}
bool MGuiRil::registered_voice()
{
return (_voice.reg_state == 1 || _voice.reg_state == 5);
}
bool MGuiRil::registered_data()
{
return (_data.reg_state == 1 || _data.reg_state == 5);
}
CellularTechState
MGuiRil::tech()
{
switch (_voice.radio_tech) {
case RADIO_TECH_GPRS: return CellularTech2G; /* 2G */
case RADIO_TECH_EDGE: return CellularTechEdge; /* E */
case RADIO_TECH_UMTS: return CellularTech3G; /* 3G */
case RADIO_TECH_HSDPA:
case RADIO_TECH_HSUPA:
case RADIO_TECH_HSPAP: return CellularTechHSDPAP; /* H */
case RADIO_TECH_HSPA: return CellularTechHSDPA; /* H+ */
case RADIO_TECH_LTE: return CellularTech4G; /* 4G */
case RADIO_TECH_LTEP: return CellularTech4G; /* in future we need to modify it to 4G+ when we implement MGUI */
case RADIO_TECH_GSM: return CellularTechG; /* G */
default: return CellularTechUnknown; /* ? */
}
}
const char *
MGuiRil::tech_to_str()
{
switch (_voice.radio_tech) {
case RADIO_TECH_GPRS: return "2G";
case RADIO_TECH_EDGE: return "EDGE";
case RADIO_TECH_UMTS: return "3G";
case RADIO_TECH_HSDPA:
case RADIO_TECH_HSUPA:
case RADIO_TECH_HSPAP: return "H+";
case RADIO_TECH_HSPA: return "H";
case RADIO_TECH_LTE: return "4G";
case RADIO_TECH_GSM: return "GSM";
default: return "Unknown";
}
}
int MGuiRil::convertDbmToRssi(int rsrp)
{
if(rsrp == INT_MAX)
_rssi = 99;
else if(rsrp < -113)
_rssi = 0;
else if(rsrp > -51)
_rssi = 31;
else
_rssi = (113 + rsrp) / 2;
return 0;
}
void MGuiRil::SignalStrengthInd(void *data, int len)
{
ILOG_TRACE(MGUI_RSSI);
RIL_SignalStrength_v6 *rssi = (RIL_SignalStrength_v6 *)data;
if (tech() == CellularTech4G) {
ILOG_DEBUG(MGUI_RSSI, "in LTE, using rsrp == %d as rssi value\n",
rssi->LTE_SignalStrength.rsrp);
convertDbmToRssi(rssi->LTE_SignalStrength.rsrp);
} else {
ILOG_DEBUG(MGUI_RSSI, "Not LTE, rssi = %d\n",
rssi->GW_SignalStrength.signalStrength);
_rssi = rssi->GW_SignalStrength.signalStrength;
}
ILOG_DEBUG(MGUI_RSSI, "rssi value changed to %d\n", _rssi);
if (!registered_voice()) {
ILOG_DEBUG(MGUI_RSSI, "no voice, no data\n");
_bar->setCellularState(CellularNull);
} else if (!registered_data()) {
ILOG_DEBUG(MGUI_RSSI, "voice, no data\n");
if (_rssi >= 18)
_bar->setCellularState(Cellular4NoData);
else if (_rssi >= 13)
_bar->setCellularState(Cellular3NoData);
else if (_rssi >= 10)
_bar->setCellularState(Cellular2NoData);
else if (_rssi >= 5)
_bar->setCellularState(Cellular1NoData);
else
_bar->setCellularState(Cellular0NoData);
} else {
ILOG_DEBUG(MGUI_RSSI, "voice and data\n");
if (_rssi >= 18)
_bar->setCellularState(Cellular4);
else if (_rssi >= 13)
_bar->setCellularState(Cellular3);
else if (_rssi >= 10)
_bar->setCellularState(Cellular2);
else if (_rssi >= 5)
_bar->setCellularState(Cellular1);
else
_bar->setCellularState(Cellular0);
}
ILOG_DEBUG(MGUI_RSSI, "%s:%d: Exit\n", __FUNCTION__, __LINE__);
}
};