5 A Linux/Unix toolset and driver for Nokia mobile phones.
7 Released under the terms of the GNU GPL, see file COPYING for more details.
9 Provides a generic API for accessing functions on the phone, wherever
10 possible hiding the model specific details.
12 The underlying code should run in it's own thread to allow communications to
13 the phone to be run independantly of mailing code that calls these API
16 Unless otherwise noted, all functions herein block until they complete. The
17 functions themselves are defined in a structure in gsm-common.h.
28 #include "misc_win32.h"
33 #include "newmodules/n6110.h"
34 #include "newmodules/n7110.h"
35 #include "newmodules/newat.h"
37 #include "newmodules/sniff/sniff.h"
39 #include "protocol/fbusirda.h"
40 #include "protocol/fbus.h"
41 #include "protocol/mbus.h"
42 #include "protocol/at.h"
43 #include "files/cfgreader.h"
46 #include "devices/device.h"
50 /* for VC6 make scripts save VERSION constant in mversion.h file */
54 /* GSM_LinkOK is set to true once normal communications with the phone have
59 /* Define pointer to the GSM_Functions structure used by external code to call
60 relevant API functions. This structure is defined in gsm-common.h. */
64 /* Define pointer to the GSM_Information structure used by external code to
65 obtain information that varies from model to model. This structure is also
66 defined in gsm-common.h */
68 GSM_Information *GSM_Info;
70 /* Initialise interface to the phone. Model number should be a string such as
71 3810, 5110, 6110 etc. Device is the serial port to use e.g. /dev/ttyS0, the
72 user must have write permission to the device. */
74 GSM_Protocol *Protocol;
76 /* Local variables used by get/set phonebook entry code. Buffer is used as a
77 source or destination for phonebook data and other functions... Error is
78 set to GE_NONE by calling function, set to GE_COMPLETE or an error code by
79 handler routines as appropriate. */
81 GSM_PhonebookEntry *CurrentPhonebookEntry;
82 GSM_Error CurrentPhonebookError;
84 GSM_SpeedDial *CurrentSpeedDialEntry;
85 GSM_Error CurrentSpeedDialError;
87 unsigned char Current_IMEI[GSM_MAX_IMEI_LENGTH];
88 unsigned char Current_Revision[GSM_MAX_REVISION_LENGTH];
89 unsigned char Current_Model[GSM_MAX_MODEL_LENGTH];
91 GSM_SMSMessage *CurrentSMSMessage;
92 GSM_Error CurrentSMSMessageError;
93 int CurrentSMSPointer;
95 GSM_SMSFolders *CurrentSMSFolders;
96 GSM_Error CurrentSMSFoldersError;
97 int CurrentSMSFoldersCount;
99 GSM_OneSMSFolder CurrentSMSFolder;
100 GSM_Error CurrentSMSFolderError;
101 int CurrentSMSFolderID;
103 GSM_MemoryStatus *CurrentMemoryStatus;
104 GSM_Error CurrentMemoryStatusError;
106 GSM_NetworkInfo *CurrentNetworkInfo;
107 GSM_Error CurrentNetworkInfoError;
109 GSM_SMSStatus *CurrentSMSStatus;
110 GSM_Error CurrentSMSStatusError;
112 GSM_MessageCenter *CurrentMessageCenter;
113 GSM_Error CurrentMessageCenterError;
115 int *CurrentSecurityCodeStatus;
116 GSM_Error CurrentSecurityCodeError;
117 GSM_SecurityCode *CurrentSecurityCode;
119 GSM_DateTime *CurrentDateTime;
120 GSM_Error CurrentDateTimeError;
122 GSM_DateTime *CurrentAlarm;
123 GSM_Error CurrentAlarmError;
125 GSM_CalendarNote *CurrentCalendarNote;
126 GSM_Error CurrentCalendarNoteError;
128 GSM_NotesInfo CurrentCalendarNotesInfo,*CurrentCalendarNotesInfo2;
129 GSM_Error CurrentCalendarNotesInfoError;
131 GSM_Error CurrentSetDateTimeError;
132 GSM_Error CurrentSetAlarmError;
134 GSM_Error CurrentEnableExtendedCommandsError;
140 int CurrentDisplayStatus;
141 GSM_Error CurrentDisplayStatusError;
143 GSM_Error CurrentResetPhoneSettingsError;
145 char *CurrentNetmonitor;
146 GSM_Error CurrentNetmonitorError;
148 GSM_Bitmap *CurrentGetBitmap=NULL;
149 GSM_Error CurrentGetBitmapError;
151 GSM_Error CurrentSetBitmapError;
153 GSM_Error CurrentSendDTMFError;
155 GSM_Profile *CurrentProfile;
156 GSM_Error CurrentProfileError;
158 GSM_Error CurrentDisplayOutputError;
160 GSM_CBMessage *CurrentCBMessage;
161 GSM_Error CurrentCBError;
163 int CurrentPressKeyEvent;
164 GSM_Error CurrentPressKeyError;
166 GSM_Error CurrentPlayToneError=GE_UNKNOWN;
168 GSM_Error CurrentDialVoiceError;
170 GSM_Error CurrentGetOperatorNameError;
171 GSM_Network *CurrentGetOperatorNameNetwork;
172 GSM_Error CurrentSetOperatorNameError;
174 GSM_Error CurrentGetIMEIError;
176 GSM_Error CurrentGetHWError;
178 unsigned char CurrentPPS[4];
179 GSM_Error CurrentProductProfileSettingsError;
181 char CurrentIncomingCall[20];
183 GSM_Error CurrentBinRingtoneError;
184 GSM_BinRingtone *CurrentGetBinRingtone=NULL;
186 GSM_Error CurrentRingtoneError;
188 GSM_Error CurrentMagicError;
190 GSM_Error CurrentSimlockInfoError;
191 GSM_AllSimlocks *CurrentSimLock;
193 GSM_Error CurrentGetWAPBookmarkError;
194 GSM_Error CurrentSetWAPBookmarkError;
195 GSM_WAPBookmark *WAPBookmark;
197 GSM_Error CurrentGetWAPSettingsError;
198 GSM_WAPSettings *WAPSettings;
200 GSM_Error CurrentCallDivertError;
201 GSM_CallDivert *CurrentCallDivert;
203 char *CurrentManufacturer;
205 /* This is the connection type used in gnokii. */
206 GSM_ConnectionType CurrentConnectionType;
208 /* Pointer to a callback function used to return changes to a calls status */
209 /* This saves unreliable polling */
210 void (*CurrentCallPassup)(char c);
212 /* Pointer to callback function in user code to be called when RLP frames
214 void (*CurrentRLP_RXCallback)(RLP_F96Frame *frame);
216 /* Used to disconnect the call */
217 u8 CurrentCallSequenceNumber;
221 bool CurrentRequestTerminate;
223 bool CurrentDisableKeepAlive;
225 bool CheckModel (GSM_Information InfoToCheck, char *model, GSM_ConnectionType connection) {
227 bool found_match=false;
229 if (strstr(InfoToCheck.FBUSModels, model) != NULL) {
230 if (connection==GCT_FBUS) found_match=true;
232 if (strstr(InfoToCheck.MBUSModels, model) != NULL) {
233 if (connection==GCT_MBUS) found_match=true;
235 if (strstr(InfoToCheck.InfraredModels, model) != NULL) {
236 if (connection==GCT_Infrared) found_match=true;
238 if (strstr(InfoToCheck.DLR3Models, model) != NULL) {
239 if (connection==GCT_DLR3) found_match=true;
241 if (strstr(InfoToCheck.IrdaModels, model) != NULL) {
242 if (connection==GCT_Irda) found_match=true;
244 if (strstr(InfoToCheck.ATModels, model) != NULL) {
245 if (connection==GCT_AT) found_match=true;
247 if (strstr(InfoToCheck.TekramModels, model) != NULL) {
248 if (connection==GCT_Tekram) found_match=true;
254 GSM_Error TryNewNokia(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame)) {
257 unsigned char init_char = N6110_SYNC_BYTE;
259 /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
262 if (Protocol->Initialise(device,initlength,connection,rlp_callback)!=GE_NONE)
264 return GE_NOTSUPPORTED;
267 if (connection!=GCT_MBUS) {
268 InitLength = atoi(initlength);
270 if ((strcmp(initlength, "default") == 0) || (InitLength == 0)) {
271 InitLength = 250; /* This is the usual value, lower may work. */
275 fprintf(stdout,_("Writing init chars...."));
278 /* Initialise link with phone or what have you */
279 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
281 for (count = 0; count < InitLength; count ++) {
283 Protocol->WritePhone(1,&init_char);
287 fprintf(stdout,_("Done\n"));
290 N6110_SendStatusRequest();
295 if (N6110_SendIDFrame()!=GE_NONE)
298 while (N6110_GetModel(phonemodel) != GE_NONE)
301 if (!strcmp(phonemodel,"NPE-3") || !strcmp(phonemodel,"NSE-5"))
305 /* Set pointers to relevant addresses */
306 GSM = &N7110_Functions;
307 GSM_Info = &N7110_Information;
308 GSM_LinkOK = &CurrentLinkOK;
315 GSM_Error GSM_Initialise(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame), char* SynchronizeTime)
317 bool found_match=false;
319 GSM_ConnectionType connection2;
326 connection2=connection;
328 CurrentRLP_RXCallback = rlp_callback;
329 CurrentCallPassup=NULL;
330 CurrentPhonebookEntry=NULL;
331 CurrentNetworkInfo = NULL;
332 CurrentGetBitmap=NULL;
333 CurrentPlayToneError=GE_UNKNOWN;
334 strcpy(CurrentIncomingCall," ");
335 CurrentGetBinRingtone=NULL;
336 CurrentNetworkInfo=NULL;
337 CurrentRequestTerminate=false;
338 CurrentDisableKeepAlive=false;
339 CurrentCalendarNotesInfo.HowMany=2000;
340 CurrentMagicError = GE_BUSY;
342 if (!strcmp(model,"auto")) {
345 GSM = &N6110_Functions;
346 GSM_Info = &N6110_Information;
347 GSM_LinkOK = &CurrentLinkOK;
349 fprintf(stdout,_("Trying FBUS for new Nokia phones...\n"));
352 Protocol = &FBUS_Functions;
353 CurrentConnectionType=GCT_FBUS;
354 connection2=GCT_FBUS;
355 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
366 GSM = &N6110_Functions;
367 GSM_Info = &N6110_Information;
368 GSM_LinkOK = &CurrentLinkOK;
370 fprintf(stdout,_("Trying DLR3 for new Nokia phones...\n"));
373 Protocol = &FBUS_Functions;
374 CurrentConnectionType=GCT_DLR3;
375 connection2=GCT_DLR3;
376 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
388 GSM = &N6110_Functions;
389 GSM_Info = &N6110_Information;
390 GSM_LinkOK = &CurrentLinkOK;
392 fprintf(stdout,_("Trying MBUS for new Nokia phones...\n"));
395 Protocol = &MBUS_Functions;
396 CurrentConnectionType=GCT_MBUS;
397 connection2=GCT_MBUS;
398 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
406 if (!found_match) return GE_NOTSUPPORTED;
412 if (CheckModel (Nsniff_Information, model, connection)) {
413 /* Set pointers to relevant addresses */
414 GSM = &Nsniff_Functions;
415 GSM_Info = &Nsniff_Information;
416 GSM_LinkOK = &CurrentLinkOK;
421 if (CheckModel (N6110_Information, model, connection)) {
422 /* Set pointers to relevant addresses */
423 GSM = &N6110_Functions;
424 GSM_Info = &N6110_Information;
425 GSM_LinkOK = &CurrentLinkOK;
428 if (CheckModel (N7110_Information, model, connection)) {
429 /* Set pointers to relevant addresses */
430 GSM = &N7110_Functions;
431 GSM_Info = &N7110_Information;
432 GSM_LinkOK = &CurrentLinkOK;
435 if (CheckModel (Nat_Information, model, connection)) {
436 /* Set pointers to relevant addresses */
437 GSM = &Nat_Functions;
438 GSM_Info = &Nat_Information;
439 GSM_LinkOK = &CurrentLinkOK;
444 switch (connection) {
445 case GCT_FBUS : Protocol = &FBUS_Functions; break;
446 case GCT_Infrared: Protocol = &FBUS_Functions; break;
447 case GCT_Tekram : Protocol = &FBUS_Functions; break;
448 case GCT_DLR3 : Protocol = &FBUS_Functions; break;
449 case GCT_MBUS : Protocol = &MBUS_Functions; break;
450 case GCT_Irda : Protocol = &FBUSIRDA_Functions;break;
451 case GCT_AT : Protocol = &AT_Functions; break;
452 case GCT_Default : Protocol = NULL; break;
455 return GE_NOTSUPPORTED;
459 /* Now call model specific initialisation code. */
460 error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
462 /* RTH: FIXME: second try for Irda (6210 only?)*/
463 if ( error!=GE_NONE && connection == GCT_Irda)
466 fprintf(stdout,"Irda connection: second try!\n");
469 error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
472 if (error==GE_NONE && !strcmp(SynchronizeTime,"yes"))
475 now=localtime(&nowh);
477 Date.Year = now->tm_year;
478 Date.Month = now->tm_mon+1;
479 Date.Day = now->tm_mday;
480 Date.Hour = now->tm_hour;
481 Date.Minute = now->tm_min;
482 Date.Second = now->tm_sec;
487 /* Well, this thing is copyrighted in U.S. This technique is known as
488 Windowing and you can read something about it in LinuxWeekly News:
489 http://lwn.net/1999/features/Windowing.phtml. This thing is beeing
490 written in Czech republic and Poland where algorithms are not allowed
494 Date.Year = Date.Year+1900;
496 Date.Year = Date.Year+2000;
499 /* FIXME: Error checking should be here. */
500 GSM->SetDateTime(&Date);
506 GSM_Error Unimplemented(void)
508 return GE_NOTIMPLEMENTED;
511 GSM_Error NotSupported(void)
513 return GE_NOTSUPPORTED;
516 /* Applications should call N6110_Terminate to shut down the N6110 thread and
517 close the serial port. */
518 void NULL_Terminate(void)
520 Protocol->Terminate();
524 /* Here are things made for keeping connecting */
525 void NULL_KeepAlive()
529 /* Here are things made for keeping connecting */
530 void NULL_KeepAlive()
536 void NULL_TX_DisplayMessage(u16 MessageLength, u8 *MessageBuffer)
538 fprintf(stdout, _("PC: "));
540 txhexdump(MessageLength,MessageBuffer);
544 bool NULL_WritePhone (u16 length, u8 *buffer) {
545 if (device_write(buffer,length)!=length) return false;
549 GSM_Error NULL_WaitUntil (int time, GSM_Error *value)
555 /* Wait for timeout or other error. */
556 while (timeout != 0 && *value == GE_BUSY ) {
567 GSM_Error NULL_SendMessageSequence (int time, GSM_Error *value,
568 u16 message_length, u8 message_type, u8 *buffer)
572 Protocol->SendMessage(message_length, message_type, buffer);
574 return NULL_WaitUntil (time, value);
577 GSM_ConnectionType GetConnectionTypeFromString(char *Connection) {
579 GSM_ConnectionType connection=GCT_FBUS;
581 if (!strcmp(Connection, "irda")) connection=GCT_Irda;
582 if (!strcmp(Connection, "infrared")) connection=GCT_Infrared;
583 if (!strcmp(Connection, "mbus")) connection=GCT_MBUS;
584 if (!strcmp(Connection, "dlr3")) connection=GCT_DLR3;
585 if (!strcmp(Connection, "at")) connection=GCT_AT;
586 if (!strcmp(Connection, "tekram210"))connection=GCT_Tekram;
591 bool GetMemoryTypeString(char *memorytext, GSM_MemoryType *type)
600 GSM_MTStrings mystring[] = {
614 while (strcmp(mystring[i].name,"undefined")) {
615 if (*type==mystring[i].type) {
616 strcpy(memorytext,mystring[i].name);
624 bool GetMemoryTypeID(char *memorytext, GSM_MemoryType *type)
633 GSM_MTStrings mystring[] = {
647 while (strcmp(mystring[i].name,"undefined")) {
648 if (strcmp(mystring[i].name,memorytext)==0) {
649 *type=mystring[i].type;
658 char *GetMygnokiiVersion() {
660 static char Buffer[1000]="";
662 sprintf(Buffer, "%s",VERSION);
668 1.Name,2.CodeName,3.Calendar,4.Netmonitor,5.Caller groups,6.Phonebook,
669 7.Authentication 8.Datacalls 9.KeysPressing 10.SMSC Default Recipient
670 11.SpeedDials 12.ScreenSavers 13.DTMF 14.SMS 15.NoPowerFrame 16.StartUpLogo
671 17.Profiles 18.Ringtones 19.WAP
674 static OnePhoneModel allmodels[] = {
676 /*1, 2, 3, 4, 5, 6 7 8 9 10 11 12 13 14 15 16 17 18 19 */
677 {"3210","NSE-8",{ 0,F_NETMON, 0, 0, 0, 0, 0,F_SMSCDEF,F_SPEED, 0, 0,F_SMS ,F_NOPOWER,F_STANIM,F_PROF51,F_RINGBIN, 0}},
678 {"3210","NSE-9",{ 0,F_NETMON, 0, 0, 0, 0, 0,F_SMSCDEF,F_SPEED, 0, 0,F_SMS ,F_NOPOWER,F_STANIM,F_PROF51,F_RINGBIN, 0}},
679 {"3310","NHM-5",{F_CAL33,F_NETMON, 0,F_PBK33, 0, 0, 0,F_SMSCDEF,F_SPEED,F_SCRSAV, 0,F_SMS ,F_NOPOWER,F_STANIM,F_PROF33,F_RING_SM, 0}},
680 {"3330","NHM-6",{F_CAL33,F_NETMON, 0,F_PBK33, 0, 0,F_KEYB,F_SMSCDEF,F_SPEED,F_SCRSAV, 0,F_SMS , 0,F_STANIM,F_PROF33,F_RING_SM,F_WAP}},
681 {"5110","NSE-1",{ 0,F_NETMON, 0, 0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0, 0,F_PROF51, 0, 0}},
682 {"5130","NSK-1",{ 0,F_NETMON, 0, 0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0, 0,F_PROF51, 0, 0}},
683 {"5190","NSB-1",{ 0,F_NETMON, 0, 0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0, 0,F_PROF51, 0, 0}},
684 {"6110","NSE-3",{F_CAL61,F_NETMON,F_CALER61, 0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0,F_STA ,F_PROF61,F_RINGBIN, 0}},
685 {"6130","NSK-3",{F_CAL61,F_NETMON,F_CALER61, 0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0,F_STA ,F_PROF61,F_RINGBIN, 0}},
686 {"6150","NSM-1",{F_CAL61,F_NETMON,F_CALER61, 0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0,F_STA ,F_PROF61,F_RINGBIN, 0}},
687 {"6190","NSB-3",{F_CAL61,F_NETMON,F_CALER61, 0,F_AUTH,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0,F_STA ,F_PROF61,F_RINGBIN, 0}},
688 {"6210","NPE-3",{F_CAL71,F_NETMON,F_CALER61,F_PBK71, 0,F_DATA71, 0,F_SMSCDEF,F_SPEED, 0, 0,F_SMS71, 0,F_STA62 ,F_PROF61,F_RINGBIN,F_WAP}},
689 {"6250","NHM-3",{F_CAL71,F_NETMON,F_CALER61,F_PBK71, 0,F_DATA71, 0,F_SMSCDEF,F_SPEED, 0, 0,F_SMS71, 0,F_STA62 ,F_PROF61,F_RINGBIN,F_WAP}},
690 {"7110","NSE-5",{F_CAL71,F_NETMON,F_CALER61,F_PBK71, 0,F_DATA71, 0,F_SMSCDEF,F_SPEED, 0, 0,F_SMS71, 0,F_STA71 ,F_PROF61,F_RINGBIN,F_WAP}},
691 {"8210","NSM-3",{ 0,F_NETMON,F_CALER61, 0, 0,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0,F_STA ,F_PROF61,F_RINGBIN, 0}},
692 {"8850","NSM-2",{ 0,F_NETMON,F_CALER61, 0, 0,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0,F_STA ,F_PROF61,F_RINGBIN, 0}},
693 {"9210","RAE-3",{ 0,F_NETMON,F_CALER61, 0, 0,F_DATA61,F_KEYB,F_SMSCDEF,F_SPEED, 0,F_DTMF,F_SMS , 0,F_STA ,F_PROF61,F_RINGBIN, 0}},//quesses only !
694 {"" ,"" ,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
697 OnePhoneModel *GetPhoneModelData (const char *num)
701 while (allmodels[i].number != "") {
702 if (strcmp (num, allmodels[i].number) == 0) {
703 return (&allmodels[i]);
708 return (&allmodels[i]);
711 char *GetModelName ()
713 static char model[64];
715 while (GSM->GetModel(model) != GE_NONE) sleep(1);
717 return (GetPhoneModelData(model)->model);
720 int GetModelFeature (featnum_index num)
722 static char model[64];
724 while (GSM->GetModel(model) != GE_NONE) sleep(1);
726 return (GetPhoneModelData(model)->features[num]);
729 int LogAvailable=-1; //-1 not checked earlier, 0 not, 1 yes
732 bool AppendLog(u8 *buffer, int length,bool format)
738 struct CFG_Header *cfg_info;
741 if (LogAvailable==-1) {
745 cfg_info=CFG_FindGnokiirc();
746 if (cfg_info==NULL) return false;
748 LogFile = CFG_Get(cfg_info, "global", "logfile");
753 file=fopen(logfilename, "a+");
755 /* We have first entry in this session and too large file */
756 if (fread( buffer2, 1, 50000,file )==50000) {
758 file=fopen(logfilename, "w");
762 if (LogAvailable==1) {
763 file=fopen(logfilename, "a");
767 if (LogAvailable==1) {
768 for (i=0;i<length;i++) {
770 fprintf(file, "%02x",buffer[i]);
772 case 0x09:fprintf(file,_(" |"));break;
774 if (isprint(buffer[i])) fprintf(file, _("%c|"),buffer[i]);
775 else fprintf(file, _(" |"));
779 fprintf(file, "%c",buffer[i]);
782 if (format) fprintf(file, "\n");
786 return (LogAvailable==1);
789 bool AppendLogText(u8 *buffer,bool format)
791 return AppendLog(buffer,strlen(buffer),format);