Click here to Skip to main content
15,891,788 members
Please Sign up or sign in to vote.
3.00/5 (3 votes)
See more:
I need to write a code in C to access GSM Modem thro' serial port. I already done successfully. But I need help to write a method in C which is equivalent to DoEvents in VB 6.0. That is, I declared global variable OK in C. If I try to retrieve the value in the middle of the process I could not able to get the correct value though the I set the OK value equal to true in the middle of the process. This can be acheieved using DoEvents method in VB 6.0 and already did this and got the result correctly. But not in C. I am new to C. Please go thro' my code and help me.

I opened the Serial port in Non-Overlapped mode.

Code:

#include <string>
#include <windows.h>
#include <time.h>

using namespace std;

//STRUCTURE TO STORE TELEPHONE BOOK (THE COM OUTPUT)

typedef struct{
	char splitRecs[25];
} phBook;
phBook record[50];

char INBUFFER[500];
char OUTBUFFER[500];
char * chrArray;
static string strArray;
bool greaterSign = false;

//SMS VARIABLES
bool Message_Store = false;
string Message_Buffer;
char *SMS_MesgNum = NULL;
char *SMS_TelephoneNum = NULL;

// PORTS
HANDLE h_GSM = NULL;
DCB dcbConfig;
COMMTIMEOUTS CommTimeouts;
	
DWORD dwEventMask;
DWORD bytes_read    = 0;    // Number of bytes read from port
DWORD bytes_written = 0;

//VARIABLES USED IN FUNCTION ComEvent
bool OK = false;
bool Error = false;
bool RING = false;

// FUNCTIONS USED IN THIS PROGRAM
int WriteCOM();
int ReadCOM();
static void doEvents();
void wait_for_response();
char *substring(size_t start, size_t stop, char src[]);
int split(char input[], const char *delims);
void ComEvent(char Event[]);
void wait_for_response();
static void doEvents();

// WRITE TO THE PORT
int WriteCOM(){
	 
     if(!WriteFile(h_GSM,           // Handle
		   &OUTBUFFER,      // Outgoing data
		   20,              // Number of bytes to write
		   &bytes_written,  // Number of bytes written
		   NULL)){          
		// error processing code here
		printf("Error in writing\n");
		return 0;
	}
 return 0;
}

// READ THE PORT
int ReadCOM(){
	strcpy(&INBUFFER[0], "");
	memset(INBUFFER, 0, sizeof(INBUFFER));
			
	do
	{				
	    if(ReadFile(h_GSM, &INBUFFER, sizeof(INBUFFER),   
               &bytes_read, NULL) != 0){
				   
	    }
			
	}while(bytes_read > 0);
			
	//printf("%d\n", bytes_read);
return 0;
}

// FUNCTION TO EXTRACT SPECIFIED NUMBER OF SUBSTRING FROM THE OUTPUT
char *substring(size_t start, size_t stop, char src[])
{
   
   size_t size = sizeof(src);
   
   char* dst = (char*) malloc(strlen(src) * sizeof(char));
   int count = stop - start;
   
   sprintf(dst, "%.*s", count, src + start);
   return dst;
}

//SPLIT COM OUTPUT AND STORE THE PHONE BOOK INTO ARRAY
int split(char input[], const char *delims){	
	char *output[500];
	int loop;
	double NumOfStr_Input = strlen(input);
	int i = 0;
    
	output[0] = strtok(input, delims); 
	
	if(output[0]==NULL) 
	{ 
		printf("No text to search.\n"); 
		exit(0); 
	} 
	
	for(loop=1;loop<numofstr_input;loop++)>
	{ 
	
		output[loop]=strtok(NULL,delims); 
		if(output[loop]==NULL) 
		break; 
	} 
	for(loop=0;loop<numofstr_input;loop++)>
	{ 
		if(output[loop]==NULL) 
		break; 
		//printf("Item #%d is %s.\n",loop,output[loop]); 
	
		//split(output[loop], delim);
		strcpy(record[i].splitRecs, output[loop]);
		i++;
		
	} 
	/*
	int j=0;
	
	for(;j < i;j++){
	
		printf("%s\n", record[j].splitRecs);
		
	}*/
return 0; 
}

// VALIDATE THE (GSM) COM OUTPUT
void ComEvent(char Event[]){
	
	// IF 'OK' RECEIVED FROM PORT, THE WRITE/READ COMMAND (IF ISSUED) SUCCEEDS
	if (strcmp(Event, "OK") == 0){
		
		OK = true;
		
	}
	// IF 'ERROR' RECEIVED FROM PORT, THE WRITE/READ COMMAND (IF ISSUED) FAILED
	
	if(strcmp(Event, "Error") == 0){
		
		Error = true;
		
	}
	
	// THIS IS USED TO FIND THE INCOMING CALLER ID TO VALIDATE. 
	// FOR EXAMPLE, IF SOMEONE CALLS THE GSM WE CAN EXTRACT THE CALLER MOBILE NUMBER
	// TO CHECK WHETHER HE/SHE IS ADMIN/OWNER OR ANONYMOUS, ETC USING 'CLCC' COMMAND
	
	if(strcmp(Event, "RING") == 0){
		
		RING = true;
		strcpy(&OUTBUFFER[0], "AT+CLCC\r");
		WriteCOM();
		
	}
	
	//CALL SUBSTRING FUNCTION TO IDENTIFY THE EVENT WHETHER IF IT IS SMS OR ELSE 
	substring(0, 5, Event); 
	
	// IF PHONE BOOK READ COMMAND ISSUED
	if(strcmpi(substring(0, 5, Event), "+CPBR") == 0){
		
		split(Event, ",");
		
	}
	
	// IF SMS Message received
	if(strcmpi(substring(0, 5, Event), "+CMTI") == 0){
		
		//Event = "";
		OK = false;
		Error = false;
		
		split(Event, ",");
		//Event = "";
		int lenSMS_MesgNum = strlen(record[1].splitRecs);
		
		SMS_MesgNum = (char*) malloc(lenSMS_MesgNum * sizeof(int));
		sprintf(SMS_MesgNum,"%s",record[1].splitRecs);
		//Event = "";
		//getMessage(SMS_MesgNum, Event);
		
		// GETTING SMS
		char *MesgCmd = NULL;
		char ATCommand[] = "AT+CMGR=";
		char *Param = SMS_MesgNum;
		char term_char[] = "\r";
		MesgCmd = (char*) malloc((strlen(ATCommand) * sizeof(char)) + (strlen(Param) * sizeof(int)) + (strlen(term_char) * sizeof(char)) );
		
		sprintf(MesgCmd, "%s%s%s",ATCommand,Param,term_char );
		//printf("%s\n", MesgCmd);
        //return;
		strcpy(&OUTBUFFER[0], MesgCmd);
		WriteCOM(); //WRITING TO THE PORT
		//while (!OK){
			wait_for_response();
		//}
		
		//printf("%d\n", OK);
		if (OK == true){
			split(Event, ",");
			printf("%s\n", substring(1, 12, record[1].splitRecs));
			SMS_TelephoneNum = substring(1, 12, record[1].splitRecs);
			printf("%s\n", SMS_TelephoneNum);
		}
		
		
		//printf("%s\n", SMS_MesgNum);
		
		/*
		return;
		// JUST RETURN THE SMS NUMBER 1 FOR TESTING PURPOSE ONLY
		strcpy(&OUTBUFFER[0], "AT+CMGR=1\r");
		WriteCOM(); //WRITING TO THE PORT
		wait_for_response();
		*/
	}
	
	//IF GSM IS RECEIVING CALL
	if(strcmpi(substring(0, 5, Event), "+CLCC") == 0){
		
		split(Event, ",");
		//printf("%s\n", substring(4, 14, record[5].splitRecs));
		Event="";
		OK = false;
		Error = false;
		
		if (strcmpi(substring(4, 14, record[5].splitRecs), "9944232334")  == 0){
			printf("%s\n", "GSM Admin Calling...");
			
			/*
			strcpy(&OUTBUFFER[0], "ATH\r");
			WriteCOM();
			wait_for_response();
			
			char ATCommand[] = "ATD";
			char *mobileNum = substring(1, 14, record[5].splitRecs);
			char term_char[] = ";\r";
			char *NumToCall = NULL;
			NumToCall = (char*) malloc((strlen(ATCommand) * sizeof(char)) + (strlen(mobileNum) * sizeof(int)) + (strlen(term_char) * sizeof(char)));
			sprintf(NumToCall,"%s%s%s",ATCommand,mobileNum,term_char);
			strcpy(&OUTBUFFER[0], NumToCall);
			WriteCOM();
			*/
			
			//wait_for_response();
			//strcpy(&OUTBUFFER[0], "AT+CMGS=\x22substring(4, 14, record[5].splitRecs)\x22");
			
			
			//wait_for_response();
			//printf("%d\n", greaterSign);
			/*
			if (greaterSign == true){
				strcpy(&OUTBUFFER[0], "Confirmation SMS sent from GSM Unit\x1A");
				WriteCOM(); 
				wait_for_response();
			}*/
		}
		else{
			printf("%s\n", "Anonymous Call...");
			strcpy(&OUTBUFFER[0], "ATH\r");
			WriteCOM();
			wait_for_response();
		}
	}
  }
void wait_for_response(){
	   
   		  time_t seconds;
		  seconds = time (NULL);
		  
		  while (1)
		  {
			  
			  doEvents(); 
				
			  if(time(NULL) - seconds >= 5){
				break;
			  }
		  }
}
static void doEvents(){
		
	    MSG msg;
	    HWND hWnd;
		while( PeekMessage( &msg, hWnd, 0, 0, PM_REMOVE )){
						  
		   TranslateMessage( &msg );
		   DispatchMessage( &msg );
					   
		}	
}
//**********************************************************************
int main(int argc, char* argv[]){
	
	h_GSM = CreateFile(TEXT("COM1"),// open com1:
		GENERIC_READ | GENERIC_WRITE, // for reading and writing
		0,                            // exclusive access
		NULL,                         // no security attributes
		OPEN_EXISTING,                // Existing Port
		FILE_ATTRIBUTE_NORMAL,        // Non-overlapped ***
						NULL);
		if (h_GSM == INVALID_HANDLE_VALUE){
        // error processing code
		printf("Error Opening Port\n");
		return 0;
    }
    
    // Set timeouts in milliseconds
    CommTimeouts.ReadIntervalTimeout         = 0; 
    CommTimeouts.ReadTotalTimeoutMultiplier  = 0; 
    CommTimeouts.ReadTotalTimeoutConstant    = 100;
    CommTimeouts.WriteTotalTimeoutMultiplier = 0;
    CommTimeouts.WriteTotalTimeoutConstant   = 100;
    
	if(!SetCommTimeouts(h_GSM ,&CommTimeouts)){
	    // error processing code
		printf("Error setting timeouts");
		return 0;
	}
    
    // Set Port parameters.
    
    if(!GetCommState(h_GSM, &dcbConfig)){
		printf("Error getting Comm Settings");
		return 0;
	}
    
	dcbConfig.BaudRate = 9600;
        dcbConfig.StopBits = ONESTOPBIT;
        dcbConfig.ByteSize = 8;
        dcbConfig.Parity   = NOPARITY;
     
	if(!SetCommState(h_GSM, &dcbConfig)){
		printf("Error getting Comm Settings");
		return 0;
	}
	
	// DISABLE GSM MODEM 'ECHO' THE INPUT (TYPING)
	strcpy(&OUTBUFFER[0], "ATE0\r");
	WriteCOM();
	wait_for_response();

PROBLEM HERE!!!
	
******** HERE I HAVE TO CHECK THE STATUS OF "OK". IF IT IS '1' THEN START TO EXECUTE THE NEXT LINE. BUT I COULD NOT ABLE TO RECEIVE THE CORRECT STATUS OF THE "OK'. I ALWAYS RECEIVE FALSE.**********

        IF(OK == true){
	    // SET THE SMS IN TEXT MODE (PDU MODE IS DEFAULT = 0)
	       strcpy(&OUTBUFFER[0], "AT+CMGF=1\r");
	       WriteCOM();
	       wait_for_response();
        }

	// SETTING COM MASK TO FORCE THE PORT TO INFORM THE USER ONLY 
	// IF IT RECEIVES ANY EVENTS FROM GSM MODEM
    
	//if(!SetCommMask(h_GSM, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING | EV_RLSD)){
	if(!SetCommMask(h_GSM, EV_RXCHAR)){
		printf("Set Comm Mask Error!!!\n");
		return 0;
	}
	// IF WAIT COM EVENT FAILURE
	if (!WaitCommEvent(h_GSM, &dwEventMask, NULL)){
		printf("Wait Comm Event Error!!!\n");
		return 0;
	}
	
	//WAIT UNTIL EVENTS OCCURED IN THE PORT
	while(WaitCommEvent(h_GSM, &dwEventMask, NULL))	{
		
		// IF CHARACTER RECEIVED (EV_RXCHAR)
		if (dwEventMask & EV_RXCHAR){
			
			// READ THE OUTPUT OF PORT
			ReadCOM();
	 :sigh: 		
			int lenStrArray;
			int j = 0;
			
			// STORE BUFFER VALUES INTO STRING
			strArray = INBUFFER;
			lenStrArray = strArray.length();
			
			//POINTER DECLARED AS GLOBAL VARIABLE (SEE AT THE TOP)
			chrArray = (char*) realloc(chrArray,lenStrArray * sizeof(char));
			//chrArray = (char*) malloc(lenStrArray * sizeof(char));
			
			if (chrArray == NULL){
				printf("Memory allocation failed\n" );
				return 0;
			}
			
			// READ OUTPUT DATA ONE BY ONE TO ELIMINATE CARRIAGE RETURN CHARACTERS AND 
			// LINE FEED CHARACTERS AND TO EXTRACT ONLY VALID DATA
			for(int i = 0; i < lenStrArray; i++){
				/*
				if (Message_Store){
					if(strcat((char*)Message_Buffer[i], (char*)chrArray[i]) == 0){
						printf("Message store\n");
					}
				} */
				switch(strArray[i]){
				
					case '\x0A': //if line feed detected in the com output
						
						break;
					
					case '\x3E':
						
						greaterSign = true;
						printf("%d\n", greaterSign);
						break;
					case '\x0D': //if enter or carriage return detected in the com output
						
						chrArray[j] = '\0';
						int lenInput;
						lenInput = strlen(chrArray);
						
						if (lenInput> 0){
							printf("%s\n",	chrArray);
							ComEvent(chrArray);
							j=0;
						}
						
						break;
						
					default:
					
						chrArray[j] = strArray[i]; //Store the data one by one into buffer
						j++;
						
						break;
					}
			}
			
			free(chrArray);  // free memory
			chrArray = '\0'; // nullify the pointer
		}
	}
 CloseHandle(h_GSM); // Closing the Port
 h_GSM = INVALID_HANDLE_VALUE;
 return 0;
}
</time.h></windows.h></string>
Posted
Updated 14-Jan-11 21:21pm
v3
Comments
Sandeep Mewara 14-Jan-11 7:25am    
Code dump!

2 things:
1. Next time, format your code using PRE tags. It makes it readable
2. Post specific code and not whole junk of code which no one will read
pmk_1969 14-Jan-11 11:56am    
Ok. Why I posted this entire code here is that the code can help everyone who requires code in C to access GSM Modem. I searched lot and get tired till date, I could not able to find any useful information yet. Thats why I posted all the contents. Sorry, next time I can post specific code.

Move IO to a separate thread.

I would also consider ACE[^], it's a widely used[^] C++ library that provides robust implmentations of "Best practice" patterns you wiil find useful.

Douglas C. Schmidt is the primary architect behind ACE and TAO, one of the most acknowledged experts in the field.

Regards
Espen Harlinn
 
Share this answer
 
v2
Comments
Sergey Alexandrovich Kryukov 14-Jan-11 10:17am    
Espen, this is good (my 5). I would also discourage DoEvents or similar way of skipping processing between events. It's harmless but 1) often does not reach the goal, 2) can waste CPU resource without a reason.
Espen Harlinn 14-Jan-11 10:32am    
Thanks SAKryukov!
pmk_1969 14-Jan-11 11:53am    
ok. Thanks. can you please give me some sample piece of code how to move IO to a separate thread.
Espen Harlinn 14-Jan-11 12:06pm    
ACE and TAO includes an enormous amount of examples and tests - You'll surely find just what you need - here is an old, but still pretty good tutorial http://www.eol.ucar.edu/software/ACE/ACE-tutorial.pdf
That is, I declared global variable OK in C. If I try to retrieve the value in the middle of the process I could not able to get the correct value though the I set the OK value equal to true in the middle of the process.


bool OK; or char OK; is atomic[^], so you will not have any garbage value if you try to read/write "in the middle of the process" (what's that ? :doh: ).

But what you need is synchronization, so learn it before trying, you will save lot of time !

boost thread[^] may help you

Have a look also to this article :Lock & Wait Synchronization in C++[^]
 
Share this answer
 
v2
Comments
pmk_1969 14-Jan-11 11:49am    
I started learning synchronization. Thanks for your advice
jean Davy 14-Jan-11 11:52am    
New life !
Good luck...
You could look into this:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) 
{
     TranslateMessage(&msg);
     DispatchMessage(&msg);
}
 
Share this answer
 
Comments
pmk_1969 14-Jan-11 11:48am    
John Simmons / outlaw,

I tried the method. But no result
Espen Harlinn 14-Jan-11 12:31pm    
His not using asynch IO - or a COM compnent ref: CreateFile(TEXT("COM1") - BTW: 5+ It's the equivalent of DoEvents

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900