I am using GSM module SIM800 on Arduino and want to learn how to create my own custom library for it. I have been using TinyGSM library and trying to learn from it. I feel like this library is 10x overkill for my project needs and its very hard to follow because it has very many nested functions which keeps calling another functions over and over again which makes it nearly impossible to follow this code (atleast for begginer programmer as me).
I want to create a class constructor which would allow me to create GSM module object, and then I can use this object to use any functions that I declare within a class.
From the tinyGSM library, I think the object constructor is defined as:
public:
explicit TinyGsmSim800(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
However, I am not able to fully understand why it is being declared in this manner?
- Why Stream instead of Serial?
- What are those sockets and why use memset?
This is going to be my first custom library that I am going to write and I dont have much experience with classes, hoping you guys could help me out.
I have created a cpp file where I am going to declare my constructor. I also want to create a send_AT_command function where I am going to pass a string of AT command that I want to send to my GSM modem. Can someone help me understand how to properly build a Constructor and how to further use it in my other functions?
#include "custom_modem.h"
#include "Arduino.h"
custom_modem :: custom_modem(Serial serial)
{
}
custom_modem :: send_AT_command(String command){
}
UPDATE2
I have made some progress. I have found another thread: Arduino: Calling serial.begin() on a Stream object
And I have simplified it further for my needs.
My header file:
#ifndef custom_modem_h
#define custom_modem_h
#include <Arduino.h>
#include <Stream.h>
#include <HardwareSerial.h>
#define MODEM_TX 27
#define MODEM_RX 26
class custom_modem
{
public:
custom_modem(HardwareSerial* serial);
void start_modem();
void send_AT_command(String command);
private:
Stream * _port;
//Stream& _serial;
};
#endif
My source file:
#include "custom_modem.h"
#include "Arduino.h"
custom_modem::custom_modem(HardwareSerial* serial)
{
_port = serial;
}
void custom_modem::start_modem(){
static_cast<HardwareSerial*>(_port)->begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
}
I am now able to create a class object and the program does not return any errors:
custom_modem modem(&SerialAT);
However, this code brings me a lot of questions:
1. As you can see from the source file, I am passing HardwareSerial* serial and then I assign this variable to
_port = serial
But in my header file, the _port is declared as Stream* variable. How does this work?
2. Why do I need use pointers as such: In my source file:
custom_modem::custom_modem(HardwareSerial* serial)
And in my header file:
custom_modem(HardwareSerial* serial);
Is it not better to pass it by reference? using HardwareSerial& ? What is the difference? Pointers are killing me I dont understand them very well
3. Why do I need to use this annoying cast?
static_cast<HardwareSerial*>(_port)->begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
If I simply write:
_port.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
Its going to give me an error.
I would very much appreciate if you could help me answer those questions! Thanks
UPDATE3
I have developed a method for my class to send an AT command and return an answer:
String custom_modem::send_AT_command()
{
String return_message; // Crate a string to store a return message
static_cast<HardwareSerial*>(_port)->write("AT"); // Write an "AT" message to serial device. Expecting to receive "OK"
delay(1);
while( static_cast<HardwareSerial*>(_port)->available())
{
char c = static_cast<HardwareSerial*>(_port)->read(); // Read character at a time
return_message.concat(c); // append a string with the character
}
return return_message;
}
However, When I call this in my arduino code:
String answer;
void loop() {
answer = modem.send_AT_command();
Serial.print("answer=");
Serial.println(answer);
delay(2000);
// put your main code here, to run repeatedly:
}
It does not seem to return anything: Serial monitor image
I believe this could be an issue with the way I implement my send_AT_command function?
UPDATE4
Solved the AT command issue by adding a line termination /n/r. Now works fine.
When trying to initialise a class by referencing HardwareSerial, I still have problems:
My cpp:
#include "Arduino.h"
#include "String.h"
custom_modem::custom_modem(HardwareSerial* serial)
{
_port = serial;
}
void custom_modem::start_modem(){
_port->begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
}
String custom_modem::send_AT_command()
{
String return_message; // Crate a string to store a return message
_port->write("AT\n\r"); // Write an "AT" message to serial device. Expecting to receive "OK"
delay(1);
while(_port->available())
{
char c = _port->read(); // Read character at a time
return_message.concat(c); // append a string with the character
}
return return_message;
}
and the header:
#ifndef custom_modem_h
#define custom_modem_h
#include <Arduino.h>
#include <HardwareSerial.h>
#define MODEM_TX 27
#define MODEM_RX 26
class custom_modem
{
public:
custom_modem(HardwareSerial* serial);
void start_modem();
String send_AT_command();
private:
HardwareSerial* _port;
};
#endif
The code above works when I initialise class object as :
#define SerialAT Serial1
custom_modem modem(&SerialAT);
Could you clarify how do I have to change the code to get it to work if I want to use HardwareSerial by referencing:
If I change both .cpp and header file :
HardwareSerial* serial
to
HardwareSerial& serial
It gives me an error. I believe it might have to do with the variable _port in my header file.:
private:
HardwareSerial* _port;
What would be the correct way to initialise it?