#include #include #include "RilMonitor.h" #include "RilStructDecoder.h" #include "debug.h" #ifdef _BOOST_LITE #include "boost_lite.h" #else #include #endif #include "RilExceptions.h" typedef std::map FuncCalls; typedef std::multimap EventCalls; typedef std::pair EventRange; // this object contains the static callback function, as passed to rilinit. // also, it manages a list of outstanding requests, and returns answers to the correct callers. class rilmonitor_impl { private: FuncCalls _funccalls; boost::mutex _fnmutex; // protects access to _funccalls EventCalls _evtcalls; boost::mutex _evmutex; // protects access to _evtcalls HANDLE _handle; public: HRIL _hril; public: rilmonitor_impl(DWORD dwIndex); ~rilmonitor_impl(); void clear_events(); void clear_functions(); // ril framework void process_request(requesthandler_ptr rq); void register_notifier(eventhandler_ptr nh); void deregister_notifier(eventhandler_ptr nh); // registered with RIL_Initialize static void handle_ril_result(DWORD dwCode, HRESULT hrCmdID, const void *lpData, DWORD cbdata, DWORD dwParam); void HandleResult(long dwCode, HRESULT hrCmdID, const void *lpData, long cbdata); static void handle_ril_events(DWORD dwCode, const void *lpData, DWORD cbdata, DWORD dwParam); void HandleEvent(DWORD dwCode, const void *lpData, DWORD cbdata); HANDLE handle(); }; // ============================================================================= // ================== function result handlers ================================= // ============================================================================= // // ------- RIL_GetSignalQuality class SignalQualityHandler : public requesthandler { private: HRIL _hril; long &_level; public: SignalQualityHandler(HRIL hril, long&level) : _hril(hril), _level(level) { } virtual std::string name() const { return "GetSignalQuality"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { //debug("mon:fromthread - SignalQualityHandler::handle\n"); checksize(data, size, sizeof(RILSIGNALQUALITY)); const RILSIGNALQUALITY *pd= static_cast(data); debug("Handle%sAnswer : %s\n", name().c_str(), GetSignalQualityString(pd).c_str()); _level= pd->nSignalStrength; } virtual int request() { HRESULT hr= RIL_GetSignalQuality(_hril); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::GetSignalQuality(long &level) { requesthandler_ptr rq(new SignalQualityHandler(_->_hril, level)); _->process_request(rq); return rq; } // ------- RIL_GetUserIdentity class UserIdentityHandler : public requesthandler { private: HRIL _hril; std::string& _imsi; public: UserIdentityHandler(HRIL hril, std::string& imsi) : _hril(hril), _imsi(imsi) { } virtual std::string name() const { return "GetUserIdentity"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { //debug("mon:fromthread - UserIdentityHandler::handle\n"); const char*pd= static_cast(data); debug("Handle%sAnswer :%d: %s\n", name().c_str(), size, pd); _imsi= pd; } virtual int request() { HRESULT hr= RIL_GetUserIdentity(_hril); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::GetUserIdentity(std::string& imsi) { requesthandler_ptr rq(new UserIdentityHandler(_->_hril, imsi)); _->process_request(rq); return rq; } // ------- RIL_GetEquipmentInfo class EquipmentInfoHandler : public requesthandler { private: HRIL _hril; std::string& _imei; public: EquipmentInfoHandler(HRIL hril, std::string& imei) : _hril(hril), _imei(imei) { } virtual std::string name() const { return "GetEquipmentInfo"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { //debug("mon:fromthread - EquipmentInfoHandler::handle\n"); checksize(data, size, sizeof(RILEQUIPMENTINFO)); const RILEQUIPMENTINFO *pd= static_cast(data); debug("Handle%sAnswer : %s\n", name().c_str(), GetEquipmentInfoString(pd).c_str()); _imei= pd->szSerialNumber; } virtual int request() { HRESULT hr= RIL_GetEquipmentInfo(_hril); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::GetEquipmentInfo(std::string &imei) { requesthandler_ptr rq(new EquipmentInfoHandler(_->_hril, imei)); _->process_request(rq); return rq; } // ------- RIL_GetEquipmentState class GetEquipmentStateHandler : public requesthandler { private: HRIL _hril; DWORD &_state; public: GetEquipmentStateHandler(HRIL hril, DWORD&state) : _hril(hril), _state(state) { } virtual std::string name() const { return "GetEquipmentState"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { //debug("mon:fromthread - GetEquipmentStateHandler::handle\n"); checksize(data, size, sizeof(RILEQUIPMENTSTATE)); const RILEQUIPMENTSTATE *pd= static_cast(data); debug("Handle%sAnswer : %s\n", name().c_str(), GetEquipmentStateString(pd).c_str()); // dwEqState: UNKNOWN, MINIMUM, FULL, DISABLETX, DISABLERX, DISABLETXANDRX // dwRadioSupport: UNKNOWN, OFF, ON // dwReadyState: bitmask ( NONE, INITIALIZED, SIM, SMS, UNLOCKED ) _state= pd->dwEqState; } virtual int request() { HRESULT hr= RIL_GetEquipmentState(_hril); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::GetEquipmentState(DWORD &state) { requesthandler_ptr rq(new GetEquipmentStateHandler(_->_hril, state)); _->process_request(rq); return rq; } // ------- RIL_SetEquipmentState class SetEquipmentStateHandler : public requesthandler { private: HRIL _hril; DWORD _state; public: SetEquipmentStateHandler(HRIL hril, DWORD state) : _hril(hril), _state(state) { } virtual std::string name() const { return "SetEquipmentState"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { //debug("mon:fromthread - SetEquipmentStateHandler::handle\n"); debug("Handle%sAnswer : %08lx:%08lx\n", name().c_str(), data, size); } virtual int request() { HRESULT hr= RIL_SetEquipmentState(_hril, _state); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::SetEquipmentState(DWORD state) { requesthandler_ptr rq(new SetEquipmentStateHandler(_->_hril, state)); _->process_request(rq); return rq; } // ------- RIL_SendRestrictedSimCmd class RestrictedSimCmdHandler : public requesthandler { private: HRIL _hril; DWORD _dwCommand; DWORD _dwFileId; const BYTE* _lpbData; DWORD _dwSize; DWORD _nParams; int _p1; int _p2; int _p3; public: RestrictedSimCmdHandler(HRIL hril, DWORD dwCommand, DWORD dwFileId, const BYTE* lpbData, DWORD dwSize, DWORD nParams, int p1, int p2, int p3) : _hril(hril), _dwCommand(dwCommand), _dwFileId(dwFileId), _lpbData(lpbData), _dwSize(dwSize), _nParams(nParams), _p1(p1),_p2(p2),_p3(p3) { } virtual std::string name() const { return "SendRestrictedSimCmd"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { //debug("mon:fromthread - RestrictedSimCmdHandler::handle\n"); checkminsize(data, size, sizeof(RILSIMRESPONSE)); const RILSIMRESPONSE *pd= static_cast(data); debug("Handle%sAnswer %04x:%03d: %s\n", name().c_str(), _dwFileId, _p1, GetRestrictedSimCmdString(pd, size).c_str()); } // transparent EF -> READBINARY : class=0xa0, p1.bit8=0, p1.b7-1 = offset, p3=size // linfix+cycl EF -> READRECORD : class=0xa0, p1=recnr, p2='02'(next),'03'(prev),'04'(abs), p3=size // see 51.011, which refers to TS 102 221 // virtual int request() { RILSIMCMDPARAMETERS simcmd; memset(&simcmd, 0, sizeof(RILSIMCMDPARAMETERS)); simcmd.cbSize= sizeof(RILSIMCMDPARAMETERS); simcmd.dwParams= RIL_PARAM_SCP_FILEID; simcmd.dwFileID= _dwFileId; if (_nParams>0) { simcmd.dwParameter1= _p1; simcmd.dwParams |= RIL_PARAM_SCP_PARAM1; } if (_nParams>1) { simcmd.dwParameter2= _p2; simcmd.dwParams |= RIL_PARAM_SCP_PARAM2; } if (_nParams>2) { simcmd.dwParameter3= _p3; simcmd.dwParams |= RIL_PARAM_SCP_PARAM3; } HRESULT hr= RIL_SendRestrictedSimCmd(_hril, _dwCommand, &simcmd, _lpbData, _dwSize); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::SendRestrictedSimCmd(DWORD dwCommand, DWORD dwFileId, const BYTE* lpbData, DWORD dwSize, DWORD nParams, int p1, int p2, int p3) { requesthandler_ptr rq(new RestrictedSimCmdHandler(_->_hril, dwCommand, dwFileId, lpbData, dwSize, nParams, p1,p2,p3)); _->process_request(rq); return rq; } // ------- RIL_GetSimRecordStatus // // transparent EF -> READBINARY : class=0xa0, p1.bit8=0, p1.b7-1 = offset, p3=size // linfix+cycl EF -> READRECORD : class=0xa0, p1=recnr, p2='02'(next),'03'(prev),'04'(abs), p3=size // see 51.011, which refers to TS 102 221 // class SimRecordStatusHandler : public requesthandler { private: HRIL _hril; DWORD _dwFileId; int &_type; size_t &_itemcount; size_t &_itemsize; public: SimRecordStatusHandler(HRIL hril, DWORD dwFileId, int& type, size_t& itemcount, size_t& itemsize) : _hril(hril), _dwFileId(dwFileId), _type(type), _itemcount(itemcount), _itemsize(itemsize) { } virtual std::string name() const { return "GetSimRecordStatus"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { //debug("mon:fromthread - SimRecordStatusHandler::handle\n"); checkminsize(data, size, sizeof(RILSIMRECORDSTATUS)); const RILSIMRECORDSTATUS*pd= static_cast(data); debug("Handle%sAnswer %04x: %s\n", name().c_str(), _dwFileId, GetSimRecordStatusString(pd, size).c_str()); _type= pd->dwRecordType; _itemcount= pd->dwItemCount; _itemsize= pd->dwSize; } virtual void error(DWORD dwError) { if (dwError!=E_FAIL) debug("%sError: %04x: %s\n", name().c_str(), _dwFileId, RilErrorString(dwError).c_str()); requesthandler::error(dwError); } virtual int request() { HRESULT hr= RIL_GetSimRecordStatus(_hril, _dwFileId); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::GetSimRecordStatus(DWORD dwFileId, int& type, size_t& itemcount, size_t& itemsize) { requesthandler_ptr rq(new SimRecordStatusHandler(_->_hril, dwFileId, type, itemcount, itemsize)); _->process_request(rq); return rq; } // ------- RIL_DevSpecific // class DevSpecificHandler : public requesthandler { private: HRIL _hril; const ByteVector& _request; ByteVector& _response; public: DevSpecificHandler(HRIL hril, const ByteVector& request, ByteVector& response) : _hril(hril), _request(request), _response(response) { } virtual std::string name() const { return "DevSpecific"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { _response.resize(size); memcpy(&_response[0], data, size); } virtual void error(DWORD dwError) { if (dwError!=E_FAIL) debug("%s Error: %02x : %s\n", name().c_str(), _request[0], RilErrorString(dwError).c_str()); requesthandler::error(dwError); } virtual int request() { HRESULT hr= RIL_DevSpecific(_hril, &_request.front(), _request.size()); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::DevSpecific(const ByteVector& request, ByteVector& response) { requesthandler_ptr rq(new DevSpecificHandler(_->_hril, request, response)); _->process_request(rq); return rq; } // ------- RIL_Dial // class DialHandler : public requesthandler { private: HRIL _hril; std::string _nr; DWORD _type; DWORD _opts; public: DialHandler(HRIL hril, const std::string& nr, DWORD type, DWORD opts) : _hril(hril), _nr(nr), _type(type), _opts(opts) { } virtual std::string name() const { return "Dial"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { // expect NULL } virtual void error(DWORD dwError) { if (dwError!=E_FAIL) debug("%sError: %s : %s\n", name().c_str(), RilErrorString(dwError).c_str(), _nr.c_str()); requesthandler::error(dwError); } virtual int request() { HRESULT hr= RIL_Dial(_hril, _nr.c_str(), _type, _opts); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::Dial(const std::string& nr, DWORD type, DWORD opts) { requesthandler_ptr rq(new DialHandler(_->_hril, nr, type, opts)); _->process_request(rq); return rq; } // ------- RIL_Answer // class AnswerHandler : public requesthandler { private: HRIL _hril; public: AnswerHandler(HRIL hril) : _hril(hril) { } virtual std::string name() const { return "Answer"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { // expect NULL } virtual void error(DWORD dwError) { if (dwError!=E_FAIL) debug("%sError: %s\n", name().c_str(), RilErrorString(dwError).c_str()); requesthandler::error(dwError); } virtual int request() { HRESULT hr= RIL_Answer(_hril); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::Answer() { requesthandler_ptr rq(new AnswerHandler(_->_hril)); _->process_request(rq); return rq; } // ------- RIL_Hangup(0x33) // // used by uni_at.exe to send at commands // class HangupHandler : public requesthandler { private: HRIL _hril; public: HangupHandler(HRIL hril) : _hril(hril) { } virtual std::string name() const { return "Hangup"; } virtual void handle(long dwCode, const void *data, size_t size) throw() { } virtual void error(DWORD dwError) { if (dwError!=E_FAIL) debug("%sError: %s\n", name().c_str(), RilErrorString(dwError).c_str()); requesthandler::error(dwError); } virtual int request() { HRESULT hr= RIL_Hangup(_hril); if (hr<0) throw ril_error(name(), hr); return static_cast(hr); } }; requesthandler_ptr rilmonitor::Hangup() { requesthandler_ptr rq(new HangupHandler(_->_hril)); _->process_request(rq); return rq; } // ============================================================================= // ============================ event handlers ================================= // ============================================================================= // void rilmonitor::registerhandler(eventhandler_ptr handler) { _->register_notifier(handler); } void rilmonitor::deregisterhandler(eventhandler_ptr handler) { _->deregister_notifier(handler); } // ============================================================================= // ======================= synchronous ril funtions ============================ // ============================================================================= void rilmonitor::DumpDriverInfo() { HRESULT hr; RILSERIALPORTSTATS portstats; hr= RIL_GetSerialPortStatistics(_->_hril, &portstats); if (IS_ERROR(hr)) error(hr, "RIL_GetSerialPortStatistics"); debug("RIL_GetSerialPortStatistics: %hs\n", GetSerialPortStatisticsString(&portstats).c_str()); DWORD dwVersion; hr= RIL_GetDriverVersion(_->_hril, &dwVersion); if (IS_ERROR(hr)) error(hr, "RIL_GetDriverVersion"); debug("RIL_GetDriverVersion: version=%08lx\n", dwVersion); DWORD dwRadioPresence; hr= RIL_GetRadioPresence(_->_hril, &dwRadioPresence); if (IS_ERROR(hr)) error(hr, "RIL_GetRadioPresence"); debug("RIL_GetRadioPresence: presence=%hs\n", GetRadioPresenceString(dwRadioPresence).c_str()); } HANDLE rilmonitor_impl::handle() { HRESULT hr; if (_handle!=INVALID_HANDLE_VALUE) return _handle; hr= RIL_GetSerialPortHandle(_hril, &_handle); if (IS_ERROR(hr)) { error(hr, "RIL_GetSerialPortHandle"); _handle = INVALID_HANDLE_VALUE; } debug("RIL_GetSerialPortHandle: handle=%08lx\n", _handle); return _handle; } // ---------------------------------------------------------------- // implementation // ---------------------------------------------------------------- rilmonitor_impl::rilmonitor_impl(DWORD dwIndex) : _hril(0), _handle(INVALID_HANDLE_VALUE) { HRESULT res= RIL_Initialize(dwIndex, rilmonitor_impl::handle_ril_result, rilmonitor_impl::handle_ril_events, -1, reinterpret_cast(this), &_hril); if (res) throw ril_error("RIL_Initialize", res); } rilmonitor_impl::~rilmonitor_impl() { clear_events(); clear_functions(); if (_hril) { HRESULT res= RIL_Deinitialize(_hril); if (res) error("RIL_Deinitialize: %08lx\n", res); } } void rilmonitor_impl::clear_events() { boost::mutex::scoped_lock lock(_evmutex); _evtcalls.clear(); } void rilmonitor_impl::clear_functions() { boost::mutex::scoped_lock lock(_fnmutex); _funccalls.clear(); } rilmonitor::rilmonitor() { _= new rilmonitor_impl(1); } rilmonitor::~rilmonitor() { delete _; _= NULL; } void rilmonitor::write(const ByteVector& data) { DWORD n=0; if (!WriteFile(_->handle(), &data[0], data.size(), &n, 0)) throw win32_error("WriteFile"); } void rilmonitor::read(ByteVector& data, size_t n) { DWORD nr=0; data.resize(n); if (!ReadFile(_->handle(), &data[0], data.size(), &nr, 0)) throw win32_error("WriteFile"); data.resize(nr); } // --------- ril function result handling ----------- // processes a user request, and registers a handler to handle the async result from ril. void rilmonitor_impl::process_request(requesthandler_ptr rq) { boost::mutex::scoped_lock lock(_fnmutex); //debugt("%s : request\n", rq->name().c_str()); std::pair i= _funccalls.insert(FuncCalls::value_type(rq->request(), rq)); if (!i.second) throw ril_error("duplicate cmdid", E_FAIL); } // processes the answer from ril. void rilmonitor_impl::handle_ril_result(DWORD dwCode, HRESULT hrCmdID, const void *lpData, DWORD cbdata, DWORD dwParam) { reinterpret_cast(dwParam)->HandleResult(dwCode, hrCmdID, lpData, cbdata); } void rilmonitor_impl::HandleResult(long dwCode, HRESULT hrCmdID, const void *lpData, long cbdata) { //debug("mon:handle result\n"); requesthandler_ptr rq; // in block, to localize the lock. // -> not locked when processing the result. { boost::mutex::scoped_lock lock(_fnmutex); FuncCalls::iterator i= _funccalls.find(static_cast(hrCmdID)); if (i==_funccalls.end()) { debug("mon:ERROR:unknown cmdid %d\n", hrCmdID); return; } rq= (*i).second; _funccalls.erase(i); } //debugt("mon:handling result for hr=%d: %s\n", hrCmdID, rq->name().c_str()); try { switch(dwCode) { case RIL_RESULT_OK: rq->handle(dwCode, lpData, cbdata); break; case RIL_RESULT_ERROR: if (cbdata!=sizeof(DWORD)) debug("mon:ERROR: RIL_RESULT_ERROR, with cbdata=%d ( != 4 )\n", cbdata); else rq->error(*static_cast(lpData)); break; case RIL_RESULT_NOCARRIER : case RIL_RESULT_NODIALTONE : case RIL_RESULT_BUSY : case RIL_RESULT_NOANSWER : case RIL_RESULT_CALLABORTED: case RIL_RESULT_CALLDROPPED: rq->lineerror(dwCode); break; default: debug("mon:ERROR: unexpected error code: %08lx\n", dwCode); } } catch(ril_error& e) { debug("rilresult: %s %08lx: %s\n", rq->name().c_str(), e.err, e.name.c_str()); } catch(ril_structsize_error& e) { debug("rilresult: %s got %d, expected %d\n", rq->name().c_str(), e.got, e.expect); } catch(...) { debug("rilresult: %s unknown exception\n", rq->name().c_str()); } rq->notify(); } // --------- ril event handling ----------- void rilmonitor_impl::register_notifier(eventhandler_ptr nh) { boost::mutex::scoped_lock lock(_evmutex); _evtcalls.insert(EventCalls::value_type(nh->code(), nh)); // note: _evtcalls is a multimap -> insert will not fail if the key was already there. } void rilmonitor_impl::deregister_notifier(eventhandler_ptr nh) { EventRange range= _evtcalls.equal_range(nh->code()); if (range.first==range.second) throw "notifier not registered"; for (EventCalls::iterator i=range.first ; i!=range.second ; ++i) { if ((*i).second==nh) { _evtcalls.erase(i); } } } void rilmonitor_impl::handle_ril_events(DWORD dwCode, const void *lpData, DWORD cbdata, DWORD dwParam) { reinterpret_cast(dwParam)->HandleEvent(dwCode, lpData, cbdata); } void rilmonitor_impl::HandleEvent(DWORD dwCode, const void *lpData, DWORD cbdata) { boost::mutex::scoped_lock lock(_evmutex); EventRange range= _evtcalls.equal_range(dwCode); if (range.first==range.second) { debugt("mon:unhandled event %s\n", RilResultString(dwCode).c_str()); return; } // todo: don't lock _evtcalls when calling the handlers. for (EventCalls::iterator i=range.first ; i!=range.second ; ++i) { eventhandler_ptr rq= (*i).second; try { //debug("handling event %08lx: %08lx %08lx\n", dwCode, lpData, cbdata); //debug("[%s]\n", rq->name().c_str()); rq->handle(lpData, cbdata); } catch(ril_error& e) { debug("rilevent: %s %08lx: %s\n", rq->name().c_str(), e.err, e.name.c_str()); } catch(ril_structsize_error& e) { debug("rilevent: %s got %d, expected %d\n", rq->name().c_str(), e.got, e.expect); } catch(...) { debug("rilevent: %s unknown exception\n", rq->name().c_str()); } } }