/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: gsmdevice.cpp 1502 2007-04-15 07:54:20Z itsme $ */ #include #include "debug.h" #include "gsmdevice.h" //#include "ril.h" #include GsmDevice::GsmDevice() { DebugSetLogfile("gsmdev.log"); m_hCom= NULL; m_hRilDev= NULL; // m_hRil= NULL; } GsmDevice::~GsmDevice() { close(); } bool GsmDevice::open() { m_hCom= CreateFile(L"COM2:",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0); if (m_hCom==NULL || m_hCom==INVALID_HANDLE_VALUE) { error("CreateFile('COM2:')"); m_hCom= NULL; return false; } DCB dcb; if (!GetCommState(m_hCom, &dcb)) { error("GetCommState('COM2:')"); return false; } dcb.BaudRate= CBR_115200; dcb.ByteSize= 8; dcb.fParity= false; dcb.StopBits= ONESTOPBIT; dcb.fAbortOnError= false; if (!SetCommState(m_hCom, &dcb)) { error("SetCommState('COM2:')"); return false; } if (!EscapeCommFunction(m_hCom, SETDTR)) { error("EscapeCommFunction('COM2:', SETDTR)"); return false; } if (!EscapeCommFunction(m_hCom, SETRTS)) { error("EscapeCommFunction('COM2:', SETRTS)"); return false; } COMMTIMEOUTS to; if (!GetCommTimeouts(m_hCom, &to)) { error("GetCommTimeouts('COM2:')"); return false; } to.ReadIntervalTimeout= 100; to.ReadTotalTimeoutConstant= 2000; to.ReadTotalTimeoutMultiplier= 20; to.WriteTotalTimeoutConstant= 20000; to.WriteTotalTimeoutMultiplier= 20; if (!SetCommTimeouts(m_hCom, &to)) { error("SetCommTimeouts('COM2:')"); return false; } if (!SetCommMask(m_hCom, EV_RXCHAR)) { error("SetCommMask('COM2:')"); return false; } flush(); debug("GsmDevice::open : OK\n"); m_hRilDev= CreateFile(L"RIL1:",GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,0); if (m_hRilDev==NULL || m_hRilDev==INVALID_HANDLE_VALUE) { error("CreateFile('RIL1:')"); return false; } debug("rildevice open OK\n"); return true; } bool GsmDevice::DisableRIL() { /* if (!RIL_Initialize(1, NULL, NULL, 0x00040000L, NULL, &m_hRil)) { error("RIL_Initialize"); return false; } debug("status=%08lx\n", RIL_GetRegistrationStatus(m_hRil)); */ DWORD nReturned; DWORD rildevresult; if (!DeviceIoControl(m_hRilDev, 0x03000314L,0,0, &rildevresult, sizeof(DWORD), &nReturned,0)) { error("DeviceIoControl('RIL1:', 0x03000314L)"); return false; } BYTE comdevcmd[2]= {0x84, 0x00}; if (!DeviceIoControl (m_hCom,0xAAAA5679L, comdevcmd, sizeof(comdevcmd),0,0,0,0)) { error("DeviceIoControl('COM2:', 0xAAAA5679L)"); return false; } debug("DisableRIL : OK\n"); return true; } bool GsmDevice::EnableRIL() { DWORD nReturned; DWORD rildevresult; if (!DeviceIoControl(m_hRilDev, 0x03000318L,0,0, &rildevresult, sizeof(DWORD), &nReturned,0)) { error("DeviceIoControl('RIL1', 0x03000318L)"); return false; } debug("EnableRIL: OK\n"); return true; } bool GsmDevice::close() { if (m_hCom!=NULL) { CloseHandle(m_hCom); m_hCom= NULL; } /* if (m_hRil) { RIL_Deinitialize(m_hRil); m_hRil= NULL; } */ if (m_hRilDev) { CloseHandle(m_hRilDev); m_hRilDev= NULL; } debug("GsmDevice::close : OK\n"); return true; } bool GsmDevice::Reset() { flush(); *(DWORD*)0xa4000068 |= 0x40; *(DWORD*)0xa4000068 &= ~0x40; Sleep(100); *(DWORD*)0xa4000068 |= 0x40; Sleep(2000); debug("reset status: %d\n", (*(DWORD*)0xa9040000)&2); std::string reply; if (!receive(reply)) { debug("ERROR: Reset: no reply after reset\n"); return false; } size_t pos= reply.find("Interpreter ready"); if (pos==reply.npos) { debug("ERROR: Reset: reply=%hs\n", reply.c_str()); return false; } debug("Reset: OK\n"); return true; } bool GsmDevice::SendData(BYTE *buf, DWORD len) { DWORD nWritten; if (!WriteFile(m_hCom, buf, len, &nWritten, NULL)) { error("WriteFile(%08lx 'COM2:', %d)", m_hCom, len); return false; } if (nWritten!=len) { debug("ERROR: SendData: wrote %d iso %d\n", nWritten, len); return false; } debug("SendData: OK\n"); return true; } bool GsmDevice::SendByte(BYTE c) { return SendData(&c, sizeof(BYTE)); } bool GsmDevice::ReceiveData(BYTE *buf, int maxlen, DWORD *pnRead) { DWORD event; if (!WaitCommEvent(m_hCom, &event, NULL)) { error("WaitCommEvent('COM2:')", maxlen); return false; } *pnRead= 0; while (maxlen) { DWORD nRead; if (!ReadFile(m_hCom, buf, maxlen, &nRead, NULL)) { error("ReadFile('COM2:', %d)", maxlen); return false; } if (nRead==0) break; buf += nRead; maxlen -= nRead; *pnRead += nRead; } debug("ReceiveData: OK\n"); return true; } /* #define VSP_END_OF_MESSAGE 0x02 bool GsmDevice::SendEndOfMessage() { return SendByte(VSP_END_OF_MESSAGE); } bool GsmDevice::vspsend(int channel, CString& str) { int datalen= str.GetLength(); BYTE *data= new BYTE[datalen+1]; _snprintf((char*)data, datalen, "%ls", str.GetBuffer(0)); bool bRes= SendEndOfMessage() && SendByte(channel) && SendData(data, datalen) && SendEndOfMessage(); delete data; return bRes; } bool GsmDevice::vspreceive(int channel, CString& str) { BYTE data[512+1]; DWORD nRead; if (!ReceiveData(data, 512, &nRead)) return false; data[nRead]= 0; int i=0; while (i<512) { if (data[i]==channel) break; i++; } if (i==512) return false; int j=i; while (j<512) { if (data[j]==VSP_END_OF_MESSAGE) break; j++; } if (j==512) debug("warning: no end of message\n"); data[j]= 0; str.Format(L"%hs", data+i); return true; } */ bool GsmDevice::send(const std::string& str) { debug("send: %hs\n", str.c_str()); int datalen= str.size(); BYTE *data= new BYTE[datalen+1]; _snprintf((char*)data, datalen, "%hs", str.c_str()); bool bRes= true; if (!SendData(data, datalen)) { bRes= false; debug("ERROR: send: SendData failed\n"); } delete data; if (bRes) debug("send: OK\n"); return bRes; } bool GsmDevice::dataWaiting() { COMSTAT stat; DWORD dwError; if (!ClearCommError(m_hCom, &dwError, &stat)) { error("ClearCommError"); return false; } return stat.cbInQue!=0; } bool GsmDevice::receive(std::string& str) { BYTE data[640+1]; debug("receive: waiting for data\n"); do { DWORD nRead; if (!ReceiveData(data, 640, &nRead)) { debug("ERROR: receive: ReceiveData failed\n"); return false; } data[nRead]= 0; str.erase(); str.reserve(nRead); for (DWORD i=0 ; i4 || nSize==3 || (addr&1)!=0) { debug("ERROR: WriteBlock(%08lx, %d) - parameter error\n", addr, nSize); return false; } char cmd[40]; switch(nSize) { case 1: sprintf(cmd, "AT%%UREG=%08lx,%02x,%02x\r", addr, buf[0], nSize); break; case 2: sprintf(cmd, "AT%%UREG=%08lx,%02x%02x,%02x\r", addr, buf[1], buf[0], nSize); break; case 4: sprintf(cmd, "AT%%UREG=%08lx,%02x%02x%02x%02x,%02x\r", addr, buf[3], buf[2], buf[1], buf[0], nSize); break; default: return false; } if (!send(cmd)) { debug("ERROR: WriteBlock - error sending %hs\n", cmd); return false; } std::string reply; if (!receive(reply)) { debug("ERROR: WriteBlock - error reading reply\n"); return false; } if (reply.find("User mode register")!=reply.npos) { debug("ERROR: WriteBlock - invalid address - resetting gsm\n"); SetLastError(ERROR_INVALID_ADDRESS); Reset(); return false; } // todo: verify result. return true; } BYTE nyble(char c) { if (c>='0' && c<='9') return c-'0'; if (c>='a' && c<='f') return c-'a'+10; if (c>='A' && c<='F') return c-'A'+10; return 0; } bool ParseUregReply(const std::string& hexstr, BYTE* buf) { BYTE *p= buf; // todo: I think this needs either a 16bit word swap, or complete order reversal. for (std::string::const_reverse_iterator i= hexstr.rbegin() ; i != hexstr.rend() ; ) { BYTE b= nyble(*i++); *p++= b | nyble(*i++)<<4; } debug("ParseUregReply: OK\n"); return true; } bool GsmDevice::ReadBlock(BYTE *buf, DWORD addr, DWORD nSize) { debug("ReadBlock(%08lx, %04x)\n", addr, nSize); if (nSize>100 || (addr&1)!=0) { debug("ERROR: ReadBlock(%08lx, %d) - parameter error\n", addr, nSize); return false; } char cmd[40]; sprintf(cmd, "AT%%UREG?%08lx,%02x\r", addr, nSize); if (!send(cmd)) { debug("ERROR: ReadBlock - error sending %hs\n", cmd); return false; } std::string reply; if (!receive(reply)) { debug("ERROR: ReadBlock - error reading reply\n"); return false; } if (reply.find("User mode register")!=reply.npos) { debug("ERROR: ReadBlock - invalid address - resetting gsm\n"); SetLastError(ERROR_INVALID_ADDRESS); Reset(); return false; } size_t uregpos= reply.find("EXT_UREG"); if (uregpos==reply.npos) { debug("ERROR: ReadBlock - no EXT_UREG in reply: %hs\n", reply.c_str()); return false; } size_t crlfpos= reply.find("\r\n", uregpos); if (crlfpos==reply.npos) { debug("ERROR: ReadBlock - no crlf in reply: %hs\n", reply.c_str()); return false; } if (crlfpos-uregpos-9!=2*nSize) { debug("ERROR: ReadBlock - reply length incorrect: (%d, expected %d) %hs\n", crlfpos-uregpos-9, 2*nSize, reply.c_str()); return false; } if (!ParseUregReply(reply.substr(uregpos+9, 2*nSize), buf)) { debug("ERROR: ReadBlock - could not parse answer: %hs\n", reply.c_str()); return false; } debug("ReadBlock: OK\n"); return true; }