Showing posts with label modem. Show all posts
Showing posts with label modem. Show all posts

Monday, October 31, 2022

Simple C++ example to send serial AT commands to and receive data from a modem

I tried using many C/C++ libraries trying to coax a 5G modem to respond to my input AT commands for a long time but I was not successful. The command I was trying to send was the Quectel modem command to query for PDN channels:

AT+CGDCONT?

After a while, I figured out I had to simulate a keyboard Enter press in code to actually tell the modem the command is complete. So all I had to do was append the carriage return (\r) and new line (\n) characters to the AT command string, e.g:

string cmd = "AT+CGDCONT?\r\n";

A working C++ code example is shown below:

#include <string>
#include <iostream>
#include <cstdio>
#include <unistd.h>

// Using header only library from 
// https://github.com/karthickai/serial
#include "Serial.h"


using namespace std;


int main ( int argc, char** argv) {

        string commPort = "/dev/ttyUSB2";
        unsigned int baud = 115200;
        serial::Serial serial;

        serial.open ( commPort, baud);

        if ( !serial.isOpen()) {
                cout << "comm port is not open" << endl;
                return 1;
        }

        // A modem AT query command
        string cmd = "AT+CGDCONT?\r\n";
        vector<uint8_t> cmdVec (cmd.begin(), cmd.end());

        // send command to the modem
        size_t bytesSent = serial.transmitAsync(cmdVec);
        cout << "Bytes sent " << bytesSent << endl;

        int received_bytes = -1;

        while (received_bytes != 0 ) {
                // read one byte from the modem and timeout if the
                // there is no response in more than 1 sec.
                future<vector<uint8_t>> future = serial.receiveAsync(1, 1000);
                vector<uint8_t> const received_data = future.get();
                received_bytes = received_data.size();

                string str(received_data.begin(), received_data.end());
                cout << "[" << received_data[0] << "] " << endl;
        }
        // Close the serial port
        serial.close();

        cout << "End of process" << endl;

        return 0;

}

The example prints out the data sent by the modem to the calling program, as shown below:

Note: this example is using the modern serial header only C++ library from this site: https://github.com/karthickai/serial

Monday, September 19, 2022

Run Quectel's Connection Manager as a systemd service on Ubuntu

I found myself in possession of a modem by Quectel (https://www.quectel.com) to hook up to a Raspberry Pi running Ubuntu 20.04. I wanted to auto run Quectel's connection manager executable quectel-CM on system start up but found limited information available online from Quectel. So I had to roll up my sleeves and make my own systemd service for that purpose.

This post outlines the steps I took:

Download and compile the quectel-CM executable

  1. Using an Internet browser, download the latest Quectel LTE, 5G Linux USB driver, e.g. Quectel_LTE5G_Linux_USB_Driver_V1.0.zip from https://www.quectel.com/download-zone.
     
  2.  Extract QConnectManager_Linux_V1.0.zip into a folder e.g. /home/ubuntu/Downloads/quectel-CM/.

  3. In a Terminal, change directory to the extracted folder.

    $ cd ~/Downloads/quectel-CM/

  4. Use the make command to compile the connection manager executable.

    $ make

    The quectel-CM executable is compiled.

Place the quectel-CM exe to the run time directory

  1. In a Terminal, type in the following commands to change directory to the extracted directory.

    $ cd /home/ubuntu/Downloads/quectel-CM/

  2. Copy the executable to /usr/local/bin/.

    $ sudo cp quectel-CM /usr/local/bin

Create a systemd service file

  1.  In the directory /etc/systemd/system, use a text editor to create a service file e.g. quectelcm.service.

    $ sudo vi /etc/systemd/system/quectelcm.service

  2. Type in the following lines, save and exit the file:
    [Unit]
    Description=Systemd service for running Quectel's Connection Manager quectel-CM executable
    
    [Service]
    ExecStart=/usr/local/bin/quectel-CM 
    Restart=always
    RestartSec=5
    
    [Install]
    WantedBy=multi-user.target
    

  3. Give the service file the following executable permission:

    $ sudo chmod 664 /etc/systemd/system/quectelcm.service

 Create the service

  1. In the Terminal, type in the following commands:

    $ sudo systemctl daemon-reload
    $ sudo systemctl enable quectelcm

    The quectelcm service is created.

 

Running and monitoring the service

  1. You can either reboot the Raspberry Pi or type in the following command to start the service in a Terminal.

    $ sudo systemctl start quectelcm

  2. To monitor the quectelcm service, use the journalctl command:

    $ journalctl -u quectelcm -f


Note: In order for quectel-CM to request and set the machine's network address, the software prerequisites net-tools and udhcpc must be installed on the Raspberry Pi.