Adafruit FONA MiniGSM is a great product, you can learn more here, they wrote a library for Arduino which is found here.
If you buy this product and use it on Arduino, you will have not problems but what about if you need to do some complex needing a Raspberry Pi (RPi) or similar computer? Adafruit provide you a post for connecting FONA to a RPi here but has nothing for programming something.
When I bought FONA (like a year ago) I was in this situation, I wrote a small library in C which supports the most basic operations like send command and check command reply, I wrote a function to send SMS which basically use the previous functions, if you need more functions is not hard to extend the library.
The library is written in C and tested in Linux, it should work with most Linux distributions and with most SIMXXX chips working with AT commands.
I put a Main function as an example for using this library.
Note: This assume you have connected FONA to the port "/dev/ttyUSB0", be sure to change it if is not the case.
/**
* source: http://stackoverflow.com/a/6947758/3211175
*
* Author: Alexis Hernandez
*
* gcc adafruit_fona_rpi.c -o fona -std=c99
**/
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <features.h>
#include <string.h>
#ifndef CRTSCTS
# ifdef CNEW_RTSCTS
# define CRTSCTS CNEW_RTSCTS
# else
# define CRTSCTS 0x80000000
# endif /* CNEW_RTSCTS */
#endif /* !CRTSCTS */
int set_interface_attribs(int fd, int speed, int parity) {
struct termios tty;
memset(&tty, 0, sizeof tty);
if ( tcgetattr(fd, &tty) != 0 ) {
printf("error %d from tcgetattr\n", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if ( tcsetattr(fd, TCSANOW, &tty) != 0 ) {
printf("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void set_blocking(int fd, int should_block) {
struct termios tty;
memset (&tty, 0, sizeof tty);
if ( tcgetattr(fd, &tty) != 0 ) {
printf("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if ( tcsetattr(fd, TCSANOW, &tty) != 0 ) {
printf("error %d setting term attributes", errno);
}
}
int fd; // file descriptor for connection
char buf [100]; // buffer for the reply
// init connection
int startConnection(char *portname) {
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("error %d opening %s: %s", errno, portname, strerror (errno));
return 0;
}
set_interface_attribs(fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking(fd, 0); // set no blocking
//
send("AT");
usleep(100000);
// turn off Echo!j
send("ATE0");
usleep(100000);
return sendCheckReply("ATE0", "OK");
}
void endConnection() {
close(fd);
}
// send a command to the serial port, read the answer but do nothing
int send(char *cmd) {
// printf("send: %s\n", cmd);
int cmd_len = strlen(cmd);
write( fd, cmd, cmd_len ); // send cmd
write( fd, "\n", 1 );
usleep ( (cmd_len + 10 + 25) * 300 ); // sleep enough to transmit the cmd plus
// receive 25: approx 100 uS per char
int read_len = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read
/*
// print result
printf(" read: %d bytes\n", read_len);
for (int i = 0; i < read_len; i++) printf( " %c", buf[i] );
printf("\n");
for (int i = 0; i < read_len; i++) printf( " %d", buf[i] );
printf("\n");
*/
return 1;
}
/**
* send cmd and checks device's reply match exact message
* cmd and reply should ends with "cr+lf"
**/
int sendCheckReply(char *cmd, char *reply) {
// printf("sendCheckReply: %s\n", cmd);
int cmd_len = strlen(cmd);
write( fd, cmd, cmd_len ); // send cmd
write( fd, "\n", 1 );
usleep ( (cmd_len + 10 + 25) * 300 ); // sleep enough to transmit the cmd plus
// receive 25: approx 100 uS per char
int read_len = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read
// should return some like "\r\nxx\r\n", then avoid first 2 and last 2 bytes
// print result
/*
printf(" read: %d bytes\n", read_len);
for (int i = 0; i < read_len; i++) printf( " %c", buf[i] );
printf("\n");
for (int i = 0; i < read_len; i++) printf( " %d", buf[i] );
printf("\n");
*/
// strcmp
int reply_idx = 0;
int reply_len = strlen(reply);
int read_idx = 2;
read_len -= 2;
for (; reply_idx < reply_len && read_idx < read_len && reply[reply_idx] == buf[read_idx]; reply_idx++, read_idx++);
return reply_idx == reply_len && read_idx == read_len ? 1 : 0;
}
/**
* send cmd and checks device's reply is a prefix of response
**/
int sendCheckReplyPrefix(char *cmd, char *reply, int extraSleep) {
printf("sendCheckReplyPrefix: %s\n", cmd);
int cmd_len = strlen(cmd);
write( fd, cmd, cmd_len ); // send cmd
write( fd, "\n", 1 );
usleep ( (cmd_len + 10 + 25) * 300 ); // sleep enough to transmit the cmd plus
// receive 25: approx 100 uS per char
if ( extraSleep )
usleep(extraSleep);
int read_len = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read
// should return some like "\r\nxx\r\n", then avoid first 2 and last 2 bytes
// print result
printf(" read: %d bytes\n", read_len);
for (int i = 0; i < read_len; i++) printf( " %c", buf[i] );
printf("\n");
for (int i = 0; i < read_len; i++) printf( " %d", buf[i] );
printf("\n");
// strcmp
int reply_idx = 0;
int reply_len = strlen(reply);
int read_idx = 2;
for (; reply_idx < reply_len && read_idx < read_len && reply[reply_idx] == buf[read_idx]; reply_idx++, read_idx++);
return reply_idx == reply_len ? 1 : 0;
}
// send smmmsg to smsaddr
int sendSMS(char *smsaddr, char *smsmsg) {
if ( !sendCheckReply("AT+CMGF=1", "OK") ) {
printf("fail: AT+CMGF=1\n");
return 0;
}
// build send command like = AT+CMGS="nnnn"
char sendcmd[30] = "AT+CMGS=\"";
strncpy( sendcmd+9, smsaddr, 30-9-2); // 9 bytes beginning, 2 bytes for close quote + null
sendcmd[ strlen(sendcmd) ] = '\"';
printf("trying to send: %s\n", sendcmd);
if ( !sendCheckReplyPrefix( &sendcmd[0], "> ", 0 ) ) {
printf("fail: AT+CMGS=num\n");
return 0;
}
// build msg command, append new line + ctrl+z
char msgcmd [200];
int msglen = strlen(smsmsg);
strncpy(msgcmd, smsmsg, msglen);
msgcmd[msglen] = '\n';
msgcmd[msglen + 1] = 0x1A;
return sendCheckReplyPrefix( msgcmd, "+CMGS", 1000000 * 3 );
}
// main
int main() {
char *portname = "/dev/ttyUSB0";
int attemps = 10;
while ( attemps-- && !startConnection(portname) ) usleep(1000);
if ( attemps <= 0 ) {
printf( "ERROR: Can not start connection\n" );
return 0;
}
printf("Connection started!\n");
char *num = "0123456789";
char *msg = "message here";
if ( sendSMS(num, msg) ) {
printf("SMS sent\n");
} else {
printf("SMS can not be send\n");
}
printf("end\n");
endConnection();
return 0;
}
I hope this can be useful for you, be sure to ask any question.
Thanks for reading and see you in next post.
No comments:
Post a Comment
Leave me a comment