/*------------------------------------------------------------------------------- * dsd_rigctl.c * Simple RIGCTL Client for DSD (remote control of GQRX, SDR++, etc) * * Portions from https://github.com/neural75/gqrx-scanner * * LWVMOBILE * 2022-10 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ #include "dsd.h" #include #include #include #include //UDP Specific #include #define BUFSIZE 1024 #define FREQ_MAX 4096 #define SAVED_FREQ_MAX 1000 #define TAG_MAX 100 // // error - wrapper for perror // void error(char *msg) { perror(msg); exit(0); } struct sockaddr_in address; // // Connect // int Connect (char *hostname, int portno) { int sockfd; struct sockaddr_in serveraddr; struct hostent *server; /* socket: create the socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { fprintf(stderr,"ERROR opening socket\n"); error("ERROR opening socket"); } /* gethostbyname: get the server's DNS entry */ server = gethostbyname(hostname); if (server == NULL) { fprintf(stderr,"ERROR, no such host as %s\n", hostname); //exit(0); return (0); //return 0, check on other end and configure pulse input } /* build the server's Internet address */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, server->h_length); serveraddr.sin_port = htons(portno); /* connect: create a connection with the server */ if (connect(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) { fprintf(stderr,"ERROR opening socket\n"); return (0); } return sockfd; } // // Send // bool Send(int sockfd, char *buf) { int n; n = write(sockfd, buf, strlen(buf)); if (n < 0) error("ERROR writing to socket"); return true; } // // Recv // bool Recv(int sockfd, char *buf) { int n; n = read(sockfd, buf, BUFSIZE); if (n < 0) error("ERROR reading from socket"); buf[n]= '\0'; return true; } // // GQRX Protocol // long int GetCurrentFreq(int sockfd) { long int freq = 0; char buf[BUFSIZE]; char * ptr; char * token; Send(sockfd, "f\n"); Recv(sockfd, buf); if (strcmp(buf, "RPRT 1") == 0 ) return freq; token = strtok (buf, "\n"); freq = strtol (token, &ptr, 10); // fprintf (stderr, "\nRIGCTL VFO Freq: [%ld]\n", freq); return freq; } bool SetFreq(int sockfd, long int freq) { char buf[BUFSIZE]; sprintf (buf, "F %ld\n", freq); Send(sockfd, buf); Recv(sockfd, buf); if (strcmp(buf, "RPRT 1") == 0 ) return false; return true; } bool SetModulation(int sockfd, int bandwidth) { char buf[BUFSIZE]; //the bandwidth is now a user/system based configurable variable sprintf (buf, "M FM %d\n", bandwidth); Send(sockfd, buf); Recv(sockfd, buf); if (strcmp(buf, "RPRT 1") == 0 ) return false; return true; } bool GetSignalLevel(int sockfd, double *dBFS) { char buf[BUFSIZE]; Send(sockfd, "l\n"); Recv(sockfd, buf); if (strcmp(buf, "RPRT 1") == 0 ) return false; sscanf(buf, "%lf", dBFS); *dBFS = round((*dBFS) * 10)/10; if (*dBFS == 0.0) return false; return true; } bool GetSquelchLevel(int sockfd, double *dBFS) { char buf[BUFSIZE]; Send(sockfd, "l SQL\n"); Recv(sockfd, buf); if (strcmp(buf, "RPRT 1") == 0 ) return false; sscanf(buf, "%lf", dBFS); *dBFS = round((*dBFS) * 10)/10; return true; } bool SetSquelchLevel(int sockfd, double dBFS) { char buf[BUFSIZE]; sprintf (buf, "L SQL %f\n", dBFS); Send(sockfd, buf); Recv(sockfd, buf); if (strcmp(buf, "RPRT 1") == 0 ) return false; return true; } // // GetSignalLevelEx // Get a bunch of sample with some delay and calculate the mean value // bool GetSignalLevelEx(int sockfd, double *dBFS, int n_samp) { double temp_level; *dBFS = 0; int errors = 0; for (int i = 0; i < n_samp; i++) { if ( GetSignalLevel(sockfd, &temp_level) ) *dBFS = *dBFS + temp_level; else errors++; usleep(1000); } *dBFS = *dBFS / (n_samp - errors); return true; } //shoe in UDP input connection here...still having issues that I don't know how to resolve int UDPBind (char *hostname, int portno) { UNUSED(hostname); int sockfd; struct sockaddr_in serveraddr; /* socket: create the socket */ //UDP socket sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sockfd < 0) { fprintf(stderr,"ERROR opening UDP socket\n"); error("ERROR opening UDP socket"); } /* build the server's Internet address */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY serveraddr.sin_port = htons(portno); //Bind socket to listening if (bind(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) { perror("ERROR on binding UDP Port"); } return sockfd; } //going to leave this function available, even if completely switched over to rtl_dev_tune now, may be useful in the future void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency) { UNUSED(state); int handle; unsigned short udp_port = opts->rtl_udp_port; char data[5] = {0}; //data buffer size is 5 for UDP frequency tuning struct sockaddr_in address; uint32_t new_freq = frequency; opts->rtlsdr_center_freq = new_freq; //for ncurses terminal display after rtl is started up handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); data[0] = 0; data[1] = new_freq & 0xFF; data[2] = (new_freq >> 8) & 0xFF; data[3] = (new_freq >> 16) & 0xFF; data[4] = (new_freq >> 24) & 0xFF; memset((char * ) & address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr("127.0.0.1"); //make user configurable later address.sin_port = htons(udp_port); sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in)); close (handle); //close socket after sending. } int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data) { UNUSED(state); size_t err = 0; //listen with: //short 8k/2 //socat stdio udp-listen:23456 | play --buffer 320*2 -q -b 16 -r 8000 -c2 -t s16 - //short 8k/1 //socat stdio udp-listen:23456 | play --buffer 160*2 -q -b 16 -r 48000 -c2 -t s16 - //float 8k/2 //socat stdio udp-listen:23456 | play --buffer 320*4 -q -e float -b 32 -r 8000 -c2 -t f32 - //float 8k/1 //socat stdio udp-listen:23456 | play --buffer 160*4 -q -e float -b 32 -r 8000 -c1 -t f32 - //send audio or data to socket err = sendto(opts->udp_sockfd, data, nsam, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in)); if (err < 0) fprintf (stderr, "\n UDP SENDTO ERR %ld", err); //return value here is size_t number of characters sent, or -1 for failure if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible } int udp_socket_connect(dsd_opts * opts, dsd_state * state) { UNUSED(state); long int err = 0; err = opts->udp_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (err < 0) { fprintf (stderr, " UDP Socket Error %ld\n", err); return (err); } // Don't think this is needed, but doesn't seem to hurt to keep it here either int broadcastEnable = 1; err = setsockopt(opts->udp_sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); if (err < 0) { fprintf (stderr, " UDP Broadcast Set Error %ld\n", err); return (err); } memset((char * ) & address, 0, sizeof(address)); address.sin_family = AF_INET; err = address.sin_addr.s_addr = inet_addr(opts->udp_hostname); if (err < 0) //error in this context reports back 32-bit inet_addr reversed order byte pairs { fprintf (stderr, " UDP inet_addr Error %ld\n", err); return (err); } address.sin_port = htons(opts->udp_portno); if (err < 0) { fprintf (stderr, " UDP htons Error %ld\n", err); return (err); } }