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.
30 #include "misc_win32.h"
36 #include "newmodules/n6110.h"
37 #include "newmodules/n7110.h"
38 #include "newmodules/newat.h"
40 #include "newmodules/sniff/sniff.h"
42 #include "protocol/fbusirda.h"
44 #include "protocol/fbus.h"
46 #include "protocol/mbus.h"
47 #include "protocol/at.h"
49 #include "files/cfgreader.h"
52 #include "devices/device.h"
56 /* for VC6 make scripts save VERSION constant in mversion.h file */
60 /* GSM_LinkOK is set to true once normal communications with the phone have
65 /* Define pointer to the GSM_Functions structure used by external code to call
66 relevant API functions. This structure is defined in gsm-common.h. */
70 /* Define pointer to the GSM_Information structure used by external code to
71 obtain information that varies from model to model. This structure is also
72 defined in gsm-common.h */
74 GSM_Information *GSM_Info;
76 /* Initialise interface to the phone. Model number should be a string such as
77 3810, 5110, 6110 etc. Device is the serial port to use e.g. /dev/ttyS0, the
78 user must have write permission to the device. */
80 GSM_Protocol *Protocol;
82 /* Local variables used by get/set phonebook entry code. Buffer is used as a
83 source or destination for phonebook data and other functions... Error is
84 set to GE_NONE by calling function, set to GE_COMPLETE or an error code by
85 handler routines as appropriate. */
87 GSM_PhonebookEntry *CurrentPhonebookEntry;
88 GSM_Error CurrentPhonebookError;
90 GSM_SpeedDial *CurrentSpeedDialEntry;
91 GSM_Error CurrentSpeedDialError;
93 unsigned char Current_IMEI[GSM_MAX_IMEI_LENGTH];
94 unsigned char Current_Revision[GSM_MAX_REVISION_LENGTH];
95 unsigned char Current_Model[GSM_MAX_MODEL_LENGTH];
98 GSM_SMSMessage *CurrentSMSMessage;
99 GSM_Error CurrentSMSMessageError;
100 int CurrentSMSPointer;
102 GSM_SMSFolders *CurrentSMSFolders;
103 GSM_Error CurrentSMSFoldersError;
104 int CurrentSMSFoldersCount;
106 GSM_OneSMSFolder CurrentSMSFolder;
107 GSM_Error CurrentSMSFolderError;
108 int CurrentSMSFolderID;
111 GSM_MemoryStatus *CurrentMemoryStatus;
112 GSM_Error CurrentMemoryStatusError;
115 GSM_NetworkInfo *CurrentNetworkInfo;
116 GSM_Error CurrentNetworkInfoError;
118 GSM_SMSStatus *CurrentSMSStatus;
119 GSM_Error CurrentSMSStatusError;
121 GSM_MessageCenter *CurrentMessageCenter;
122 GSM_Error CurrentMessageCenterError;
124 int *CurrentSecurityCodeStatus;
125 GSM_Error CurrentSecurityCodeError;
126 GSM_SecurityCode *CurrentSecurityCode;
128 GSM_DateTime *CurrentDateTime;
129 GSM_Error CurrentDateTimeError;
131 GSM_Error CurrentResetPhoneSettingsError;
133 GSM_DateTime *CurrentAlarm;
134 GSM_Error CurrentAlarmError;
136 GSM_CalendarNote *CurrentCalendarNote;
137 GSM_Error CurrentCalendarNoteError;
139 GSM_NotesInfo CurrentCalendarNotesInfo,*CurrentCalendarNotesInfo2;
140 GSM_Error CurrentCalendarNotesInfoError;
142 GSM_Error CurrentSetDateTimeError;
143 GSM_Error CurrentSetAlarmError;
145 int *CurrentFirstCalendarFreePos;
146 GSM_Error CurrentFirstCalendarFreePosError;
149 GSM_Error CurrentEnableExtendedCommandsError;
156 int CurrentDisplayStatus;
157 GSM_Error CurrentDisplayStatusError;
159 char *CurrentNetmonitor;
160 GSM_Error CurrentNetmonitorError;
162 GSM_Bitmap *CurrentGetBitmap=NULL;
163 GSM_Error CurrentGetBitmapError;
165 GSM_Error CurrentSetBitmapError;
167 GSM_Error CurrentSendDTMFError;
169 GSM_Profile *CurrentProfile;
170 GSM_Error CurrentProfileError;
172 GSM_Error CurrentDisplayOutputError;
174 GSM_CBMessage *CurrentCBMessage;
175 GSM_Error CurrentCBError;
177 int CurrentPressKeyEvent;
178 GSM_Error CurrentPressKeyError;
180 GSM_Error CurrentPlayToneError=GE_UNKNOWN;
183 GSM_Error CurrentDialVoiceError;
186 GSM_Error CurrentGetOperatorNameError;
187 GSM_Network *CurrentGetOperatorNameNetwork;
188 GSM_Error CurrentSetOperatorNameError;
191 GSM_Error CurrentGetIMEIError;
193 GSM_Error CurrentGetHWError;
196 unsigned char CurrentPPS[4];
197 GSM_Error CurrentProductProfileSettingsError;
199 char CurrentIncomingCall[20];
201 GSM_Error CurrentBinRingtoneError;
202 GSM_BinRingtone *CurrentGetBinRingtone=NULL;
204 GSM_Error CurrentRingtoneError;
207 GSM_Error CurrentMagicError;
210 GSM_Error CurrentSimlockInfoError;
211 GSM_AllSimlocks *CurrentSimLock;
213 GSM_Error CurrentGetWAPBookmarkError;
214 GSM_Error CurrentSetWAPBookmarkError;
215 GSM_WAPBookmark *WAPBookmark;
217 GSM_Error CurrentGetWAPSettingsError;
218 GSM_WAPSettings *WAPSettings;
220 GSM_Error CurrentCallDivertError;
221 GSM_CallDivert *CurrentCallDivert;
223 char *CurrentManufacturer;
226 /* This is the connection type used in gnokii. */
227 GSM_ConnectionType CurrentConnectionType;
229 /* Pointer to a callback function used to return changes to a calls status */
230 /* This saves unreliable polling */
231 void (*CurrentCallPassup)(char c);
233 /* Pointer to callback function in user code to be called when RLP frames
235 void (*CurrentRLP_RXCallback)(RLP_F96Frame *frame);
237 /* Used to disconnect the call */
238 u8 CurrentCallSequenceNumber;
242 bool CurrentRequestTerminate;
245 bool CurrentDisableKeepAlive;
251 bool CheckModel (GSM_Information InfoToCheck, char *model, GSM_ConnectionType connection) {
253 bool found_match=false;
255 if (strstr(InfoToCheck.FBUSModels, model) != NULL) {
256 if (connection==GCT_FBUS) found_match=true;
259 if (strstr(InfoToCheck.MBUSModels, model) != NULL) {
260 if (connection==GCT_MBUS) found_match=true;
262 if (strstr(InfoToCheck.InfraredModels, model) != NULL) {
263 if (connection==GCT_Infrared) found_match=true;
265 if (strstr(InfoToCheck.DLR3Models, model) != NULL) {
266 if (connection==GCT_DLR3) found_match=true;
268 if (strstr(InfoToCheck.IrdaModels, model) != NULL) {
269 if (connection==GCT_Irda) found_match=true;
271 if (strstr(InfoToCheck.ATModels, model) != NULL) {
272 if (connection==GCT_AT) found_match=true;
274 if (strstr(InfoToCheck.TekramModels, model) != NULL) {
275 if (connection==GCT_Tekram) found_match=true;
284 GSM_Error TryNewNokia(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame)) {
287 unsigned char init_char = N6110_SYNC_BYTE;
289 /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
292 if (Protocol->Initialise(device,initlength,connection,rlp_callback)!=GE_NONE)
294 return GE_NOTSUPPORTED;
297 if (connection!=GCT_MBUS) {
298 InitLength = atoi(initlength);
300 if ((strcmp(initlength, "default") == 0) || (InitLength == 0)) {
301 InitLength = 250; /* This is the usual value, lower may work. */
305 fprintf(stdout,_("Writing init chars...."));
308 /* Initialise link with phone or what have you */
309 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
311 for (count = 0; count < InitLength; count ++) {
313 Protocol->WritePhone(1,&init_char);
317 fprintf(stdout,_("Done\n"));
320 N6110_SendStatusRequest();
325 if (N6110_SendIDFrame()!=GE_NONE)
328 while (N6110_GetModel(phonemodel) != GE_NONE)
332 if (!strcmp(phonemodel,"NPE-3") || !strcmp(phonemodel,"NSE-5"))
336 /* Set pointers to relevant addresses */
337 GSM = &N7110_Functions;
338 GSM_Info = &N7110_Information;
339 GSM_LinkOK = &CurrentLinkOK;
348 extern GSM_Information N6110_Information;
349 extern GSM_Functions N6110_Functions;
351 GSM_Error GSM_Initialise(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame), char* SynchronizeTime)
353 bool found_match=false;
355 GSM_ConnectionType connection2;
364 connection2=connection;
366 CurrentRLP_RXCallback = rlp_callback;
367 CurrentCallPassup=NULL;
368 CurrentPhonebookEntry=NULL;
370 CurrentNetworkInfo = NULL;
371 CurrentGetBitmap=NULL;
372 CurrentPlayToneError=GE_UNKNOWN;
373 strcpy(CurrentIncomingCall," ");
374 CurrentGetBinRingtone=NULL;
375 CurrentNetworkInfo=NULL;
377 CurrentRequestTerminate=false;
379 CurrentDisableKeepAlive=false;
380 CurrentCalendarNotesInfo.HowMany=2000;
382 CurrentMagicError = GE_BUSY;
385 if (!strcmp(model,"auto")) {
388 GSM = &N6110_Functions;
389 GSM_Info = &N6110_Information;
390 GSM_LinkOK = &CurrentLinkOK;
392 fprintf(stdout,_("Trying FBUS for new Nokia phones...\n"));
395 Protocol = &FBUS_Functions;
396 CurrentConnectionType=GCT_FBUS;
397 connection2=GCT_FBUS;
398 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
409 GSM = &N6110_Functions;
410 GSM_Info = &N6110_Information;
411 GSM_LinkOK = &CurrentLinkOK;
413 fprintf(stdout,_("Trying DLR3 for new Nokia phones...\n"));
416 Protocol = &FBUS_Functions;
417 CurrentConnectionType=GCT_DLR3;
418 connection2=GCT_DLR3;
419 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
431 GSM = &N6110_Functions;
432 GSM_Info = &N6110_Information;
433 GSM_LinkOK = &CurrentLinkOK;
435 fprintf(stdout,_("Trying MBUS for new Nokia phones...\n"));
438 Protocol = &MBUS_Functions;
439 CurrentConnectionType=GCT_MBUS;
440 connection2=GCT_MBUS;
442 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
452 if (!found_match) return GE_NOTSUPPORTED;
461 if (CheckModel (Nsniff_Information, model, connection)) {
462 /* Set pointers to relevant addresses */
463 GSM = &Nsniff_Functions;
464 GSM_Info = &Nsniff_Information;
465 GSM_LinkOK = &CurrentLinkOK;
471 if (CheckModel (N6110_Information, model, connection)) {
472 /* Set pointers to relevant addresses */
473 GSM = &N6110_Functions;
474 GSM_Info = &N6110_Information;
475 GSM_LinkOK = &CurrentLinkOK;
479 if (CheckModel (N7110_Information, model, connection)) {
480 /* Set pointers to relevant addresses */
481 GSM = &N7110_Functions;
482 GSM_Info = &N7110_Information;
483 GSM_LinkOK = &CurrentLinkOK;
486 if (CheckModel (Nat_Information, model, connection)) {
487 /* Set pointers to relevant addresses */
488 GSM = &Nat_Functions;
489 GSM_Info = &Nat_Information;
490 GSM_LinkOK = &CurrentLinkOK;
496 switch (connection) {
497 case GCT_FBUS : Protocol = &FBUS_Functions; break;
499 case GCT_Infrared: Protocol = &FBUS_Functions; break;
500 case GCT_Tekram : Protocol = &FBUS_Functions; break;
501 case GCT_DLR3 : Protocol = &FBUS_Functions; break;
502 case GCT_MBUS : Protocol = &MBUS_Functions; break;
503 case GCT_Irda : Protocol = &FBUSIRDA_Functions;break;
504 case GCT_AT : Protocol = &AT_Functions; break;
505 case GCT_Default : Protocol = NULL; break;
509 return GE_NOTSUPPORTED;
513 /* Now call model specific initialisation code. */
514 error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
517 /* RTH: FIXME: second try for Irda (6210 only?)*/
518 if ( error!=GE_NONE && connection == GCT_Irda)
521 fprintf(stdout,"Irda connection: second try!\n");
524 error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
529 if (error==GE_NONE && !strcmp(SynchronizeTime,"yes"))
532 now=localtime(&nowh);
534 Date.Year = now->tm_year;
535 Date.Month = now->tm_mon+1;
536 Date.Day = now->tm_mday;
537 Date.Hour = now->tm_hour;
538 Date.Minute = now->tm_min;
539 Date.Second = now->tm_sec;
544 /* Well, this thing is copyrighted in U.S. This technique is known as
545 Windowing and you can read something about it in LinuxWeekly News:
546 http://lwn.net/1999/features/Windowing.phtml. This thing is beeing
547 written in Czech republic and Poland where algorithms are not allowed
551 Date.Year = Date.Year+1900;
553 Date.Year = Date.Year+2000;
556 /* FIXME: Error checking should be here. */
557 GSM->SetDateTime(&Date);
566 GSM_Error Unimplemented(void)
568 return GE_NOTIMPLEMENTED;
571 GSM_Error NotSupported(void)
573 return GE_NOTSUPPORTED;
578 /* Applications should call N6110_Terminate to shut down the N6110 thread and
579 close the serial port. */
580 void NULL_Terminate(void)
582 Protocol->Terminate();
586 /* Here are things made for keeping connecting */
587 void NULL_KeepAlive()
591 /* Here are things made for keeping connecting */
592 void NULL_KeepAlive()
598 void NULL_TX_DisplayMessage(u16 MessageLength, u8 *MessageBuffer)
600 fprintf(stdout, _("PC: "));
602 txhexdump(MessageLength,MessageBuffer);
606 bool NULL_WritePhone (u16 length, u8 *buffer) {
607 if (device_write(buffer,length)!=length) return false;
611 GSM_Error NULL_WaitUntil (int time, GSM_Error *value)
617 /* Wait for timeout or other error. */
618 while (timeout != 0 && *value == GE_BUSY ) {
629 GSM_Error NULL_SendMessageSequence (int time, GSM_Error *value,
630 u16 message_length, u8 message_type, u8 *buffer)
634 Protocol->SendMessage(message_length, message_type, buffer);
636 return NULL_WaitUntil (time, value);
639 GSM_ConnectionType GetConnectionTypeFromString(char *Connection) {
641 GSM_ConnectionType connection=GCT_FBUS;
644 if (!strcmp(Connection, "irda")) connection=GCT_Irda;
645 if (!strcmp(Connection, "infrared")) connection=GCT_Infrared;
646 if (!strcmp(Connection, "mbus")) connection=GCT_MBUS;
647 if (!strcmp(Connection, "dlr3")) connection=GCT_DLR3;
648 if (!strcmp(Connection, "at")) connection=GCT_AT;
649 if (!strcmp(Connection, "tekram210"))connection=GCT_Tekram;
655 bool GetMemoryTypeString(char *memorytext, GSM_MemoryType *type)
664 static GSM_MTStrings mystring[] = {
678 while (strcmp(mystring[i].name,"undefined")) {
679 if (*type==mystring[i].type) {
680 strcpy(memorytext,mystring[i].name);
688 bool GetMemoryTypeID(char *memorytext, GSM_MemoryType *type)
697 static GSM_MTStrings mystring[] = {
711 while (strcmp(mystring[i].name,"undefined")) {
712 if (strcmp(mystring[i].name,memorytext)==0) {
713 *type=mystring[i].type;
722 char *GetMygnokiiVersion() {
724 static char Buffer[1000]="";
726 sprintf(Buffer, "%s",VERSION);
732 1.Name,2.CodeName,3.Calendar,4.Netmonitor,5.Caller groups,6.Phonebook,
733 7.Authentication 8.Datacalls 9.KeysPressing 10.SMSC Default Recipient
734 11.SpeedDials 12.ScreenSavers 13.DTMF 14.SMS 15.NoPowerFrame 16.StartUpLogo
735 17.Profiles 18.Ringtones 19.WAP
738 static OnePhoneModel allmodels[] = {
740 /*1, 2, 3, 4, 5, 6 7 8 9 10 11 12 13 14 15 16 17 18 19 */
741 {"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}},
742 {"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}},
743 {"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}},
744 {"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}},
745 {"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}},
746 {"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}},
747 {"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}},
748 {"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}},
749 {"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}},
750 {"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}},
751 {"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}},
752 {"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}},
753 {"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}},
754 {"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}},
755 {"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}},
756 {"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}},
757 {"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 !
758 {"" ,"" ,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
761 static OnePhoneModel *GetPhoneModelData (const char *num)
765 while (allmodels[i].number != "") {
766 if (strcmp (num, allmodels[i].number) == 0) {
767 return (&allmodels[i]);
772 return (&allmodels[i]);
775 char *GetModelName ()
777 static char model[64];
779 while (GSM->GetModel(model) != GE_NONE) sleep(1);
781 return (GetPhoneModelData(model)->model);
784 int GetModelFeature (featnum_index num)
786 static char model[64];
788 while (GSM->GetModel(model) != GE_NONE) sleep(1);
790 return (GetPhoneModelData(model)->features[num]);
794 int LogAvailable=-1; //-1 not checked earlier, 0 not, 1 yes
797 bool AppendLog(u8 *buffer, int length,bool format)
803 struct CFG_Header *cfg_info;
806 if (LogAvailable==-1) {
810 cfg_info=CFG_FindGnokiirc();
811 if (cfg_info==NULL) return false;
813 LogFile = CFG_Get(cfg_info, "global", "logfile");
818 file=fopen(logfilename, "a+");
820 /* We have first entry in this session and too large file */
821 if (fread( buffer2, 1, 50000,file )==50000) {
823 file=fopen(logfilename, "w");
827 if (LogAvailable==1) {
828 file=fopen(logfilename, "a");
832 if (LogAvailable==1) {
833 for (i=0;i<length;i++) {
835 fprintf(file, "%02x",buffer[i]);
837 case 0x09:fprintf(file,_(" |"));break;
839 if (isprint(buffer[i])) fprintf(file, _("%c|"),buffer[i]);
840 else fprintf(file, _(" |"));
844 fprintf(file, "%c",buffer[i]);
847 if (format) fprintf(file, "\n");
851 return (LogAvailable==1);
854 bool AppendLogText(u8 *buffer,bool format)
856 return AppendLog(buffer,strlen(buffer),format);