Related
Hi
I want to make a call with my mda without using the RAS dialer. Direct access to the COM-ports does not work, as described in the document "Serial Communications". But that documents mentions that TAPI calls are possible with an xda.
It says:
"If you´ve establised a call, TAPI returns a handle for further data-i/o..."
Is there an example how to make a call using TAPI especially how to get that data-handle. And furthermore can I use that handle with WriteFile / ReadFile as I would use a handle to a COM-Port?
I did this for a terminal emulator I wrote. I pass a string to these functions which is COM1: for serial, TAPI for modem or RAS for TCPIP RAS.
I have simply copied some of my code here, work through it as if lpszPortName = "TAPI" and you should make sense of it. Once you have the port handle hPort which is returned by the Connected response of the TAPI call back function, then you can read and write as if that were a serial/file handle.
Cheers
Paul
#include <windows.h>
#include <string.h>
#include <tapi.h>
#include "toolbox.h"
//Initilise the port either the TAPI or COMM port as requested by lpszPortName
BOOL PortInitialize (LPTSTR lpszPortName)
{
DWORD dwError;
BOOL RetValue;
HKEY hKey;
DWORD RegKeyDisp, RegKeyType, RegKeySize;
DWORD dwTapiNumDevs;
LONG lTapiReturn;
char PrintString[80];
TCHAR TempString[20];
char CharString[20];
LINEDEVCAPS TapiLineDevCaps;
static DWORD dwLocalAPIVersion;
LINEEXTENSIONID LineExtensionID;
LINECALLPARAMS LineCallParams;
static DWORD ChoosenDevice;
TCHAR DialNumber[30];
#ifdef _WIN32_WCE_EMULATION
if (wcscmp(lpszPortName, TEXT("TAPI")) != 0)
return TRUE; //If running under emulator then unable to emulate
#endif //the serial port, so in this 'test' mode just echo.
if (COMMPORTSHUT == TRUE) //If this is True then we are shutting down the program
return TRUE; //So don't try to re-open port as it gets stuck in an infinate loop
if (wcscmp(lpszPortName, TEXT("TAPI")) == 0)
{
#ifdef DEBUGVERSION
VTPrint("Entering (TAPI)PortInitilize\r\n" , 0);
#endif
//Retrive the telephone number from the registry
// Fill in the Modem Telephone number
wcscpy(DialNumber, TEXT("T"));
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
TEXT("Software\\PVG\\Terminal\\Settings"),
0, NULL, 0,0, NULL, &hKey, &RegKeyDisp) == ERROR_SUCCESS)
{
//Retrive the telephone number
RegKeyType = REG_SZ;
RegKeySize = sizeof(DialNumber);
RegQueryValueEx(hKey, TEXT("Telephone"),
NULL, &RegKeyType,
(PBYTE)DialNumber + sizeof(TCHAR),
&RegKeySize);
RegCloseKey(hKey);
}
//Confirm there is a telephone number
if (*(DialNumber + 1) == 0)
{
VTPrint("No Telephone Number\r\n", 0);
return FALSE;
}
// Use TAPI to open a DATAMODEM communication channel
if (ghLineApp == NULL)
{
#ifdef DEBUGVERSION
VTPrint("Tapi - LineInitialise\r\n",0);
#endif
memset(&TapiLineDevCaps, 0, sizeof(TapiLineDevCaps));
lTapiReturn = lineInitialize(&ghLineApp, hInst, TapiCallBackFunction, NULL, &dwTapiNumDevs);
if (lTapiReturn)
{
wsprintf (TempString,TEXT("%d"), lTapiReturn);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 20, NULL, NULL);
VTPrint("TAPI failed to initialise\n\rError Code = ",0);
VTPrint(CharString, 0);
VTPrint("\n\r",0);
TAPIShutdown();
return FALSE;
}
//Loop through devices to find one that can do data at 9600 baud (GSM)
for (ChoosenDevice=0 ; ChoosenDevice < dwTapiNumDevs ; ChoosenDevice++)
{
TapiLineDevCaps.dwTotalSize = sizeof(TapiLineDevCaps);
//Ask for at least TAPI Version 1.4
lTapiReturn = lineNegotiateAPIVersion(ghLineApp, ChoosenDevice, 0x00010004,
0x00010004, &dwLocalAPIVersion, &LineExtensionID);
#ifdef DEBUGVERSION
if (lTapiReturn)
{
wsprintf (TempString,TEXT("%d"), lTapiReturn);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 20, NULL, NULL);
VTPrint("TAPI failed to negotiate API Version\n\rError Code = ",0);
VTPrint(CharString, 0);
VTPrint("\n\r",0);
}
#endif
if (!(lTapiReturn))
{
lTapiReturn=lineGetDevCaps(ghLineApp, ChoosenDevice, dwLocalAPIVersion, 0, &TapiLineDevCaps);
#ifdef DEBUGVERSION
if (lTapiReturn)
{
wsprintf (TempString,TEXT("%d"), lTapiReturn);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 20, NULL, NULL);
VTPrint("TAPI failed to get device capibility\n\rError Code = ",0);
VTPrint(CharString, 0);
VTPrint("\n\r",0);
}
else
#endif
#ifndef DEBUGVERSION
if (!(lTapiReturn))
#endif
{
if ((TapiLineDevCaps.dwBearerModes & LINEBEARERMODE_VOICE) &&
(TapiLineDevCaps.dwMaxRate >= 9600) &&
(TapiLineDevCaps.dwMediaModes & LINEMEDIAMODE_DATAMODEM))
break;
}
}
}
if (!((TapiLineDevCaps.dwBearerModes & LINEBEARERMODE_VOICE) ||
(TapiLineDevCaps.dwMaxRate >= 9600) ||
(TapiLineDevCaps.dwMediaModes & LINEMEDIAMODE_DATAMODEM)))
{
VTPrint("Unable to find a modem device\r\n", 0);
TAPIShutdown();
lineShutdown(ghLineApp);
ghLineApp = NULL;
return FALSE;
}
//Now we have found a device capable of a dial up modem
strcpy(PrintString, "TAPI Initilised (");
wsprintf (TempString,TEXT("%d"), ChoosenDevice);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 20, NULL, NULL);
strcat(PrintString, CharString);
strcat(PrintString, "/");
wsprintf (TempString,TEXT("%d"), dwTapiNumDevs);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 3, NULL, NULL);
strcat(PrintString, CharString);
strcat(PrintString, ")\n\r");
VTPrint(PrintString, 0);
}
//Open the TAPI line device
if (ghLine == NULL)
{
#ifdef DEBUGVERSION
VTPrint("TAPI - Obtaining line handle\r\n", 0);
#endif
lTapiReturn = lineOpen(ghLineApp, ChoosenDevice, &ghLine, dwLocalAPIVersion, 0 , 0,
LINECALLPRIVILEGE_NONE, LINEMEDIAMODE_DATAMODEM, 0);
if (lTapiReturn)
{
wsprintf (TempString,TEXT("%d"), lTapiReturn);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 20, NULL, NULL);
VTPrint("TAPI failed to Open Line\n\rError Code = ",0);
VTPrint(CharString, 0);
VTPrint("\n\r",0);
TAPIShutdown();
return FALSE;
}
//Request specific notification messages
lTapiReturn = lineSetStatusMessages(ghLine, LINEDEVSTATE_RINGING | LINEDEVSTATE_CONNECTED |
LINEDEVSTATE_DISCONNECTED | LINEDEVSTATE_OUTOFSERVICE |
LINEDEVSTATE_MAINTENANCE | LINEDEVSTATE_CLOSE |
LINEDEVSTATE_REINIT, LINEADDRESSSTATE_OTHER);
if (lTapiReturn)
{
wsprintf (TempString,TEXT("%d"), lTapiReturn);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 20, NULL, NULL);
VTPrint("TAPI failed to Set Status Messages\n\rError Code = ",0);
VTPrint(CharString, 0);
VTPrint("\n\r",0);
TAPIShutdown();
return FALSE;
}
//Configure line device for a data modem
memset(&LineCallParams, 0, sizeof(LineCallParams));
LineCallParams.dwTotalSize = sizeof(LineCallParams);
LineCallParams.dwBearerMode = LINEBEARERMODE_VOICE;
LineCallParams.dwMediaMode = LINEMEDIAMODE_DATAMODEM;
//Expect the line to start out idle (we don't want to break into a current call)
LineCallParams.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
//If multiple addresses on the line, use the first address
LineCallParams.dwAddressMode = LINEADDRESSMODE_ADDRESSID;
LineCallParams.dwAddressID = 0;
}
//Make the call
if (ghCall == NULL)
{
#ifdef DEBUGVERSION
VTPrint("TAPI Making the call\r\n", 0);
#endif
lTapiReturn = lineMakeCall(ghLine, &ghCall, DialNumber, 0, &LineCallParams);
if (lTapiReturn < 0)
{
wsprintf (TempString,TEXT("%d"), lTapiReturn);
WideCharToMultiByte(CP_ACP, 0, TempString, -1, CharString, 20, NULL, NULL);
VTPrint("TAPI failed to Make the Call\n\rError Code = ",0);
VTPrint(CharString, 0);
VTPrint("\n\r",0);
TAPIShutdown();
ghCall = NULL;
return FALSE;
}
}
VTPrint("Call Initiated\r\n",0);
return TRUE;
}
if (wcscmp(lpszPortName, TEXT("RAS")) != 0)
{
{
// Open the serial port.
hPort = CreateFile (lpszPortName, // Pointer to the name of the port
GENERIC_READ | GENERIC_WRITE,
// Access (read-write) mode
0, // Share mode
NULL, // Pointer to the security attribute
OPEN_EXISTING,// How to open the serial port
0, // Port attributes
NULL); // Handle to port with attribute
// to copy
// If it fails to open the port, return FALSE.
if ( hPort == INVALID_HANDLE_VALUE )
{
// Could not open the port.
COMMPORTSHUT=TRUE;
MessageBox (hMainWnd, TEXT("Unable to open the port"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return FALSE;
}
}
RetValue=InitiliseCommHandle();
return RetValue;
}
return TRUE;
}
//Initilise the communication handle, this occurs once a communication channel has been
//opened, either direct to a serial port or via TAPI
BOOL InitiliseCommHandle(void)
{
DWORD dwError,
dwThreadID;
DCB PortDCB;
COMMTIMEOUTS CommTimeouts;
#ifdef DEBUGVERSION
char SendString[40];
sprintf(SendString, "Handle = %d\r\n", hPort);
VTPrint(SendString,0);
#endif
// Get the default port setting information.
PortDCB.DCBlength = sizeof (DCB);
GetCommState (hPort, &PortDCB);
// Change the DCB structure settings.
if (wcscmp(COMMPORTNAME, TEXT("TAPI")) == 0)
{
//TAPI (modem) Settings
PortDCB.BaudRate = 19200; // Current baud
PortDCB.ByteSize = 8; // Number of bits/byte, 4-8
PortDCB.Parity = NOPARITY; // Parity odd,even,mark,space
}
else
{
//Standard Serial Port Settings
PortDCB.BaudRate = 1200; // Current baud
PortDCB.ByteSize = 7; // Number of bits/byte, 4-8
PortDCB.Parity = EVENPARITY; // Parity odd,even,mark,space
}
PortDCB.fBinary = TRUE; // Binary mode; no EOF check
PortDCB.fParity = TRUE; // Enable parity checking
PortDCB.fOutxCtsFlow = FALSE; // CTS output flow control
PortDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
PortDCB.fOutxDsrFlow = FALSE; // No DSR output flow control
PortDCB.fDtrControl = DTR_CONTROL_ENABLE; //DTR output ON
PortDCB.fDsrSensitivity = FALSE; // DSR sensitivity
PortDCB.fTXContinueOnXoff = TRUE; // XOFF continues Tx
PortDCB.fOutX = FALSE; // No XON/XOFF out flow control
PortDCB.fInX = FALSE; // No XON/XOFF in flow control
PortDCB.fErrorChar = FALSE; // Disable error replacement
PortDCB.fNull = FALSE; // Disable null stripping
PortDCB.fAbortOnError = FALSE; // Do not abort reads/writes on
// error
PortDCB.StopBits = ONESTOPBIT; // 0,1,2 = 1, 1.5, 2
// Configure the port according to the specifications of the DCB
// structure.
if (!SetCommState (hPort, &PortDCB))
{
MessageBox (hMainWnd, TEXT("Unable to configure the port"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return FALSE;
}
// Retrieve the time-out parameters for all read and write operations
// on the port.
GetCommTimeouts (hPort, &CommTimeouts);
// Change the COMMTIMEOUTS structure settings.
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 20;
CommTimeouts.WriteTotalTimeoutConstant = 1000;
// Set the time-out parameters for all read and write operations
// on the port.
if (!SetCommTimeouts (hPort, &CommTimeouts))
{
// Could set the timeouts.
MessageBox (hMainWnd, TEXT("Unable to set the port time-out parameters"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return FALSE;
}
if (wcscmp(COMMPORTNAME, TEXT("TAPI")) != 0)
{
// Direct the port to perform extended functions SETDTR and SETRTS
// SETDTR: Sends the DTR (data-terminal-ready) signal.
// SETRTS: Sends the RTS (request-to-send) signal.
// EscapeCommFunction (hPort, SETDTR);
// EscapeCommFunction (hPort, SETRTS);
//Use the Swap Comms routine to set the serial port to the last open state
//This is a little messy to set the port first of all and then change some
//of the settings here
SwapComms(CurrentController);
}
// Create a read thread for reading data from the communication port.
if (hReadThread = CreateThread (NULL, 0, PortReadThread, 0, 0,
&dwThreadID))
{
CloseHandle (hReadThread);
}
else
{
// Could not create the read thread.
MessageBox (hMainWnd, TEXT("Unable to create the read thread"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return FALSE;
}
return TRUE;
}
//TAPI sends status messages to this function.
void CALLBACK TapiCallBackFunction(DWORD dwdevice, DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
DWORD lTapiReturn, dwStructSize;
VARSTRING *pvs, *pvsOld;
#ifdef DEBUGVERSION
char SendString[40];
#endif
pvs = NULL;
dwStructSize = sizeof (VARSTRING);
switch(dwMsg)
{
case LINE_CALLSTATE:
switch(dwParam1)
{
case LINECALLSTATE_IDLE:
if (hPort != INVALID_HANDLE_VALUE)
{
VTPrint("Line Idle\n\r",0);
//Change MENU back to COMM mode
ControllerMenu(TRUE);
//Shutdown TAPI
hPort = INVALID_HANDLE_VALUE;
lineDeallocateCall(ghCall);
ghCall = NULL;
ghLine = NULL;
}
break;
case LINECALLSTATE_CONNECTED:
//If a handle is already present then don't re-open
//This needs doing as multiple connected events can occur on connection
if (hPort != INVALID_HANDLE_VALUE)
break;
//Spin round loop till the structure is big enough
do
{ pvsOld = pvs;
if (NULL == (pvs = realloc (pvs, dwStructSize)))
break;
pvs->dwTotalSize = dwStructSize;
if (lTapiReturn = lineGetID (NULL, 0, ghCall, LINECALLSELECT_CALL,
pvs, TEXT("comm/datamodem")))
break;
}
while ((dwStructSize = pvs->dwNeededSize) > pvs->dwTotalSize) ;
if (pvs == NULL)
{
if (pvsOld)
free (pvsOld);
VTPrint("Failed to allocate port handle memory\n\r", 0);
TAPIShutdown();
break;
}
if (lTapiReturn)
{
free(pvs);
VTPrint("Failed to obtain port handle\n\r", 0);
TAPIShutdown();
break;
}
hPort = * (HANDLE*) ((char*) pvs + pvs->dwStringOffset);
free(pvs);
//Change Menu to Modem Mode
ControllerMenu(FALSE);
VTPrint("Connected\n\r", 0);
InitiliseCommHandle();
break;
case LINECALLSTATE_DIALING:
//VTPrint("Dialling\n\r", 0);
break;
case LINECALLSTATE_PROCEEDING:
//VTPrint("Waiting for an answer\n\r", 0);
break;
case LINECALLSTATE_DISCONNECTED:
ControllerMenu(TRUE);
//Change Menu to COMM mode
switch (dwParam2)
{
case LINEDISCONNECTMODE_UNREACHABLE:
VTPrint("Unreachable\r\n",0);
hPort = INVALID_HANDLE_VALUE;
break;
case LINEDISCONNECTMODE_BUSY:
VTPrint("Line Busy\n\r", 0);
break;
}
TAPIShutdown();
}
break;
default:
break;
}
}
[/code]
BOOL TAPIShutdown()
//Do the TAPI Shutdown Process
{
static bShuttingDown = FALSE;
//If we are not initilised then Shutdown unnecessary
if (ghLineApp == NULL)
return TRUE;
//Prevent Shutdown re-entrancy problems
if (bShuttingDown)
return TRUE;
bShuttingDown=TRUE;
if (ghCall != NULL)
lineDrop(ghCall, NULL, 0);
bShuttingDown = FALSE;
return TRUE;
}
Thanks for code posted. It is very helpful.
But I don't quite understand the logic how the "hPort" is created when receiveing a "CONNECTED" message callback.
Can you explain a little bit more?
- David
The handle to the port (hPort) is contained at the end of a variable length string (VARSTRING) that is returned from the call to LineGetID.
The fiddly thing about it is you give LineGetID a pointer to a VARSTRING called pvs and you have to fill in one of the member variables of pvs with the size allocated ( pvs->dwTotalSize ) to the variable length string.
Since I don't know how much to allocate to the VARSTRING, initially I just allocate enough memory from a sizeof(VARSTRING) result. Maybe you could just allocate a set size and not bother with the looping back, I think it is better to ask the system how much memory it wants as LineGetID may need more memory in later versions of the operating system.
Then you pass the VARSTRING with it's size stored in dwTotalSize to the function LineGetID.
The LineGetID function then fills in dwNeededSize with the size of the VARSTRING it needed to complete. That is why I loop back and re-allocate the VARSTRING to a new (bigger) size if NeededSize is greater than TotalSize.
Once the LineGetID function succeeds with a big enough VARSTRING then the Port Handle is at the end of the VARSTRING, as it is a variable length string you have to do maths to say the Port Handle is at the Address of the string PLUS the offset to the actural data wanted i.e. pvs + pvs->dwStringOffset The maths must be done with char* byte sizes and the final result is a handle, hence the casting HANDLE* on the final result.
Once the Port Handle is stored in hPort, the memory allocated to pvs is freed.
One other thing I noticed is that you can get multiple CONNECTED events, that is why I just exit the CONNECTED event if there is already a valid handle
I hope that makes sense.
Cheers
Paul
Do you have sample for the answering part?
thanks,
- David
No, sorry I have only ever written programs to dial out.
Hi,
I tried the sample code posted in this thread. It works only if I used
LineCallParams.dwBearerMode = LINEBEARERMODE_VOICE;
LineCallParams.dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE;
combination. I got the RING message. However, the original:
LineCallParams.dwBearerMode = LINEBEARERMODE_VOICE;
LineCallParams.dwMediaMode = LINEMEDIAMODE_DATAMODEM;
didn't seem to work.
Do I miss something? (I think I have successfully killed the cprog.exe already)
Thanks,
- David
That means you are making a voice call.
So is the problem that you can not make a data(modem) type call ?
Check that you have data enabled on your SIM and also that under Settings -> Connections -> CSD Line Type it is set correctly. In the UK it is 9600 bps(v.32) and Non-tranparent, but I was told it is v110 is the states.
Let me know how you get on.
Is there any chance that somebody could compile this TAPI code as an object I could consume in C#? I have tried, but I am not even able to compile the example in C++... it's just not my world!
I would be eternally gratefull - and I bet a whole bunch of other guys who just want to quickly establish a data connection over GSM from C# (or VB?) would be also! It should have been in the phone.dll if you ask me!
compiled sample
Hey could somebody compile the tapi code for me in eVc++ or MFC ?? because i am really struggling. Plus what is toolbox.h i dont seem to have it ?? can somebody please help ??
thanks guys
This is an old post of mine, don't worry about Toolbox.h that was for the program I was writing and it has nothing to do with Tapi.
This sample code was not meant to compile, after you you won't have function VTPrint but I hope you can guess that just shows text. It was just posted to demonstate the order of functions needed to get a modem connection.
I built all this Tapi code into a DLL and I have it all presented with the eVC 3.0 build files in this post, this code will compile as presented and is just a zip of all the project files of a single sample application.
http://forum.xda-developers.com/viewtopic.php?t=18978
Have a look there.
Cheers
Paul
during a data call when using TAPI can u make some kind of AT command request ??? and retrieve the data from that answer ??? And do i need some TAPI app on the remote unit to send the data back ?
i am trying to access a remote unit ( GPS RX and GSM TX )
I don't really understand your question that well.
But AT commands have nothing to do with TAPI, so any question saying can TAPI send an AT command for etc -- The answer must be no.
All TAPI does is gives a Handle that can be used with ReadFile and WriteFile for receiving and sending data over the modem.
So TAPI will dial a number and establish a DataModem connection, then on Connect it can provide the handle for you to direct read/write requests to. Once the link is established you just treat the handle as if it was a file handle returned from a CreateFile command.
As said earlier all this has nothing to do with AT commands.
During a data call should ic onnect via COM 1 or COM 9 if i'm using TAPI ?? Would you have any sample code i could have a look at ? I'm a bit lost at the moment .... with LineGetID too ...
you can't use COM2 or COM9 via TAPI cause COM2 and COM9 masked by RIL
about lineGetID look http://forum.xda-developers.com/viewtopic.php?t=9761
ok thanks - so if i cant use COM1 or COM9 in this case then i'm guessing that i shall pass a string (lpszPortName) just like the example on this post.
Code:
// Open the serial port.
hPort = CreateFile (lpszPortName, // Pointer to the name of the port
GENERIC_READ | GENERIC_WRITE,
// Access (read-write) mode
0, // Share mode
NULL, // Pointer to the security attribute
OPEN_EXISTING,// How to open the serial port
0, // Port attributes
NULL); // Handle to port with attribute
// to copy
But what should the string lpszPortName be initialized to ? Or am i totally wrong ?[/quote]
L"COM9:" for COM9
but not with TAPI
with TAPI you have not open any COM-ports
you must use lineGetID
Code:
//PART 7 - TIMEOUT AND DCB SETTINGS
PortDCB.BaudRate = 115200;
PortDCB.fBinary = TRUE;
PortDCB.fParity = FALSE;
PortDCB.fOutxCtsFlow = FALSE;
PortDCB.fOutxDsrFlow = FALSE;
PortDCB.fDtrControl = DTR_CONTROL_ENABLE;
PortDCB.fDsrSensitivity = FALSE;
PortDCB.fTXContinueOnXoff = FALSE;
PortDCB.fOutX = FALSE;
PortDCB.fInX = FALSE;
PortDCB.fErrorChar = FALSE;
PortDCB.fNull = FALSE;
PortDCB.fRtsControl = RTS_CONTROL_DISABLE;
PortDCB.fAbortOnError = FALSE;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
if (!SetCommState (hPort, &PortDCB))
{
MessageBox (_T("unable to configure com port "));
return FALSE;
}
GetCommTimeouts (hPort, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 20;
CommTimeouts.WriteTotalTimeoutConstant = 1000;
if (!SetCommTimeouts (hPort, &CommTimeouts))
{
MessageBox (_T("unable to set comport parameters"));
return FALSE;
}
Are the COM and Timeout settings necessary when using TAPI ? because i am getting an error message at the !setCommState function.
I use lineGetID to retrieve the Handle to the Comm then i try to use readFile but the operation is unsuccesful.
Anyhelp from out there ? thanks.
Are you sure that you call lineGetID only after connection?
Maybe you are right. I just do lineMakeCall then do lineGetId without waiting for a LINECALLSTATE_CONNECTED message.
I think its because i have troubles implementing the lineCallBackFunc() i dont understand the parameters that need to be passed to it.
Code:
void CALLBACK lineCallbackFunc(
DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
Anyhelp for this ?? Cheers.
Hi,
here my second problem :?
Has someone of you an idea how to Answer a call automaticly? I tried RIL_Answer and it seams to work, but i can't talk because the speaker and micro seems to be off.
Also I tried to dial with RIL_Dial - but there seems nothing to go on.
Greetings from hanovre again and
many many thanks for every idea
Andreas )
PS: Is there somewhere a RIL-Command to send AT-Commands directly (in text, not in HEX)?
PS: Is there somewhere a RIL-Command to send AT-Commands directly (in text, not in HEX)?
Click to expand...
Click to collapse
unfortunately there is not.
auto-answer
to make auto answer of phone call, just simulate the hardware key is pressed. not too hard to write in mVC+.
the question is: what next?
auto-answer works fine when you can switch to the speakerphone mode automatically right after the software did pick-up the call
I cannot do that, I tried in several ways but it is not working.
I cannot simulate "longer-press" of hardware buttons as you know you can turn on/off the speakerphone mode
Hi.
I'm also trying to use RIL_Dial. The way I'm running this function is:
RIL_Dial (g_hRil, (CHAR*)_T("696761699"), RIL_CALLTYPE_VOICE, RIL_DIALOPT_NONE)
My XDA seems to accept and try to establish the call since it opens the phone interface (without displaying the passed number). But then I get this answer back from the phone: UNKNOWN APPLICATION
Anyone knows how I can establish a call with this function?
Thanks,
Erik.
@ballrock2:
To answer a call using RIL_Answer do this:
- Call RIL_Answer
- Sleep(100)
- Send a VK_F4 down
- Sleep(100)
- Send a VK_F4 Up
You can then talk.
Quan
does not works
you dream,
keybd_event(VK_F4, MapVirtualKey(VK_F4, 0), 0, 0);
return one shot of button down emulation
no matter how long you are awaiting for the next
keybd_event(VK_F4, MapVirtualKey(VK_F4, 0), KEYEVENTF_KEYUP | KEYEVENTF_SILENT, 0);
so, in this way we cannot emulate tap-and-hold of the green phone button to turn on the speakerphone mode
can you explain or just post how you managed to initialize RIL ?? i dont seem to figure it out !!
thanks.
nutitija
Use Search
In Last Time
/*
callback for result of async functions
*/
void CALLBACK ril_result_callback(DWORD dwCode, HRESULT hrCmdID, const void* lpData, DWORD cbData, DWORD dwParam)
{
....
}
/*
callback for phony notifications (like incoming call)
*/
void CALLBACK ril_notify_callback(DWORD dwCode, const void* lpData, DWORD cbData, DWORD dwParam)
{
...
}
...
HRIL ril = NULL;
......
/*
1 - for RIL1: device
RIL1: device for COM2: device
*/
if (RIL_Initialize(1, ril_result_callback, ril_notify_callback, RIL_NCLASS_CALLCTRL | RIL_NCLASS_NETWORK | RIL_NCLASS_SUPSERVICE | RIL_NCLASS_RADIOSTATE, 0, &ril) < 0)
return;
.....
ok i kinda got the whole idea of it now, this is my implementation to try to initialize RIL however i get the following error :
error C2660: 'RIL_Initialize' : function does not take 6 parameters
Anybody can help me here ? i'm guessing maybe gotta do something with the RIL header file or lib or exp ?
************************************************
// Global Variables
HRESULT result;
DWORD dwNotificationClasses = 0xFF0000;
DWORD g_dwParam = 0x55AA55AA;
HRIL g_hRil = NULL;
// RL initilize
void CTerminalDlg::RIL_Initialize()
{
result = RIL_Initialize(1, ril_result_callback, ril_notify_callback, dwNotificationClasses, g_dwParam, &g_hRil);
}
************************************************
// Global Variables
HRESULT result;
DWORD dwNotificationClasses = 0xFF0000;
DWORD g_dwParam = 0x55AA55AA;
HRIL g_hRil = NULL;
// RL initilize
void CTerminalDlg::RIL_Initialize()
{
result = ::RIL_Initialize(1, ril_result_callback, ril_notify_callback, dwNotificationClasses, g_dwParam, &g_hRil);
}
learn C++
Which port should I open for GSM modem?
I remember someone had posted the port allocation for different device before. Can someone shares that information again?
thanks,
- David :shock:
Code:
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
HANDLE hCom;
char * xpos;
char rsltstr[5];
DWORD CellId;
int bufpos;
DCB dcb;
COMMTIMEOUTS to;
DWORD nWritten;
DWORD event;
DWORD nRead;
static char outbuf[20], buf[256];
BYTE comdevcmd[2]= {0x84, 0x00};
hCom= CreateFile(L"COM2:",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
if (hCom==NULL || hCom==INVALID_HANDLE_VALUE)
{
hCom= NULL;
return -1;
}
/* HANDLE hRil= CreateFile(L"RIL1:",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
if (hRil==NULL || hRil==INVALID_HANDLE_VALUE)
{
hRil= NULL;
return -1;
}
*/
if (!GetCommState(hCom, &dcb))
{
return -2;
}
dcb.BaudRate= CBR_115200;
dcb.ByteSize= 8;
dcb.fParity= false;
dcb.StopBits= ONESTOPBIT;
if (!SetCommState(hCom, &dcb))
{
return -3;
}
if (!EscapeCommFunction(hCom, SETDTR))
{
return -4;
}
if (!EscapeCommFunction(hCom, SETRTS))
{
return -5;
}
if (!GetCommTimeouts(hCom, &to))
{
return -6;
}
to.ReadIntervalTimeout= 0;
to.ReadTotalTimeoutConstant= 200;
to.ReadTotalTimeoutMultiplier= 0;
to.WriteTotalTimeoutConstant= 20000;
to.WriteTotalTimeoutMultiplier= 0;
if (!SetCommTimeouts(hCom, &to))
{
return -7;
}
if (!SetCommMask(hCom, EV_RXCHAR))
{
return -8;
}
DWORD rildevresult=0,nReturned=0;
// DeviceIoControl(hRil, 0x03000314L,0,0, &rildevresult, sizeof(DWORD), &nReturned,0);
// HANDLE Ev=CreateEvent(NULL,TRUE,0,L"RILDrv_DataMode");
// SetEvent(Ev);
if (!DeviceIoControl (hCom,0xAAAA5679L, comdevcmd, sizeof(comdevcmd),0,0,0,0))
{
return -9;
}
bufpos = 0;
strcpy(outbuf,"AT+creg=2\r");
if (!WriteFile(hCom, outbuf, 10, &nWritten, NULL))
{
return -10;
}
if (nWritten != 10)
{
return -11;
}
if (!WaitCommEvent(hCom, &event, NULL))
{
return -12;
}
while(1)
{
if (!ReadFile(hCom, buf+bufpos, 256 - bufpos, &nRead, NULL))
{
return -13;
}
if (nRead == 0)
break;
bufpos += nRead;
if (bufpos >= 256)
break;
}
strcpy(outbuf,"AT+creg?\r");
if (!WriteFile(hCom, outbuf, 9, &nWritten, NULL))
{
return -14;
}
if (nWritten != 9)
{
return -15;
}
if (!WaitCommEvent(hCom, &event, NULL))
{
return -16;
}
while(1)
{
if (!ReadFile(hCom, buf+bufpos, 256 - bufpos, &nRead, NULL))
{
return -17;
}
if (nRead == 0)
break;
bufpos += nRead;
if (bufpos >= 256)
break;
}
puts(buf);
rildevresult = 0;
// DeviceIoControl(hRil, 0x03000318L,0,0, &rildevresult, sizeof(DWORD), &nReturned,0);
// ResetEvent(Ev);
// CloseHandle(Ev);
// CloseHandle(hRil);
if (!EscapeCommFunction(hCom, CLRDTR))
{
return -4;
}
if (hCom!=NULL)
{
CloseHandle(hCom);
hCom= NULL;
}
return CellId;
}
the commented lines force RIL to shut up and not send its commands to modem.
To communicate with modem you should open COM2, set 115200/8/N/1, send ioctl 0xAAAA5679.
I had problems when reading data from modem. When it sends a huge block (for example an output to AT%VER command) some bytes are lost and other are changed to garbage. Maybe this is a hardware problem in my imate, because the same program worked on Rover S1 without bugs.
P.S. The code I've posted is taken from this forum.
Post subject: Re: GSM modem port
Thanks for information. I am using iMate too.
Indeed the returned data are very strange. I actually had failure for "EscapeCommFunction(hCom, SETRTS)".
Did you try to dial with a number?
I got "NO CARRIER" while issing a ATD command.
- David
Re: Post subject: Re: GSM modem port
davidchu2000 said:
Did you try to dial with a number?
I got "NO CARRIER" while issing a ATD command.
Click to expand...
Click to collapse
I use TAPI functions to establish a data call. I don't think that you can use COM1 for ATD commands and receive data after connection. Internally COM9 is used after data connection is established. But I've successfully used "ATDnumber;" to make a call. Though it is much easier to use SHMakeCall function.
Hi mamaich,
I have to port a modem application for data transfering.
I can make a call using ATD through com2. Are you saying that I cannot use the same port for data communication?
I have to use COM9 instead?
- David
I don't know. You should test this yourself. For some reason TAPI or RIL opens COM9 after data connection.
Are you able to answer a data call by listening to com2? (or thru TAPI)
- David
I answer call through TAPI without problems. You should kill cprog.exe application on the incoming data call so that it does not popup.
Is anyone experience with pick a call? I can make a call but my program couln't detect an incoming call (when dialing with DATAMODEM using TAPI).
Best regards,
A. Riazi
To receive data call you should terminate cprog.exe. Look into cryptophone source code for more information.
I didn't see any code for terminating cprog.exe, only I saw one line of code to hide "Incoming call..." window. Would you please say in which source of the CryptoPhone, they did this?
Best regards,
A. Riazi
I keep refering back to this topic, wishing I were clever enough to make the XDA modem visable under C# - but I have failed miserably!
Has anybody managed to this, either by talking to COM2: or by using TAPI? All I want is to establish a data call (NOT IP!) for a POS application.
I would worship the ground you walk on if you can help me over my blockage!
Can someone explain how TAPI is implemented to do data calls ??? I am programming in MFC / eVC++ ... Thanks for ur help guys !!!
Which TAPI function do u use to establish a data call ??? is there anywhere i can get the list of all of them ?? cheers guys
I'm try write a application to addjust LCD backlight.But it failed at the
first step Create file.GetLastError return 161.
Somesone can tell me what's wrong with it?
Sorry for my poor english.
thx
Below is my code
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
TCHAR *pszDevice=_T("\\\\.\\LCD");
HANDLE hLCD=NULL;
hLCD=CreateFileW(pszDevice,
GENERIC_READ,
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
0,
NULL);
DWORD dwError=GetLastError();
if(INVALID_HANDLE_VALUE!=hLCD)
{
MessageBox(NULL,_T("Got Lcd"),_T("MyMessage"),MB_OK);
}
CloseHandle(hLCD);
return 0;
}
Hi ft1860!
I don't think you can do it that way, although I never tried it. You should check out power management API:
http://msdn.microsoft.com/library/d...pplicationsToTurnSmartphoneBacklightOffOn.asp
This example is for smartphones but should work on a PPC just as well.
P.S.:
Error 161 is "The specified path is invalid" so you should check the device name (no idea what that might be).
levenum said:
Hi ft1860!
I don't think you can do it that way, although I never tried it. You should check out power management API:
http://msdn.microsoft.com/library/d...pplicationsToTurnSmartphoneBacklightOffOn.asp
This example is for smartphones but should work on a PPC just as well.
P.S.:
Error 161 is "The specified path is invalid" so you should check the device name (no idea what that might be).
Click to expand...
Click to collapse
hi levenum
Thanks your comment,but according to this document
http://windowssdk.msdn.microsoft.co...r/base/ioctl_video_set_display_brightness.asp
It say we can set the current AC and DC backlight levels by invoke DeviceIoControl with IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS parameter.
So first I must create a handle of LCD,but I cann't open it successfully,
why?
oh,I make a mistake
IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS is Win32 function.
On smart device,I should use SetPowerRequirement to set the backlight.
But when I invoke SetPowerRequirement on my Universal with D0 or D4,it say success ,but nothing happened.
maybe you have to access backlight by BKL1: device.
CreateFile(L"BKL1:", ....
or write the brightness value into registry.. that works for sure.
buzz
buzz_lightyear said:
maybe you have to access backlight by BKL1: device.
CreateFile(L"BKL1:", ....
or write the brightness value into registry.. that works for sure.
buzz
Click to expand...
Click to collapse
Thanks
I'll try it.
It seem that SetPowerRequirement D0-D4 just Open or close backlight,
but what I want is adjust the backlight's brightness.
ft1860 said:
It seem that SetPowerRequirement D0-D4 just Open or close backlight,
but what I want is adjust the backlight's brightness.
Click to expand...
Click to collapse
then just do it through registry.
buzz
buzz_lightyear said:
ft1860 said:
It seem that SetPowerRequirement D0-D4 just Open or close backlight,
but what I want is adjust the backlight's brightness.
Click to expand...
Click to collapse
then just do it through registry.
buzz
Click to expand...
Click to collapse
oh,thanks
It almost work.
It works fine on my Universal,but it doesn't work on my x50v with WM5.
I should not debug it on my x50v,there is so many bugs in Dell's WM5 update.
Another question is how to get the max brightness value.On my Universal it is 10,but on my x50v it is 8;
below is my new code
#include <WinReg.h>
#include <pm.h>
TCHAR tszAppName[] = TEXT("PMSAMPLE");
TCHAR tszTitle[] = TEXT("Power Manager Sample");
HINSTANCE g_hInst = NULL; // Local copy of hInstance
HANDLE g_hEventShutDown = NULL;
HANDLE g_hPowerNotificationThread = NULL;
HWND g_hSystemState = NULL;
//***************************************************************************
// Function Name: SetBacklightRequirement
//
// Purpose: Sets or releases the device power requirement to keep the
// backlight at D0
//
// Arguments:
// IN BOOL fBacklightOn - TRUE to leave the backlight on
//
void SetBacklightRequirement(BOOL fBacklightOn)
{
// the name of the backlight device
TCHAR tszBacklightName[] = TEXT("BKL1:");
static HANDLE s_hBacklightReq = NULL;
if (fBacklightOn)
{
if (NULL == s_hBacklightReq)
{
// Set the requirement that the backlight device must remain
// in device state D0 (full power)
s_hBacklightReq = SetPowerRequirement(tszBacklightName, D4,
POWER_NAME, NULL, 0);
if (!s_hBacklightReq)
{
RETAILMSG(1, (L"SetPowerRequirement failed: %X\n",
GetLastError()));
}
}
}
else
{
if (s_hBacklightReq)
{
if (ERROR_SUCCESS != ReleasePowerRequirement(s_hBacklightReq))
{
RETAILMSG(1, (L"ReleasePowerRequirement failed: %X\n",
GetLastError()));
}
s_hBacklightReq = NULL;
}
}
}
#define REG_BACKLIGHT L"ControlPanel\\Backlight"
//#define REG_VAL_BATT_TO L"BatteryTimeout"
//#define REG_VAL_AC_TO L"ACTimeout"
#define REG_VAL_BN L"BrightNess"
#define REG_VAL_ACBN L"ACBrightness"
unsigned int OldBattBN=0;
unsigned int OldACBN=0;
void RegOptionBL( DWORD dw1,DWORD dw2)
{
HKEY hKey = 0;
DWORD dwSize;
HANDLE hBL;
static bool bOpened=false;
if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_CURRENT_USER,REG_BACKLIGHT, 0, 0, &hKey ) )
{
if( !bOpened )
{
bOpened=true;
dwSize = 4;
RegQueryValueEx( hKey, REG_VAL_BN,NULL,NULL,(unsigned char*)&OldBattBN,&dwSize );
dwSize = 4;
RegQueryValueEx( hKey, REG_VAL_ACBN,NULL,NULL,(unsigned char*) &OldACBN,&dwSize );
// dwSize = 4;
// dwValue = 0xefff ;
// RegSetValueEx( hKey,REG_VAL_BATT_TO,NULL,REG_DWORD,(unsigned char *)&dwValue,dwSize );
// dwSize = 4;
// dwValue = 0xefff ;
// RegSetValueEx( hKey,REG_VAL_AC_TO,NULL,REG_DWORD,(unsigned char *)&dwValue,dwSize );
dwSize = 4;
RegSetValueEx( hKey,REG_VAL_BN,NULL,REG_DWORD,(unsigned char *)&dw1,dwSize );
dwSize = 4;
RegSetValueEx( hKey,REG_VAL_ACBN,NULL,REG_DWORD,(unsigned char *)&dw2,dwSize );
}
else
{
if (OldBattBN)
{
dwSize = 4;
RegSetValueEx( hKey,REG_VAL_BN,NULL,REG_DWORD,(unsigned char *)&OldBattBN,dwSize );
}
if (OldACBN)
{
OldACBN = 4;
RegSetValueEx( hKey,REG_VAL_ACBN,NULL,REG_DWORD,(unsigned char *)&OldACBN,dwSize );
}
}
RegCloseKey( hKey );
hBL = CreateEvent( NULL, FALSE, FALSE,L"BackLightChangeEvent" );
if( hBL )
{
SetEvent(hBL);
CloseHandle( hBL );
}
}
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
int nResult = 0;
// Create mutex to track whether or not an application is already running
HANDLE hMutex = CreateMutex(0, 0, _T("_PMSAMPLE_EXE_MUTEX_"));
// check the result code
if (NULL != hMutex)
{
if (ERROR_ALREADY_EXISTS != GetLastError())
{
SetBacklightRequirement(TRUE);
RegOptionBL(8,8);
Sleep(5000);
RegOptionBL(-1,-1);
SetBacklightRequirement(FALSE);
}
else
{
}
CloseHandle(hMutex);
}
return ( nResult >= 0 );
}
When you click on the sound icon, you get the two sliders and three radio buttons. Anyone know how to set those radio buttons through code (C++) so it gets reflected in the icon display (and actually changes the "profile")?. I'd like to change to vibrate/mute/sound at different times using something like alarmToday to run a small app.
Thanks,
sbl
I wrote a profiles app in .net and C++ here are some code snippets;
You can change the registry values for the volumes (I cant remember which as I wrote it a long time ago), then you need to call the following to have the values applied.
// ProfilesHelper.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "ProfilesHelper.h"
#include <windows.h>
#include <Soundfile.h>
void WINEXPORT SetSoundMode(int mode)
{
// Initialize an empty SNDFILEINFO structure
SNDFILEINFO sndfile = {0};
if (mode == 0)
sndfile.sstType = SND_SOUNDTYPE_ON;
if (mode == 1)
sndfile.sstType = SND_SOUNDTYPE_VIBRATE;
if (mode == 2)
sndfile.sstType = SND_SOUNDTYPE_NONE;
SndSetSound(SND_EVENT_ALL, &sndfile, false);
void AudioUpdateFromRegistry();
}
void WINEXPORT SetSystemVolume(long volume)
{
waveOutSetVolume(NULL, volume);
void AudioUpdateFromRegistry();
}
Hi,
I have a similar need of programatically cycling the sound icon to MUTE VIBRATE and normal volume icon. I can do it successfully on Windows Mobile 5.0. I created a sample application with Visual Studio 2005 for WM 5.0 and I am able to set the icons as i want. But when i tried it for PPC2003 I was not able to compile that. Missing SoudFile.h. Can any one help me to find out how to do the same thing on PPC2003 specifically i-mate devices like PDA2 and PDA2K.
Thanks
With Regards,
Bhagat Nirav K.
i know its a 2 ur old post..but i need help also now
how can i mute sounds using C# in .net 2.0 for WM6
Just forget about this header file...
Operate on HKCU\ControlPanel\Notifications\ShellOverrides\Mode value. It can have 3 states: 0 == normal, 1 == vibrate and 2 == silent. That's all
Probably you need to call AudioUpdateFromRegistry function from coredll.dll.
Or... another method
look at HKCU\ControlPanel\Sounds\RingTone0:Sound, it takes 3 different values:
*none*
*vibrate*
your ringtone name, taken from SavedSound value in the same key.
Hi,
Firstly I know this post is way old, but I thought of responding to it since I was stuck on this topic for a couple of days and couldnt find a way to resolve it.
Also others having this problem will also be redirected here through various search results as I was. So to aid them
1. Meddling with the registry to change the sound profiles didnt work for me. I tried Changing the Mode inHKCU\ControlPanel\Notifications\ShellOverrides\Mode but that didnt work on my phone.
2. What I currently have working is the following code - C# with Pinvoke
public enum SND_SOUNDTYPE
{
On,
File,
Vibrate,
None
}
private enum SND_EVENT
{
All,
RingLine1,
RingLine2,
KnownCallerLine1,
RoamingLine1,
RingVoip
}
[StructLayout(LayoutKind.Sequential)]
private struct SNDFILEINFO
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPathName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
public SND_SOUNDTYPE sstType;
}
[DllImport("coredll.dll")]
public static extern void AudioUpdateFromRegistry ();
[DllImport("aygshell.dll", SetLastError = true)]
private static extern uint SndSetSound(SND_EVENT seSoundEvent, ref SNDFILEINFO pSoundFileInfo, bool fSuppressUI);
static void SetProfileNormal()
{
SNDFILEINFO soundFileInfo = new SNDFILEINFO();
soundFileInfo.sstType = SND_SOUNDTYPE.On;
uint num = SndSetSound(SND_EVENT.All, ref soundFileInfo, true);
AudioUpdateFromRegistry();
}
static void SetProfileVibrate()
{
SNDFILEINFO soundFileInfo = new SNDFILEINFO();
soundFileInfo.sstType = SND_SOUNDTYPE.Vibrate;
uint num = SndSetSound(SND_EVENT.All, ref soundFileInfo, true);
AudioUpdateFromRegistry();
}
static void SetProfileMuted()
{
SNDFILEINFO soundFileInfo = new SNDFILEINFO();
soundFileInfo.sstType = SND_SOUNDTYPE.None;
uint num = SndSetSound(SND_EVENT.All, ref soundFileInfo, true);
AudioUpdateFromRegistry();
}
Hope this helps