Example Script Showing RTCM Disconnect/Connect Status

Tim, do you have an example of where a script would get the connect/disconnect information? I see information in asterisks -rvv and then doing voter debug level 2 or 3 but it;s like a firehose at that point. Sending the asterisks cli output it to it’s own log I guess would be an option and then cron a job to grep out connect/disconnect messages and somehow put that into a php page.

Thinking out loud here.

Ted

This is not exactly what you want to do but it should give you the general idea. This is how I switch to the backup repeater when the main fails. This script runs from cron every minute.

cat testSantiagoSwitchRTCM.sh 
#!/bin/sh

voter=$(./timvot 127.0.0.1 2532)
#echo $voter
if echo "$voter" | grep -q Santiago
then
    echo "Santiago is up."
    if [ -e theDownFile ]
    then
        /bin/logger "Santiago up. Switching HB RTCM TX off."
        ./RTCM_hb_tx_off.sh
        rm -f theDownFile
    fi
else
    echo "Santiago is down."
    if [ ! -e theDownFile ]
    then
        /bin/logger "Santiago down. Switching HB RTCM TX on."
        touch theDownFile
        ./RTCM_hb_tx_on.sh
    fi
fi
exit 0

The c program timvote simply queries asterisk via the AMI for the status of the RTCM. This would be way easier to do in php but Jim Dixon wrote this and he was a c/emacs sort of a guy who wouldn’t dream of touching php. The username and password are hard coded (BAD JIM!) and are replaced with XXXXX here. If you dig in to my allmon code you see how to do this in php. Of course you could this as is replacing the username and password and compile.

cat timvot.c 
#include <stdio.h>      /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
#include <stdlib.h>     /* for atoi() and exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */

#define RCVBUFSIZE 256   /* Size of receive buffer */

char rxbuf[40960];

static void DieWithError(char *errorMessage)
{
	fprintf(stderr,errorMessage);
	exit(255);
}

void readstuff(int sock)
{
    int i,bytesRcvd;
    char echoBuffer[RCVBUFSIZE];     /* Buffer for echo string */
    fd_set fds[2];
    struct timeval tmout;

    rxbuf[0] = 0;
    while(1) {
	FD_ZERO(fds);
	FD_SET(sock,fds);
	tmout.tv_sec = 0;
	tmout.tv_usec = 100000;
	i = select(sock + 1,fds,NULL,NULL,&tmout);
	if (i < 1) break;
	if (!FD_ISSET(sock,fds)) continue;
	if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) < 0)
	        DieWithError("recv() failed or connection closed prematurely");
	if (!bytesRcvd) break;
	echoBuffer[bytesRcvd] = 0;
	if ((strlen(rxbuf) + strlen(echoBuffer)) < sizeof(rxbuf)) strcat(rxbuf,echoBuffer);
    }
    return;
}


int main(int argc, char *argv[])
{
    int sock;                        /* Socket descriptor */
    struct sockaddr_in echoServAddr; /* Echo server address */
    unsigned short echoServPort;     /* Echo server port */
    char *servIP;                    /* Server IP address (dotted quad) */
    char echoString[1024];           /* String to send to echo server */
    unsigned int echoStringLen;      /* Length of string to echo */

    if ((argc < 3) || (argc > 4))    /* Test for correct number of arguments */
    {
       fprintf(stderr, "Usage: %s <Server IP> <NodeList> [<Server Port>]\n",
               argv[0]);
       exit(1);
    }

    servIP = argv[1];             /* First arg: server IP address (dotted quad) */

    if (argc == 4)
        echoServPort = atoi(argv[3]); /* Use given port, if any */
    else
        echoServPort = 5038;  /* 7 is the well-known port for the echo service */

    /* Create a reliable, stream socket using TCP */
    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        DieWithError("socket() failed");

    /* Construct the server address structure */
    memset(&echoServAddr, 0, sizeof(echoServAddr));     /* Zero out structure */
    echoServAddr.sin_family      = AF_INET;             /* Internet address family */
    echoServAddr.sin_addr.s_addr = inet_addr(servIP);   /* Server IP address */
    echoServAddr.sin_port        = htons(echoServPort); /* Server port */

    /* Establish the connection to the echo server */
    if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
        DieWithError("connect() failed");

    strcpy(echoString,"ACTION: LOGIN\r\nUSERNAME: XXXXXXXX\r\nSECRET: XXXXXXXXXX\r\nEVENT: 0\r\n\r\n");

    echoStringLen = strlen(echoString);          /* Determine input length */
    /* Send the string to the server */
    if (send(sock, echoString, echoStringLen, 0) != echoStringLen)
        DieWithError("send() sent a different number of bytes than expected");

    readstuff(sock);

    if ((!strstr(rxbuf,"Response: Success")) ||
	(!strstr(rxbuf,"Message: Authentication accepted")))
		DieWithError(rxbuf);

    printf("Logged In\n");

    sprintf(echoString,"ACTION: VoterStatus\r\nNODE: %s\r\n\r\n",argv[2]);

    echoStringLen = strlen(echoString);          /* Determine input length */
    /* Send the string to the server */
    if (send(sock, echoString, echoStringLen, 0) != echoStringLen)
        DieWithError("send() sent a different number of bytes than expected");

    readstuff(sock);

    if (!rxbuf[0]) DieWithError("Cannot do command");

    printf("Command Returned: %s\n",rxbuf);

    close(sock);
    exit(0);
}

Thanks Tim. That should keep me busy for a while.

73
Ted
W6SAT

If you can see the information you want from the asterisk cli, it should be going to the /var/log right? I would just tail it then filter it with AWK, outputting it to a cleaner slier CSV file that you could then rsync to your computer, email it to yourself or send the STD to an MQTT broker to monitor in real time with some prettier methods.

EDIT: Could be placed as variables into PHP as well, once awk’ed and parsed.

Jae, I was wondering about this and how to get output from asterisks CLI without actually having it up on the screen. So how would you automate sending commands to the asterisks CLI from lets say cron?

Ted

Here’s one way. Just replace the command you want to run inside quotes.

 asterisk -rx "rpt stats 2531"

This bash script announces the time.

#! /bin/bash
/usr/sbin/asterisk -rx "rpt cmd 2532 status 12 0"

But for you want to do with the RTCM you have to use the AMI.

The method Tim mentioned above works great for sure. It is super easy to test, modify, deploy, read, activate and replicate. I have never used an RTCM, I could not help with that.

The way I suggested above of moving data just with using a simple script and push services of some sort is a bit more complex and only used to get data out of the box. An example of how that would work can be seen in a YouTube video I made a few days ago, found here.

Personally I think the bigger question is not how to get data into asterisk nor should we be asking how to get it out. In the grander scheme we need to be asking ourselves how to do both and how to do it in the quickest way possible, without affecting any existing code or latency. Add a full layer of communication options over top what is already existing without users seeing any impact would be a great goal. I personally think that the key to all this lies within MQTT messaging. But honestly that could be a 75 page whitepaper.

Great info. I have another DTMF question but I’ll start a new thread for that one.

Ted