Getting Started with Sim900

Peter Wood in sim900
27 Oct 2014, 14:43

Hi there!

Today we are going to get a closer look at Sim900 radio module.

So here we are with a board with Sim900 radio module, where the main contacts have already been withdrawn into the contact area for SIM card. Also, serial interface connections, as well as outlets for microphone and linear output, are available.

tumblr_inline_ne4312j0NE1sit1v2

We also have USB2UART controller. Note that drivers installation procedure on Mac OS X for various controllers may differ, so take this fact into account when choosing a controller type.

To make sure that the drivers are installed, type in the Terminal:

ls /dev/tty.*

Next we have to find our device. Here’s what our device looks like:

/dev/tty.PL2303-00001014

Connect contacts. Rx/Tx voltage of UART signals is 3.3V, which permits to connect contacts to the board directly. 5V power supply is provided by UART as well. Thus, we are using all the UART contacts: Rx/Tx, +5V and GND.

tumblr_inline_ne430y0H3d1sit1v2

Sim900 module by default requires 115200 bit/s connection speed, 8 bits per symbol and 1 stop bit. All other options should be disabled.

UART is rather simple serial interface, even simpler than Serial Com port, but we can use the same components for work with it, limited only by the data exchange on the specified transfer speed.

OS X lets us work with serial port via tеrmios, which is the part of POSIX. All we have to do is tune port settings and try to transfer data.

For data exchange we’ll use Swift programming language. Here’s how setting port options looks like:

 func openWithDevicePath(devicePath:String, error:NSErrorPointer?) -> Bool      {          let d : Int32 = open(devicePath, O_RDWR | O_NOCTTY | O_NDELAY)          if  d == -1          {              if let err = error              {                  err.memory = NSError(domain: "could not open device", code: -1, userInfo: nil)              }                            return false          }                    var tty = UnsafeMutablePointer.alloc(1)                    if tcgetattr(d, tty) != 0          {              close(d)                            if let err = error              {                  err.memory = NSError(domain: "tcgetattr failed", code: -1, userInfo: nil)              }                            return false          }                    if cfsetospeed (tty, 115200) == -1          {              close(d)                            if let err = error              {                  err.memory = NSError(domain: "cfsetospeed failed", code: -1, userInfo: nil)              }                            return false          }                    if cfsetispeed (tty, 115200) == -1          {              close(d)                            if let err = error              {                  err.memory = NSError(domain: "cfsetispeed failed", code: -1, userInfo: nil)              }                            return false          }                    tty.memory.c_cflag = (tty.memory.c_cflag & ~UInt(CSIZE)) | UInt(CS8);   // 8-bit chars                    tty.memory.c_iflag = ~UInt(IGNBRK)                                      // ignore break processing          tty.memory.c_lflag = 0                                                  // no signaling chars, no echo,          tty.memory.c_oflag = 0                                                  // no remapping, no delays                    tty.memory.c_iflag &= ~(UInt(IXON) | UInt(IXOFF) | UInt(IXANY))         // shut off xon/xoff ctrl          tty.memory.c_cflag |= (UInt(CLOCAL) | UInt(CREAD))                      // ignore modem controls,          tty.memory.c_cflag &= ~(UInt(PARENB) | UInt(PARODD))                    // shut off parity          tty.memory.c_cflag |= 0          tty.memory.c_cflag &= ~UInt(CSTOPB)                                     // One stop bit          tty.memory.c_cflag &= ~((UInt(CCTS_OFLOW) | UInt(CRTS_IFLOW)))          // Disable RTS/CTS                    if tcsetattr (d, TCSANOW, tty) != 0          {              close(d)                            if let err = error              {                  err.memory = NSError(domain: "cfsetispeed failed", code: -1, userInfo: nil)              }                            return false          }                    sim900descriptor = d                    return true      }  

The function should be always called before starting work with Sim900. The data is sent and received via read and write functions, that’s why the command execution will be realized via timer. Receiving data from the device is similar to the work of Terminal. In the next posts we’ll give a closer examination of Pooling mode, where the data is received.

So let’s execute a simple command to test connection to the module – “AT”.
main function in Swift looks like:

var error : NSError?  let sim900descriptor = sim900DescriptorWithDevicePath("/dev/tty.PL2303-00001014", &error)  if sim900descriptor == -1  {      if let e = error      {          println("Error: \(e.localizedDescription)")      }            exit(1)  }    let cmd = "AT\r\n"    write(sim900descriptor, cmd, UInt(countElements(cmd)))    sleep(2)    var buffer = UnsafeMutablePointer.alloc(Int(128))  memset(buffer, 0, 128)    let bitesReaded = read(sim900descriptor, buffer, 127)    if let response = String.fromCString(buffer)  {      println("Response: \(response)")  }  

Data is transferred via write call, as you’ve probably noticed.
If OK is returned, data transfer settings are correct.
Here’s a sample which allows sending an SMS message and making an outgoing call. Let’s describe two simple commands.

We are going to dial a telephone number, so we need to pass a command in “ATD;” format, which has the following look:

   func dialNumber(phoneNumber:String)      {          let dialCmd = "ATD\(phoneNumber);\r\n"                    write(sim900descriptor, dialCmd, UInt(countElements(dialCmd)))      }  

Making a call is that easy. Sending an SMS message is a little harder and may remind you sending POST request to the Internet. Once the command is received, the module will wait for the body of the letter and 1A symbol.

To do this, we’ll use command of “AT+CMGS=” format. Once it is sent, send the body of the message with 0x1A symbol in the end, in case the module didn’t return an error.

Look, that’s dead simple:

    func sendMessage(message:String, toNumber:String)      {                  let smsCmd = "AT+CMGS=\"\(toNumber)\"\r\n"                    write(sim900descriptor, smsCmd, UInt(countElements(smsCmd)))                    sleep(1);                    write(sim900descriptor, message, UInt(countElements(message)))                            write (sim900descriptor, UnsafePointer([0x1A] as Array), 1);      }  

We use read function to get all the data during application work:

   func availableData() -> String?      {          var buffer = UnsafeMutablePointer.alloc(Int(128))          memset(buffer, 0, 128)                    let bitesReaded = read(sim900descriptor, buffer, 127)                    if bitesReaded > 0          {              return String.fromCString(buffer)          }                    return nil      }  

tumblr_inline_ne5km68PAo1sit1v2

You can download xcode project of the test application from this post here: sim900_practice