Re: Fbus Version 1/ nokia 3310/ hardware & software request

LeBomb <[email protected]> Wed, 7 Aug 2013 22:44:16 +0200
Newsgroups gmane.linux.drivers.gnokii
Message-ID <CAOX7+HJjdcWZi81M2izmPvkq7PtaQ3k0YDEjs5Y9OEHYAa3C+A@mail.gmail.com>
Hi Mehdi,
thanks to some source code found in gnokki file, i wrote my own driver for
my atmega128 and my nokia 3310.
I send you the source code.
There is only the function to send SMS and to monitor the network.

Best regards,
Olivier.


2013/8/6 Lauters Mehdi <[email protected]>

> Hi everyone,
>
> I spent long time trying to connect my Nokia 3310 to an arduino, (and a
> computer) without success.
> I found mainly 3 sources of documentations which are
>
>
>    - http://www.embedtronics.com/nokia/fbus.html
>    -
>    http://git.savannah.gnu.org/cgit/gnokii.git/tree/Docs/protocol/nokia.txt
>    -
>    http://www.insidegadgets.com/2013/01/12/how-to-use-nokia-f-bus-to-send-an-sms-message/#comment-81129
>
>
> *and I found your email on the gnokii file*.
>
> Actually, I don't understand when to use FBus version 1 or version 2.
> On internet, almost all documentation is talking about version 2 but my
> phone seems to not be agree with that: it sometimes answer, sometimes not,
> and what it answer seems not te follow the fbus version 2 protocol because
> I'm not able to decode it with http://www.embedtronics.com/nokia/fbus.html
> And the gnokii file says that the used protocol should be FBUS version
> 1/MBUS version 1
>
> So I'm trying to send it a HW and SW request, but in version 1 of the FBus
> protocol as described on the gnokii project
>
> Frame format for FBUS version 1:
>
>     { FrameID, FrameLength, MsgType, SeqNo, {block}, ChkSum }
>
>          where FrameID:         0x01 Command frame from computer to Nokia
>                                 0x02 ??? - Data call frame from computer to Nokia - ???
>                                 0x03 Data call frame from Nokia to computer
>                                 0x04 Command frame from Nokia to computer
>                FrameLength:     {block} + 2
>                MsgType:         see List
>                SeqNo:           Sequence number of command in case where direction is
>                                 from ME to computer, the sequence number is
>                                 counting from 0x30 to 0x37 and resetting back to 0x30.
> 				Also seqnos 0x00 to 0x07 have been spotted on some
> 				3110s (but not all, maybe different firmware revs?).
>                                 When direction is from computer to ME,
>                                 sequence number counts from 0x08 to 0x0f and resets back to 0x08.
>                                 It may not be required to be this way.
>                                 Sequence numbers are used in acknowledging commands.
>                ChkSum1:         CRC = 0;
>                                 for (i = 0; i < (2 + CMD_LEN); i++)
>                                   CRC ^= frame[i];
>
> I cannot found any documentation about it so i wanted to know what is exactly the {block} in the frame and the CMD_LEN in the crc computation.
>
> From what I understood, block is needed by only few commands, so it is inexistant for example for the SW & HW request,
> and CMD_LEN is the size between byte 0 and the byte MsgType (included).
>
> Moreover, I found on the nokia3310 file
> 0x4c:
>     s Get phone info        {}
> 0x4d:
>     r Get phone info        {+IMEI, 0x00, Code, 0x00, HW, 0x00 }
>                             where IMEI: IMEI Code
>                                   CODE: Same as Code in phones back side
>                                   HW: hardware version
>
> but here also, there as things I am not sure:
>
> the {} is it corresponding to the block frame section? Has it to be set to 0x0 when empty?
>
> fields within them are there always outputs, inputs? depends?
>
> From all I understood, I sent to my phone the following request (after FBus initialisation, of course) to get its version:
>
>
>
> FrameID FrameLength getPhoneInfo   SeqNo  cheksum
>    0x1      0x2         0x4C       0x0    0x4F
>
>
> But the problem, is that... I'm still waiting its answer...
>
> I will be glad if you could give me any advice, or at least any answer
>
> Thanks,
>
>
> Regards,
>
> Mehdi
>
>
> _______________________________________________
> gnokii-users mailing list
> [email protected]
> https://lists.nongnu.org/mailman/listinfo/gnokii-users
>
>

_______________________________________________
gnokii-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/gnokii-users
gsm.c (text/x-csrc, 11 KB)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/thread.h>
#include <sys/timer.h>

#include "../config.h"
#include "uart.h"
#include "gsm.h"

#define NOKIA_3310_HWSWV   0xD1
#define NOKIA_3310_NETW    0x0A
#define NOKIA_3310_SMSSEND 0x02
#define NOKIA_3310_ACK     0x7F

extern int gsm_form(FILE * stream, REQUEST * req);

void fbus_sync(void)
{
  uint8_t i = 0;
  char sync_w = 0x55;

  for(i=0; i<128; i++) { fwrite(&sync_w, 1, 1, uart1_fd); } fflush(uart1_fd);
}

uint8_t fbus_header(uint8_t *frame, uint8_t cmd, uint16_t data_len)
{
  /* Check the frame pointer */
  if(NULL == frame) { return 1; }
  /* Cable link */
  frame[0] = 0x1E;
  /* Destination device (cell phone) */
  frame[1] = 0x00;
  /* Source device (PC) */
  frame[2] = 0x0C;
  /* Command */
  frame[3] = cmd;
  /* Length (16 bits) = data length + sequence number */
  frame[4] = (data_len+1) / 256;
  frame[5] = (data_len+1) % 256;
  return 0;
}

uint16_t fbus_frame_len(uint16_t data_len)
{
  /* Header + data length + sequence number + 1 if length is odd + checksum */
  return (6 + data_len + 1 + ((data_len+1)%2) + 2);
}

uint8_t fbus_trailer(uint8_t * frame, uint8_t seq)
{
  uint16_t i = 0;
  uint16_t pos = 0;

  /* Check the frame pointer */
  if(NULL == frame) { return 1; }
  /* Get the length from the frame */
  pos = frame[4]; pos = pos << 8; pos += frame[5];
  /* Add header */
  pos = 5 + pos;
  /* Set the sequence number */
  frame[pos] = seq; pos++;
  /* Set the padding byte if necessary */
  if((pos%2)==1) { frame[pos]=0; pos++; }
  /* Compute the checksum on even data number */
  frame[pos] = 0; for(i=0; i<pos; i=i+2) { frame[pos] = frame[pos]^frame[i]; } pos++;
  /* Compute the checksum on odd data number */
  frame[pos] = 0; for(i=1; i<pos; i=i+2) { frame[pos] = frame[pos]^frame[i]; }

  return 0;
}

uint8_t fbus_send(uint8_t cmd, uint16_t data_len, uint8_t *data, uint8_t seq)
{
  uint8_t *frame = NULL;

  /* Check the data pointer to send */
  if(NULL == data) { return 1; }
  /* Allocate the frame buffer */
  frame = malloc(fbus_frame_len(data_len));
  /* Check the frame pointer */
  if(NULL == frame) { return 2; }
  /* Build the frame header */
  fbus_header(frame, cmd, data_len);
  /* Copy the data in the frame buffer */
  memcpy(&frame[6], data, data_len);
  /* Build the frame trailer */
  fbus_trailer(frame, seq);
  /* Send the frame to the cell phone */
  fwrite(frame, fbus_frame_len(data_len), 1, uart1_fd); fflush(uart1_fd);
  /* Free the frame buffer */
  free(frame);

  return 0;
}

uint8_t fbus_receive(uint8_t *cmd, uint16_t *data_len, uint8_t **data, uint8_t *seq)
{
  uint16_t buff_len = 0;
  uint16_t i = 0;
  uint8_t xor1 = 0;
  uint8_t xor2 = 0;
  int ret = 0;

  if(0x1E != fgetc(uart1_fd)) { /*printf("ERROR header0\n");*/ return 1; }
  if(0x0C != fgetc(uart1_fd)) { /*printf("ERROR header1\n");*/ return 2; }
  if(0x00 != fgetc(uart1_fd)) { /*printf("ERROR header2\n");*/ return 3; }

  ret = fgetc(uart1_fd); if(0>ret) { /*printf("ERROR data lenH\n");*/ return 4; }
  *cmd = ret;

  ret = fgetc(uart1_fd); if(0>ret) { /*printf("ERROR data lenH\n");*/ return 5; }
  *data_len = (((ret)&0x00FF)<<8);
  ret = fgetc(uart1_fd); if(0>ret) { /*printf("ERROR data lenL\n");*/ return 6; }
  *data_len = *data_len + ret;
  if(1>*data_len) { /*printf("ERROR data len\n");*/ return 7; }
  *data_len = (*data_len) - 1;

  buff_len = (*data_len) + ((*data_len)+1)%2 + 1 + 2;
  *data = malloc(buff_len);
  if(NULL == *data) { /*printf("ERROR malloc\n");*/ return 8; }

  for(i=0; i<buff_len; i++)
  {
    ret = fgetc(uart1_fd);
    if(0>ret) { /*printf("ERROR data\n");*/ free(*data); *data=NULL; return 9; }
    else { (*data)[i] = ret; }
  }

  *seq = (*data)[*data_len];

  /* Compute the checksum on even data number */
  xor1 = 0x1E^0x00^((((*data_len)+1)>>8)&0x00FF); for(i=0; i<(buff_len-2); i=i+2) { xor1 = xor1^(*data)[i]; }
  if(xor1 != (*data)[buff_len-2]) { /*printf("ERROR xor1\n");*/ free(*data); *data=NULL; return 10; }
  /* Compute the checksum on odd data number */
  xor2 = 0x0C^(*cmd)^(((*data_len)+1)&0x00FF); for(i=1; i<(buff_len-2); i=i+2) { xor2 = xor2^(*data)[i]; }
  if(xor2 != (*data)[buff_len-1]) { /*printf("ERROR xor2\n");*/ free(*data); *data=NULL; return 11; }

  return 0;
}

uint8_t fbus_receive_ack(uint8_t _cmd)
{
  uint8_t cmd = 0;
  uint16_t data_len = 0;
  uint8_t *data = NULL;
  uint8_t seq = 0;

  if(0 != fbus_receive(&cmd, &data_len, &data, &seq)) { /*printf("ERROR receive\n");*/ return 1; }
  if(NOKIA_3310_ACK != cmd) { free(data); /*printf("ERROR ack\n");*/ return 2; }
  if(1 != data_len) { free(data); /*printf("ERROR ack len\n");*/ return 3; }
  if(data[0] != _cmd) { free(data); /*printf("ERROR ack cmd\n");*/ return 4; }
//if(seq != 0x00) { free(data); /*printf("ERROR ack seq\n");*/ return 5; }
  free(data);
  return 0;
}

uint8_t gsm_init(void)
{
  return 0;
}

/*
uchar getver[] =   {0xd1,0x05,0x00,0x01,0x00,0x03,0x00};
uchar getsmsc[]=   {0x02,0x06,0x00,0x01,0x00,0x33,0x64,0x01};
uchar getimei[]=   {0x1b,0x04,0x00,0x01,0x00,0x01};
uchar getbatt[]=   {0x17,0x04,0x00,0x01,0x00,0x02};
uchar getrf[]  =   {0x0a,0x04,0x00,0x01,0x00,0x81};
uchar getnetwork[]={0x0a,0x04,0x00,0x01,0x00,0x70};
*/

uint8_t gsm_status_get(void)
{
  uint8_t data[5] = {0x00, 0x01, 0x00, 0x70, 0x01};
  uint8_t cmd = 0;
  uint16_t data_len = 0;
  uint8_t * data_recv = NULL;
  uint8_t seq = 0;
  uint8_t ret = 0;

  /* Purge the receiving buffer of all previous data */
  fpurge(uart1_fd);
  /* Synchronize the phone for the start of FBUS exchange */
  fbus_sync();

  ret = fbus_send(NOKIA_3310_NETW, 5, data, 0x60);
  if(0 != ret) { return (10+ret); }
// 1E 00 0C 0A 00 06 00 01 00 70 01 60 13 1D

  ret = fbus_receive_ack(NOKIA_3310_NETW);
  if(0 != ret) { return (20+ret); }
// 1E 0C 00 7F 00 02 0A 00 14 71

  ret = fbus_receive(&cmd, &data_len, &data_recv, &seq);
  if(0 != ret) { return (30+ret); }
// 0x0071, ?,?,?,length,netstatus,netsel,cellIDH,cellIDL,lacH,lacL,netcode,netcode,netcode
// 1E 0C 00 0A 00 15 01 08 00 71 01 00 01 0B 01 02 0C 97 1D 4D 02 F8 01 00 00 01 47 00 4B 40
  if(NULL == data_recv) { return 1; }
  /* Check the received data */
  ret = 0;
  if(NOKIA_3310_NETW != cmd) { ret = 2; }
  if(20 != data_len)         { ret = 3; }
  if((0x01 != data_recv[8]) && (0x02 != data_recv[8]))   { ret = 4; } // Home Network
  if(0x02 != data_recv[9])   { ret = 5; } // Automatic Network selection

  free(data_recv);
  if(0 != ret) { return ret; }

  data[0] = NOKIA_3310_NETW;
  ret = fbus_send(NOKIA_3310_ACK, 1, data, 0x01);
  if(0 != ret) { return (40+ret); }

  return 0;
}

uint8_t gsm_version_get(void)
{
  uint8_t data[6] = {0, 1, 0, 3, 0, 1};
  uint8_t cmd = 0;
  uint16_t data_len = 0;
  uint8_t * data_recv = NULL;
  uint8_t seq = 0;

  /* Purge the receiving buffer of all previous data */
  fpurge(uart1_fd);
  /* Synchronize the phone for the start of FBUS exchange */
  fbus_sync();

  if(0 != fbus_send(NOKIA_3310_HWSWV, 6, data, 0x60)) { return 1; }
// 1E 00 0C D1 00 07 00 01 00 03 00 01 60 00 72 D5

  if(0 != fbus_receive_ack(NOKIA_3310_HWSWV)) { return 2; }
// 1E 0C 00 7F 00 02 D1 00 CF 71

  if(0 != fbus_receive(&cmd, &data_len, &data_recv, &seq)) { return 3; }
// NOKIA 3310 : 1E 0C 00 D2 00 26 01 00 00 03 56 20 30 34 2E 33 35 0A 32 39 2D 30 33 2D 30 31 0A 4E 48 4D 2D 35 0A 28 63 29 20 4E 4D 50 2E 00 01 42 3A A8
// NOKIA 3330 : 1E 0C 00 D2 00 26 01 00 00 03 56 20 30 34 2E 35 30 0A 31 32 2D 31 30 2D 30 31 0A 4E 48 4D 2D 36 0A 28 63 29 20 4E 4D 50 2E 00 01 XX XX XX
  if(NULL != data_recv)
  {
    free(data_recv);
    if((NOKIA_3310_HWSWV+1) != cmd) { return 4; }
    if(37 != data_len) { return 5; }
  }
  else { return 6; }

  data[0] = NOKIA_3310_HWSWV;
  if(0 != fbus_send(NOKIA_3310_ACK, 1, data, 0x01)) { return 7; }
// 1E 00 0C 7F 00 02 D2 01 C0 7C

  return 0;
}

uint8_t gsm_sms_send_with_tel(char * tel, char * msg)
{
  uint16_t up_msg_len = 0;
  uint16_t p_msg_len = 0;
  uint8_t *frame = NULL;
  unsigned int i = 0;
  unsigned int j = 0;
  uint16_t pos = 0;

  uint8_t sms_header[8] = {0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x07, 0x91};
#ifdef LOST_GSM_SMS_CENTER_SFR
  uint8_t sms_tel_center[10] = {0x33, 0x06, 0x09, 0x10, 0x93, 0xF0, 0x00, 0x00, 0x00, 0x00};
#endif
#ifdef LOST_GSM_SMS_CENTER_FREE
  uint8_t sms_tel_center[10] = {0x33, 0x96, 0x05, 0x00, 0x96, 0xF5, 0x00, 0x00, 0x00, 0x00};
#endif
#ifdef LOST_GSM_SMS_CENTER_ORANGE
  uint8_t sms_tel_center[10] = {0x33, 0x86, 0x09, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00};
#endif
  /* SMS Center
   * SFR    : +33 6 09 00 13 90
   * FREE   : +33 6 95 00 06 95
   * ORANGE : +33 6 89 00 40 00
   */
  uint8_t sms_body[7] = {0x15, 0x00, 0x00, 0x00, 0x33, 0x0A, 0xA1};
  uint8_t sms_trailer[7] = {0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

//uint8_t sms_msg[46] = {0xC8, 0x34, 0x28, 0xC8, 0x66, 0xBB, 0x40, 0x54, 0x74, 0x7A, 0x0E, 0x6A, 0x97, 0xE7, 0xF3, 0xF0, 0xB9, 0x0C, 0xBA, 0x87, 0xE7, 0xA0, 0x79, 0xD9, 0x4D, 0x07, 0xD1, 0xD1, 0xF2, 0x77, 0xFD, 0x8C, 0x06, 0x19, 0x5B, 0xC2, 0xFA, 0xDC, 0x05, 0x1A, 0xBE, 0xDF, 0xEC, 0x50, 0x08, 0x01};
// Hi All. This message was sent through F-Bus. Cool!!

  /* Check the phone number */
  if(10 != strnlen(tel, 10)) { /*printf ("TEL bad len\n");*/ return 1; }
  /* Get the message length */
  up_msg_len = strnlen(msg, 160);
  /* Force end of message */
  msg[up_msg_len] = '\0';
  /* Calculate packed message lenght */
  p_msg_len = (up_msg_len*7)/8 + 1;
  /* Alloc the frame buffer */
  frame = malloc(fbus_frame_len(8+10+7+10+7+p_msg_len+1));
  /* Check the frame pointer */
  if(NULL == frame) { return 2; }
  /* Build the frame header */
  fbus_header(frame, NOKIA_3310_SMSSEND, 8+10+7+10+7+p_msg_len+1);
  /* Build the data frame header */
  memcpy(&frame[6], &sms_header[0], 8);
  /* Build the SMS center phone number */
  memcpy(&frame[6+8], &sms_tel_center[0], 10);
  /* Build the data frame body */
  memcpy(&frame[6+8+10], &sms_body[0], 7);
  /* Overwrite the message lenght */
  frame[6+8+10+4] = up_msg_len;
  /* Build the destination phone number */
  j=0; for(i=0; i<5; i++) { frame[6+8+10+7+i] = ((tel[j]-'0')&0x0F) + (((tel[j+1]-'0')<<4)&0xF0); j=j+2; }
  /* Build the data frame trailer */
  memcpy(&frame[6+8+10+7+10], &sms_trailer[0], 7);

  /* Copy the data in the frame buffer */
  for(i=0; i<p_msg_len; i++)
  {
    frame[6+8+10+7+10+7+i] = 0;
    for(j=0; j<8; j++) { pos = i*8+j; frame[6+8+10+7+10+7+i] = frame[6+8+10+7+10+7+i] | ((msg[pos/7]>>(pos%7))<<j); }
  }
  frame[6+8+10+7+10+7+p_msg_len]=0x01;
  /* Build the frame trailer */
  fbus_trailer(frame, 0x60);

  /* Send the frame to the cell phone */
  fpurge(uart1_fd);
  fbus_sync();
  fwrite(frame, fbus_frame_len(8+10+7+10+7+p_msg_len+1), 1, uart1_fd); fflush(uart1_fd);
//fwrite(frame, fbus_frame_len(8+10+7+10+7+p_msg_len+1), 1, stdout); fflush(stdout);
  /* Free the frame buffer */
  free(frame);
// 1E 0C 00 7F 00 02 02 00 1C 71
// 1E 0C 00 02 00 09 01 08 00 02 64 95 00 01 40 00 3B 99
// 1E 00 0C 7F 00 02 02 04 10 79

  return 0;
}

uint8_t gsm_sms_send(char * msg)
{
  uint8_t ret1 = 0;
  uint8_t ret2 = 0;

  ret1 = gsm_sms_send_with_tel(LOST_GSM1, msg);
  NutSleep(2000);
  ret2 = gsm_sms_send_with_tel(LOST_GSM2, msg);

  return (ret1 + ret2);
}

char* gsm_sms_receive(void)
{
  return NULL;
}