Hi there,
I have been playing with an AD8066 (and Sparkfun’s associated breakout) connected to a computer, using C# and the .net serialPort class for control.
I have no issues with receiving messages through this, however the escape sequence for sending sms messages does not seem to work. AT commands are fine, and the code I was using to send was working on a nokia phone not long ago.
Using text mode (and the instructions in http://www.sparkfun.com/datasheets/Cell … -guide.pdf) I don’t seem to be able to send ctrl + z correctly. Have tried sending (char)26, and a bunch of other tricks with no success.
This is the message sending code:
//Function to send sms messages with raw input.
public bool SendMessage(string number, string message) {
bool interruptDisabled = false;
//If serial received interrupt is enabled, disable it for the duration of the action.
if (interrupt) {
DetachInterrupt();
interruptDisabled = true;
}
//Set text mode.
Write("AT+CMGF=1\r\n");
Thread.Sleep(10);
//Set destination phone number and open text editing. The phone does not ack this.
Write("AT+CMGS=\"" + number + "\"" + "\r\n");
Thread.Sleep(10);
//Write Message
Write(message);
Thread.Sleep(10);
//Terminating characters.
//Currently fixing this.
//Write("\x1A\x1A\r"); Attempt using hex.
//Write("\u001F\u001F"); Unicode equivalent character.
if(serialPort.IsOpen) {
byte[] terminatingChars = new byte[2];
terminatingChars[0] = 26;
terminatingChars[1] = 26;
serialPort.Write(terminatingChars, 0, 2);
}
Write("AT");
Thread.Sleep(10);
//Reenable interrupt if it has been disabled
if (interruptDisabled) {
AttachInterrupt();
}
//Flush any serial data that may have been recieved.
ReadSerial();
return true;
}
Also using my serial write method:
//Function to safely write to serial port.
public bool Write(string message) {
//Check that serial port is open.
if (serialPort.IsOpen) {
//Try to write message out serialPort.
try {
serialPort.Write(message);
//Todo: catch exceptions separately.
} catch (Exception) {
Log.WriteLine("Serial Output Exception");
return false;
}
return true;
}
return false;
}
And this is the whole class, that should compile in .net or Mono:
//Nokia Phone Serial Command Interface Class.
//Defines a phone class with control and interrupts.
//ENSURE INTERRUPT IS ATTACHED ONLY AFTER CONFIGURATION.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.IO.Ports;
using System.Threading;
namespace SMSInterface {
public class Phone {
public SerialPort serialPort = new SerialPort();
private bool interrupt;
private string messageCenter;
private Queue<Message> outgoingMessages = new Queue<Message>();
private Queue<Message> incomingMessages = new Queue<Message>();
public Phone() {
//TODO Set configurations and stuff.
//lolkay
}
//Deconstructor to ensure serial port is properly closed.
~Phone() {
Stop();
}
public bool Start(string portIn) {
//Set port.
if (!SetPort(portIn)) {
return false;
}
//Initialise Hardware
Log.WriteLine("Initialising Hardware.");
ConfigureSerial();
OpenSerial();
//Handshaking to ensure phone communicating.
if (IsAvailable()) {
ConfigurePhone();
//Attach Serial Event Interrupt.
AttachInterrupt();
//Inform the user.
Log.WriteLine("Hardware Initialised.");
return true;
} else {
return false;
}
}
public bool Stop() {
try {
DetachInterrupt();
serialPort.Close();
serialPort.Dispose();
return true;
} catch (Exception e) //Todo: this should only catch serial exceptions.
{
return false;
}
}
//Opens associated serial port.
private bool OpenSerial() {
//Open Serial Port
Log.WriteLine("Opening Serial Port");
try {
serialPort.Open();
} catch (Exception e) {
//TODO make not suck.
//i.e handle the different possible exceptions this can throw
//individually
Log.WriteLine("Serial Port Exception");
Log.WriteLine(e.Message);
return false;
}
if (serialPort.IsOpen) {
Log.WriteLine("Serial Port Open");
Thread.Sleep(500);
return true;
}
return false;
}
//Method to check phone is available.
public bool IsAvailable() {
//At should return OK.
if (SendCommand("AT")) {
return true;
}
return false;
}
//Interface method to check if messages are available.
public bool MessagesAvailable() {
if (incomingMessages.Count() > 0) {
return true;
} else {
return false;
}
}
//Interface method to retrieve message from buffer.
public Message GetMessage() {
return incomingMessages.Dequeue();
}
//Function to send sms messages with raw input.
public bool SendMessage(string number, string message) {
bool interruptDisabled = false;
//If interrupt is enabled, disable it for the duration of the action.
if (interrupt) {
DetachInterrupt();
interruptDisabled = true;
}
//Set text mode.
Write("AT+CMGF=1\r\n");
Thread.Sleep(10);
//Set destination phone number and open text editing. The phone does not ack this.
Write("AT+CMGS=\"" + number + "\"" + "\r\n");
Thread.Sleep(10);
//Write Message
Write(message);
Thread.Sleep(10);
//Terminating characters.
//Currently fixing this.
//Write("\x1A\x1A\r");
Write("\u001F\u001F");
if(serialPort.IsOpen) {
byte[] terminatingChars = new byte[2];
terminatingChars[0] = 26;
terminatingChars[1] = 26;
//serialPort.Write(terminatingChars, 0, 2);
}
Write("AT");
Thread.Sleep(10);
//Reenable interrupt if it has been disabled
if (interruptDisabled) {
AttachInterrupt();
}
//Flush any serial data that may have been recieved.
ReadSerial();
return true;
}
//Overloaded function to send sms messages with message class.
public bool SendMessage(Message message) {
return SendMessage(message.number, message.content);
}
//Function to safely (handled) write to serial port.
public bool Write(string message) {
//Check that serial port is open.
if (serialPort.IsOpen) {
//Try to write message out serialPort.
try {
serialPort.Write(message);
} catch (Exception) {
Log.WriteLine("Serial Output Exception");
return false;
}
return true;
}
return false;
}
//Function to send and confirm AT commands.
private bool SendCommand(string command) {
int count = 0;
string incoming;
bool interruptDisabled = false;
//Check serial port is open.
if (!serialPort.IsOpen) {
Log.WriteLine("Serial not available");
return false;
}
//If interrupt is enabled, disable it for the duration of the action.
if (interrupt) {
DetachInterrupt();
interruptDisabled = true;
}
//Send Command to phone.
Write(command + "\r\n");
// Loop until data recieved or timeout occurs.
while (true) {
if (serialPort.BytesToRead > 0) {
//Give the phone some time to finish responding
Thread.Sleep(10);
//Try to read incoming data.
try {
incoming = serialPort.ReadLine();
} catch (Exception e) {
Log.WriteLine(e.ToString());
return false;
}
//Parse incoming data.
if (incoming.Contains("OK")) {
//If command was successful,
//Reenable interrupt if it has been disabled
if (interruptDisabled) {
AttachInterrupt();
}
//inform calling function.
return true;
} else if (incoming.Contains("ERROR")) {
//Try Again.
Write(command + "\r");
}
}
//Count and escape after 10 attempts.
count++;
if (count > 10) {
Log.WriteLine("Serial Command Fail: " + command);
//Reenable interrupt if it has been disabled
if (interruptDisabled) {
AttachInterrupt();
}
return false;
}
//Delay to let the dust settle.
Thread.Sleep(10);
}
}
//Attach or unattach interrupt listener.
private void AttachInterrupt() {
interrupt = true;
serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.SerialPort_DataRecieved);
}
private void DetachInterrupt() {
serialPort.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(this.SerialPort_DataRecieved);
interrupt = false;
}
//Set serial port.
private bool SetPort(string input) {
string[] ports;
//Get available port names.
ports = SerialPort.GetPortNames();
//If the port is valid.
if (ports.Contains(input)) {
//Set this as the port for use.
serialPort.PortName = input;
return true;
} else {
Log.WriteLine("Invalid Serial Port: " + input);
return false;
}
}
//Configuration data for the serial port.
private void ConfigureSerial(int baudRate, int timeout) {
serialPort.BaudRate = baudRate;
serialPort.WriteTimeout = timeout;
}
//Overload for default values
private void ConfigureSerial() {
ConfigureSerial(115200, 1000);
}
//Overload to take a single input value
private void ConfigureSerial(int value, bool valueIsTimeout) {
if (valueIsTimeout) {
ConfigureSerial(115200, value);
} else {
ConfigureSerial(value, 1000);
}
}
//Configure Phone.
private bool ConfigurePhone() {
//Set text mode.
SendCommand("AT+CMGF=1");
//Set Message Reciept Mode.
SendCommand("AT+CNMI=1,2,0,0,0");
return true;
}
public void ReadSerial() {
string incoming;
string content;
string existing;
while (serialPort.BytesToRead > 0) {
//Give it a little time to recieve the message.
Thread.Sleep(10);
//Note that this blocks until a line is recieved.
incoming = serialPort.ReadLine();
Console.WriteLine(incoming);
//Interpret incoming messages.
if (incoming.StartsWith("+CMT")) {
//Mesage incoming.
Log.WriteLine("Message Incoming");
content = serialPort.ReadLine();
//Add message to queue.
Message temp = new Message(incoming, content);
incomingMessages.Enqueue(temp);
break;
} else if (incoming.StartsWith("RING")) {
//Someone is calling.
Log.WriteLine("RING");
} else if (incoming == "\r") {
//Ignore blank newlines.
} else {
//Unrecognised.
Log.WriteLine("> " + incoming);
}
}
}
//Data recieved interrupt for the serial port.
private void SerialPort_DataRecieved(object sender, SerialDataReceivedEventArgs e) {
ReadSerial();
}
}
}
Any help would be appreciated