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;
91 GSM_SpeedDial *CurrentSpeedDialEntry;
92 GSM_Error CurrentSpeedDialError;
95 unsigned char Current_IMEI[GSM_MAX_IMEI_LENGTH];
96 unsigned char Current_Revision[GSM_MAX_REVISION_LENGTH];
97 unsigned char Current_Model[GSM_MAX_MODEL_LENGTH];
100 GSM_SMSMessage *CurrentSMSMessage;
101 GSM_Error CurrentSMSMessageError;
102 int CurrentSMSPointer;
104 GSM_SMSFolders *CurrentSMSFolders;
105 GSM_Error CurrentSMSFoldersError;
106 int CurrentSMSFoldersCount;
108 GSM_OneSMSFolder CurrentSMSFolder;
109 GSM_Error CurrentSMSFolderError;
110 int CurrentSMSFolderID;
113 GSM_MemoryStatus *CurrentMemoryStatus;
114 GSM_Error CurrentMemoryStatusError;
117 GSM_NetworkInfo *CurrentNetworkInfo;
118 GSM_Error CurrentNetworkInfoError;
120 GSM_SMSStatus *CurrentSMSStatus;
121 GSM_Error CurrentSMSStatusError;
123 GSM_MessageCenter *CurrentMessageCenter;
124 GSM_Error CurrentMessageCenterError;
126 int *CurrentSecurityCodeStatus;
127 GSM_Error CurrentSecurityCodeError;
128 GSM_SecurityCode *CurrentSecurityCode;
130 GSM_DateTime *CurrentDateTime;
131 GSM_Error CurrentDateTimeError;
133 GSM_Error CurrentResetPhoneSettingsError;
135 GSM_DateTime *CurrentAlarm;
136 GSM_Error CurrentAlarmError;
138 GSM_CalendarNote *CurrentCalendarNote;
139 GSM_Error CurrentCalendarNoteError;
141 GSM_NotesInfo CurrentCalendarNotesInfo,*CurrentCalendarNotesInfo2;
142 GSM_Error CurrentCalendarNotesInfoError;
144 GSM_Error CurrentSetDateTimeError;
145 GSM_Error CurrentSetAlarmError;
147 int *CurrentFirstCalendarFreePos;
148 GSM_Error CurrentFirstCalendarFreePosError;
151 GSM_Error CurrentEnableExtendedCommandsError;
158 int CurrentDisplayStatus;
159 GSM_Error CurrentDisplayStatusError;
161 char *CurrentNetmonitor;
162 GSM_Error CurrentNetmonitorError;
164 GSM_Bitmap *CurrentGetBitmap=NULL;
165 GSM_Error CurrentGetBitmapError;
167 GSM_Error CurrentSetBitmapError;
169 GSM_Error CurrentSendDTMFError;
171 GSM_Profile *CurrentProfile;
172 GSM_Error CurrentProfileError;
174 GSM_Error CurrentDisplayOutputError;
176 GSM_CBMessage *CurrentCBMessage;
177 GSM_Error CurrentCBError;
179 int CurrentPressKeyEvent;
180 GSM_Error CurrentPressKeyError;
182 GSM_Error CurrentPlayToneError=GE_UNKNOWN;
185 GSM_Error CurrentDialVoiceError;
188 GSM_Error CurrentGetOperatorNameError;
189 GSM_Network *CurrentGetOperatorNameNetwork;
190 GSM_Error CurrentSetOperatorNameError;
193 GSM_Error CurrentGetIMEIError;
195 GSM_Error CurrentGetHWError;
198 unsigned char CurrentPPS[4];
199 GSM_Error CurrentProductProfileSettingsError;
201 char CurrentIncomingCall[20];
203 GSM_Error CurrentBinRingtoneError;
204 GSM_BinRingtone *CurrentGetBinRingtone=NULL;
206 GSM_Error CurrentRingtoneError;
209 GSM_Error CurrentMagicError;
212 GSM_Error CurrentSimlockInfoError;
213 GSM_AllSimlocks *CurrentSimLock;
215 GSM_Error CurrentGetWAPBookmarkError;
216 GSM_Error CurrentSetWAPBookmarkError;
217 GSM_WAPBookmark *WAPBookmark;
219 GSM_Error CurrentGetWAPSettingsError;
220 GSM_WAPSettings *WAPSettings;
222 GSM_Error CurrentCallDivertError;
223 GSM_CallDivert *CurrentCallDivert;
225 char *CurrentManufacturer;
228 /* This is the connection type used in gnokii. */
229 GSM_ConnectionType CurrentConnectionType;
231 /* Pointer to a callback function used to return changes to a calls status */
232 /* This saves unreliable polling */
233 void (*CurrentCallPassup)(char c);
235 /* Pointer to callback function in user code to be called when RLP frames
237 void (*CurrentRLP_RXCallback)(RLP_F96Frame *frame);
239 /* Used to disconnect the call */
240 u8 CurrentCallSequenceNumber;
244 bool CurrentRequestTerminate;
247 bool CurrentDisableKeepAlive;
253 bool CheckModel (GSM_Information InfoToCheck, char *model, GSM_ConnectionType connection) {
255 bool found_match=false;
257 if (strstr(InfoToCheck.FBUSModels, model) != NULL) {
258 if (connection==GCT_FBUS) found_match=true;
261 if (strstr(InfoToCheck.MBUSModels, model) != NULL) {
262 if (connection==GCT_MBUS) found_match=true;
264 if (strstr(InfoToCheck.InfraredModels, model) != NULL) {
265 if (connection==GCT_Infrared) found_match=true;
267 if (strstr(InfoToCheck.DLR3Models, model) != NULL) {
268 if (connection==GCT_DLR3) found_match=true;
270 if (strstr(InfoToCheck.IrdaModels, model) != NULL) {
271 if (connection==GCT_Irda) found_match=true;
273 if (strstr(InfoToCheck.ATModels, model) != NULL) {
274 if (connection==GCT_AT) found_match=true;
276 if (strstr(InfoToCheck.TekramModels, model) != NULL) {
277 if (connection==GCT_Tekram) found_match=true;
286 GSM_Error TryNewNokia(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame)) {
289 unsigned char init_char = N6110_SYNC_BYTE;
291 /* Hopefully is 64 larger as FB38_MAX* / N6110_MAX* */
294 if (Protocol->Initialise(device,initlength,connection,rlp_callback)!=GE_NONE)
296 return GE_NOTSUPPORTED;
299 if (connection!=GCT_MBUS) {
300 InitLength = atoi(initlength);
302 if ((strcmp(initlength, "default") == 0) || (InitLength == 0)) {
303 InitLength = 250; /* This is the usual value, lower may work. */
307 fprintf(stdout,_("Writing init chars...."));
310 /* Initialise link with phone or what have you */
311 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
313 for (count = 0; count < InitLength; count ++) {
315 Protocol->WritePhone(1,&init_char);
319 fprintf(stdout,_("Done\n"));
322 N6110_SendStatusRequest();
327 if (N6110_SendIDFrame()!=GE_NONE)
330 while (N6110_GetModel(phonemodel) != GE_NONE)
334 if (!strcmp(phonemodel,"NPE-3") || !strcmp(phonemodel,"NSE-5"))
338 /* Set pointers to relevant addresses */
339 GSM = &N7110_Functions;
340 GSM_Info = &N7110_Information;
341 GSM_LinkOK = &CurrentLinkOK;
350 extern GSM_Information N6110_Information;
351 extern GSM_Functions N6110_Functions;
353 GSM_Error GSM_Initialise(char *model, char *device, char *initlength, GSM_ConnectionType connection, void (*rlp_callback)(RLP_F96Frame *frame), char* SynchronizeTime)
355 bool found_match=false;
357 GSM_ConnectionType connection2;
366 connection2=connection;
368 CurrentRLP_RXCallback = rlp_callback;
369 CurrentCallPassup=NULL;
370 CurrentPhonebookEntry=NULL;
372 CurrentNetworkInfo = NULL;
373 CurrentGetBitmap=NULL;
374 CurrentPlayToneError=GE_UNKNOWN;
375 strcpy(CurrentIncomingCall," ");
376 CurrentGetBinRingtone=NULL;
377 CurrentNetworkInfo=NULL;
379 CurrentRequestTerminate=false;
381 CurrentDisableKeepAlive=false;
382 CurrentCalendarNotesInfo.HowMany=2000;
384 CurrentMagicError = GE_BUSY;
387 if (!strcmp(model,"auto")) {
390 GSM = &N6110_Functions;
391 GSM_Info = &N6110_Information;
392 GSM_LinkOK = &CurrentLinkOK;
394 fprintf(stdout,_("Trying FBUS for new Nokia phones...\n"));
397 Protocol = &FBUS_Functions;
398 CurrentConnectionType=GCT_FBUS;
399 connection2=GCT_FBUS;
400 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
411 GSM = &N6110_Functions;
412 GSM_Info = &N6110_Information;
413 GSM_LinkOK = &CurrentLinkOK;
415 fprintf(stdout,_("Trying DLR3 for new Nokia phones...\n"));
418 Protocol = &FBUS_Functions;
419 CurrentConnectionType=GCT_DLR3;
420 connection2=GCT_DLR3;
421 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
433 GSM = &N6110_Functions;
434 GSM_Info = &N6110_Information;
435 GSM_LinkOK = &CurrentLinkOK;
437 fprintf(stdout,_("Trying MBUS for new Nokia phones...\n"));
440 Protocol = &MBUS_Functions;
441 CurrentConnectionType=GCT_MBUS;
442 connection2=GCT_MBUS;
444 if (TryNewNokia(model,device,initlength,CurrentConnectionType,rlp_callback)==GE_NONE)
454 if (!found_match) return GE_NOTSUPPORTED;
463 if (CheckModel (Nsniff_Information, model, connection)) {
464 /* Set pointers to relevant addresses */
465 GSM = &Nsniff_Functions;
466 GSM_Info = &Nsniff_Information;
467 GSM_LinkOK = &CurrentLinkOK;
473 if (CheckModel (N6110_Information, model, connection)) {
474 /* Set pointers to relevant addresses */
475 GSM = &N6110_Functions;
476 GSM_Info = &N6110_Information;
477 GSM_LinkOK = &CurrentLinkOK;
481 if (CheckModel (N7110_Information, model, connection)) {
482 /* Set pointers to relevant addresses */
483 GSM = &N7110_Functions;
484 GSM_Info = &N7110_Information;
485 GSM_LinkOK = &CurrentLinkOK;
488 if (CheckModel (Nat_Information, model, connection)) {
489 /* Set pointers to relevant addresses */
490 GSM = &Nat_Functions;
491 GSM_Info = &Nat_Information;
492 GSM_LinkOK = &CurrentLinkOK;
498 switch (connection) {
499 case GCT_FBUS : Protocol = &FBUS_Functions; break;
501 case GCT_Infrared: Protocol = &FBUS_Functions; break;
502 case GCT_Tekram : Protocol = &FBUS_Functions; break;
503 case GCT_DLR3 : Protocol = &FBUS_Functions; break;
504 case GCT_MBUS : Protocol = &MBUS_Functions; break;
505 case GCT_Irda : Protocol = &FBUSIRDA_Functions;break;
506 case GCT_AT : Protocol = &AT_Functions; break;
507 case GCT_Default : Protocol = NULL; break;
511 return GE_NOTSUPPORTED;
515 /* Now call model specific initialisation code. */
516 error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
519 /* RTH: FIXME: second try for Irda (6210 only?)*/
520 if ( error!=GE_NONE && connection == GCT_Irda)
523 fprintf(stdout,"Irda connection: second try!\n");
526 error=(GSM->Initialise(device, initlength, connection2, rlp_callback));
531 if (error==GE_NONE && !strcmp(SynchronizeTime,"yes"))
534 now=localtime(&nowh);
536 Date.Year = now->tm_year;
537 Date.Month = now->tm_mon+1;
538 Date.Day = now->tm_mday;
539 Date.Hour = now->tm_hour;
540 Date.Minute = now->tm_min;
541 Date.Second = now->tm_sec;
546 /* Well, this thing is copyrighted in U.S. This technique is known as
547 Windowing and you can read something about it in LinuxWeekly News:
548 http://lwn.net/1999/features/Windowing.phtml. This thing is beeing
549 written in Czech republic and Poland where algorithms are not allowed
553 Date.Year = Date.Year+1900;
555 Date.Year = Date.Year+2000;
558 /* FIXME: Error checking should be here. */
559 GSM->SetDateTime(&Date);
568 GSM_Error Unimplemented(void)
570 return GE_NOTIMPLEMENTED;
573 GSM_Error NotSupported(void)
575 return GE_NOTSUPPORTED;
580 /* Applications should call N6110_Terminate to shut down the N6110 thread and
581 close the serial port. */
582 void NULL_Terminate(void)
584 Protocol->Terminate();
588 /* Here are things made for keeping connecting */
589 void NULL_KeepAlive()
593 /* Here are things made for keeping connecting */
594 void NULL_KeepAlive()
600 void NULL_TX_DisplayMessage(u16 MessageLength, u8 *MessageBuffer)
602 fprintf(stdout, _("PC: "));
604 txhexdump(MessageLength,MessageBuffer);
608 bool NULL_WritePhone (u16 length, u8 *buffer) {
609 if (device_write(buffer,length)!=length) return false;
613 GSM_Error NULL_WaitUntil (int time, GSM_Error *value)
619 /* Wait for timeout or other error. */
620 while (timeout != 0 && *value == GE_BUSY ) {
631 GSM_Error NULL_SendMessageSequence (int time, GSM_Error *value,
632 u16 message_length, u8 message_type, u8 *buffer)
636 Protocol->SendMessage(message_length, message_type, buffer);
638 return NULL_WaitUntil (time, value);
641 GSM_ConnectionType GetConnectionTypeFromString(char *Connection) {
643 GSM_ConnectionType connection=GCT_FBUS;
646 if (!strcmp(Connection, "irda")) connection=GCT_Irda;
647 if (!strcmp(Connection, "infrared")) connection=GCT_Infrared;
648 if (!strcmp(Connection, "mbus")) connection=GCT_MBUS;
649 if (!strcmp(Connection, "dlr3")) connection=GCT_DLR3;
650 if (!strcmp(Connection, "at")) connection=GCT_AT;
651 if (!strcmp(Connection, "tekram210"))connection=GCT_Tekram;
657 bool GetMemoryTypeString(char *memorytext, GSM_MemoryType *type)
666 GSM_MTStrings mystring[] = {
680 while (strcmp(mystring[i].name,"undefined")) {
681 if (*type==mystring[i].type) {
682 strcpy(memorytext,mystring[i].name);
690 bool GetMemoryTypeID(char *memorytext, GSM_MemoryType *type)
699 GSM_MTStrings mystring[] = {
713 while (strcmp(mystring[i].name,"undefined")) {
714 if (strcmp(mystring[i].name,memorytext)==0) {
715 *type=mystring[i].type;
724 char *GetMygnokiiVersion() {
726 static char Buffer[1000]="";
728 sprintf(Buffer, "%s",VERSION);
734 1.Name,2.CodeName,3.Calendar,4.Netmonitor,5.Caller groups,6.Phonebook,
735 7.Authentication 8.Datacalls 9.KeysPressing 10.SMSC Default Recipient
736 11.SpeedDials 12.ScreenSavers 13.DTMF 14.SMS 15.NoPowerFrame 16.StartUpLogo
737 17.Profiles 18.Ringtones 19.WAP
740 static OnePhoneModel allmodels[] = {
742 /*1, 2, 3, 4, 5, 6 7 8 9 10 11 12 13 14 15 16 17 18 19 */
743 {"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}},
744 {"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}},
745 {"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}},
746 {"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}},
747 {"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}},
748 {"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}},
749 {"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}},
750 {"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}},
751 {"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}},
752 {"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}},
753 {"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}},
754 {"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}},
755 {"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}},
756 {"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}},
757 {"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}},
758 {"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}},
759 {"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 !
760 {"" ,"" ,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
763 static OnePhoneModel *GetPhoneModelData (const char *num)
767 while (allmodels[i].number != "") {
768 if (strcmp (num, allmodels[i].number) == 0) {
769 return (&allmodels[i]);
774 return (&allmodels[i]);
777 char *GetModelName ()
779 static char model[64];
781 while (GSM->GetModel(model) != GE_NONE) sleep(1);
783 return (GetPhoneModelData(model)->model);
786 int GetModelFeature (featnum_index num)
788 static char model[64];
790 while (GSM->GetModel(model) != GE_NONE) sleep(1);
792 return (GetPhoneModelData(model)->features[num]);
796 int LogAvailable=-1; //-1 not checked earlier, 0 not, 1 yes
799 bool AppendLog(u8 *buffer, int length,bool format)
805 struct CFG_Header *cfg_info;
808 if (LogAvailable==-1) {
812 cfg_info=CFG_FindGnokiirc();
813 if (cfg_info==NULL) return false;
815 LogFile = CFG_Get(cfg_info, "global", "logfile");
820 file=fopen(logfilename, "a+");
822 /* We have first entry in this session and too large file */
823 if (fread( buffer2, 1, 50000,file )==50000) {
825 file=fopen(logfilename, "w");
829 if (LogAvailable==1) {
830 file=fopen(logfilename, "a");
834 if (LogAvailable==1) {
835 for (i=0;i<length;i++) {
837 fprintf(file, "%02x",buffer[i]);
839 case 0x09:fprintf(file,_(" |"));break;
841 if (isprint(buffer[i])) fprintf(file, _("%c|"),buffer[i]);
842 else fprintf(file, _(" |"));
846 fprintf(file, "%c",buffer[i]);
849 if (format) fprintf(file, "\n");
853 return (LogAvailable==1);
856 bool AppendLogText(u8 *buffer,bool format)
858 return AppendLog(buffer,strlen(buffer),format);