Code to calculate heading / bearing from two GPS latitude and longitude Points

Example code to Estimate heading or course  of travel or bearing given two GPS locations taken from a recorded path.

A lot of GPS devices will report heading along with latitude and longitude, but what if you lust have a series of GPS locations recorded from a path, how can you estimate heading or course of travel at points along the path  given two consecutive GPS locations from the path?

Why might you want to know heading along a path?  Well imagine you have a mobile computer vision application, the effect of the Sun’s illumination may have a large effect on your imaging, if you can calculate the Sun’s position in the sky during the recorded path, and also calculate the camera’s “heading” then you can estimate the effect that the Sun will have on your images, for example are they back-lit, front-lit, will long shadows be cast etc.

The background to the calculation can be found here under the section called ‘bearing’.

Note that the terms ‘heading’, ‘bearing’ and ‘course’ have subtly different meanings especially for vehicles that might drift or yaw like boats or aircraft, but here we use them interchangeably to refer to the movement of the GPS measurement center.  As the points we choose are close together we don’t really have to worry about the difference between initial bearing and final bearing.

Here is some code that will calculate heading from 2 locations.  Pass in the latitude and longitude of both points, the order in which the points are passed will affect the calculated heading.  The two points that you choose should be close together to get a good estimate of ‘instantaneous’ heading, however if they are too close together the estimate may be noisy due to the positional accuracy limits of GPS, a distance of 100m to 200m could work well, experiment for your GPS device and path type.

 

#define _USE_MATH_DEFINES
#include <math.h>
#include "calculate_gps_heading.h"
//   Copyright 2022 Kevin Godden
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
static inline double to_rad(double theta) {
    return (theta * M_PI) / 180.0;
}
static inline double to_degrees(double theta) {
    return (theta * 180.0) / M_PI;
}
//
// Calculate the heading in decimal degrees between 2 (preferably quite close) locations 
// (lat1, lon1) --> First location
// (lat2, lon2) --> Second location
//
double calculate_gps_heading(double lat1, double lon1, double lat2, double lon2) {
    // Convert degrees to radians
    lat1 = to_rad(lat1);
    lon1 = to_rad(lon1);
    lat2 = to_rad(lat2);
    lon2 = to_rad(lon2);    
        
    double dlon = lon2 - lon1;
    double X = cos(lat2) * sin(dlon);
    double Y = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlon);
    
    double heading = atan2(X,Y);
    
    // We want heading in degrees, not radians.
    heading = to_degrees(heading);
  
    // We want a uniform heading of >=0 and <360
    if (heading < 0)
        heading = 360.0 + heading;
    
    return heading;
}

The code along with some tests can be found in this Git repo.

Code Example: Convert Decimal Degrees and Minutes to Decimal Degrees

How to convert between Decimal Degrees & Minutes (DDM) to Decimal Degrees (DD).

I always prefer to represent latitude and longitude as full decimal degrees (DD), I find it much simpler and you can do calculations with the values.  However, other people and devices love to use the slightly (to me) esoteric Decimal Degrees and Minutes (DDM) form and I have to remember how to convert to and from decimal degrees – so here’s a short description of how it’s done along with some C++ sample code.

Decimal Degrees: Latitude and longitude are just represented as a decimal degree value.

Decimal Degrees & Minutes: Encodes a whole number of degrees in the first few digits, the rest of the digits represent a decimal minutes value with 2 digits to the left of the decimal place representing a whole minute value,  e.g. 5254.9098940 : ddmm.mmmmmm

For example, a DDM value of: 5254.9098940 represents 52 degrees and 54.9098940 minutes.

To convert this to decimal degrees, we do something like this:

dd = 52 + (54.9098940 / 60) = 52.9151649 degrees.

And in code:

//
double ddm_to_dd(double ddm) {
    double degrees = floor(ddm / 100.0);
    double minutes = ddm - degrees * 100.0;
    double decimal_degrees = degrees + minutes / 60.0;
    return decimal_degrees;
}

 

 

 

 

Simple Wrapper of boost::asio for receiving UDP datagrams

More easily receive UDP Data via boost::asio providing just IP address and port umber.

The boost::asio classes provide a cross platform way to communicate via UDP without having to use the raw socket libraries, however they can be confusing and hard to use do to their designed-in flexibility.

Sometimes I just want to provide an IP address and a port number and just receive messages so I have written a wrapper class called boost_udp_receive_rar which can be found on GitHub here.

It has 4 functions that allow you to receive string or binary messages in a synchronous or asynchronous manner, for example to receive ASCII string data:

#include "boost_udp_send_faf.h"
#include <thread>
// Setup a receiver, specifying IP address and port
// Note the IP address is that of the receiving network
// interface.  As always with UDP and non-standard ports
// check that a firewall isn't blocking data transfer.
boost_udp_receive_rar rar("127.0.0.1", 8861);
// Receive a datagram synchronously as a string
//
std::string datagram = rar.receive_sync();
std::count << "received: " << datagram << std::endl;
// Asynchronously receive a datagram as a string
//
// We loop calling receive_async() until it returns
// a non-empty string. receive_async() returns quickly
// and we can do other work (or other async reads on different
// ports) while we wait for somethign to arrive.

do {
    datagram = rar.receive_async();
    // Do other stuff
    //
    // Better do a little sleep to be nice to the
    // CPU
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
} while (datagram.empty());
std::count << "received: " << datagram << std::endl;

For an easier way to send UDP data see: boost_udp_send_faf

mktime() always uses local time zone and converts from UTC

If you’re working with UTC times, you may be upset to find that mktime() always converts using your local time zone thus wrecking your UTC times.  Instead of mktime() use:

  • Linux/Posix: timegm()
  • Windows: _mkgmtime()

For example, let’s use timegm() to make a UTC time which we will pass to SolarAzEl() to calculate the Solar Elevation at that time, it must be passed a UTC time!  See this post if you are interested in SolarAzEl().

//
// Make UTC time for 10:16:00 on 5th. May 2022
// and use it to calculate the Solar Elevation
// at the time via SolarAzEl().  SolarAzEl() 
// requires a UTC time!
//
tm utc;
// tm_year is time since 1900
utc.tm_year = 2022 - 1900;
// Month is zero based, i.e. Jan is month 0, May is 4
utc.tm_mon = 5 - 1;
utc.tm_mday = 5;
utc.tm_hour = 10;
utc.tm_min = 16;
utc.tm_sec = 00;
utc.tm_isdst = 0;
// Get UTC time_t val, do not change for local time offset!
tim = timegm(&utc);	// or _mkgmtime() on windows
//
// Now calculate Solar Elevation at
// GPS coordinates 52.975, -6.0494
// at sea level using the UTC time.
//
double altitude = 0;
double Az = 0.0;
double El = 0.0;
double lat = 52.975;
double lon = -6.0494;
SolarAzEl(tim, lat, lon, 0, &Az, &El);
printf("Solar Azimuth: %f\n", Az);
printf("Solar Elevation: %f\n", El);
//

 

 

Estimate Solar Azimuth and Elevation given GPS position and time.

C++ code to estimate Solar Azimuth and Elevation given GPS position and time.

For reasons that I won’t go into here I found it necessary to estimate Solar Azimuth and Elevation given GPS position and time.

Now there is quite a bit of information on how to this on the old inter-web, none of it could be described as being ‘easy’, and most methods use the ‘equation of time’ and require you to know your current time zone in order to to calculate Local Solar Time (LST) so that you can then calculate the current hour angle.

However dynamically determining which time zone you’re in is very difficult, most approaches involve using a web API – but what can you do if you have no internet connection?

Lucky I found some Mathlab code written by Darin C. Koblick which calculates Solar Azimuth and Elevation using just latitude, longitude, UTC time and altitude. It models the Sun orbiting the Earth and does not require to know your time zone! It seems to work very well and I am very happy with the results so far (thanks Darin!)

I ported the code over to C++, trying to change as little from the original Mathlab code as possible, I have included the code here, please note the license text at the end.

The code can be found in this Git repo.

For example, to estimate Azimuth and Elevation for Lat/Lon 52.975/-6.0494 at sea level for the current time:

/*
Copyright(c) 2010, Darin Koblick
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met :
*Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <time.h>
#include <math.h>
#include <stdio.h>
#ifndef M_PI
#define M_PI (3.14159265358979323846264338327950288)
#endif /* M_PI */
// Programed by Darin C.Koblick 2 / 17 / 2009
//
//              Darin C.Koblick 4 / 16 / 2013 Vectorized for Speed
//                                         Allow for MATLAB Datevec input in
//                                         addition to a UTC string.
//                                         Cleaned up comments and code to
//                                         avoid warnings in MATLAB editor.
//
//				Kevin Godden 9/1/2020      Ported from Matlab to C++, tried to change as little as possible.
//                                         this is a non-vectorised port.
//
//--------------------------------------------------------------------------
//
// External Function Call Sequence :
//
// double lat = 52.975;
// double lon = -6.0494;
// double altitude = 0;
//
// double Az = 0.0;
// double El = 0.0;
// SolarAzEl(time(NULL), lat, lon, 0, &Az, &El);
// 
// printf("Azimuth: %f\n", Az);
// printf("Elevation: %f\n", El);
//
// Or to calculate Az & El for an arbitary UTC time:
//
//
// tm utc;
// tm_year is time since 1900
// utc.tm_year = y - 1900;
// Month is zero based, i.e. Jan is month 0
// utc.tm_mon = m - 1;
// utc.tm_mday = d;
// utc.tm_hour = 10;
// utc.tm_min = 16;
// utc.tm_sec = 00;
// utc.tm_isdst = 0;
// 
// Get UTC time_t val
// tim = timegm(&utc);	// or _mkgmtime() on windows
// 
// double altitude = 0;
// double Az = 0.0;
// double El = 0.0;
// 
// double lat = 52.975;
// double lon = -6.0494;
// 
// SolarAzEl(tim, lat, lon, 0, &Az, &El);
// 
// printf("Az: %f\n", Az);
// printf("El: %f\n", El);
// 
//
// Function Description :
//
// SolarAzEl will ingest a Universal Time, and specific site location on earth
// it will then output the solar Azimuth and Elevation angles relative to that
// site.
//
// Input Description :
//
// utc_time_point : time_t containing target time for sun position calculations.
//
// Lat : Site Latitude in degrees -90:90->S(-) N(+)
//
// Lon : Site Longitude in degrees -180:180 W(-) E(+)
//
// Alt : Altitude of the site above sea level(Km)
//
// Output Description :
//  Az    Azimuth location of the sun(deg)
//  El    Elevation location of the sun(deg)
//
//
// Source References :
// Solar Position obtained from :
// http ://stjarnhimlen.se/comp/tutorial.html#5
//
double julian_day(time_t utc_time_point);
void SolarAzEl(time_t utc_time_point, double Lat, double Lon, double Alt, double* Az, double* El) {
    double jd = julian_day(utc_time_point);
    double d = jd - 2451543.5;
    
    // Keplerian Elements for the Sun(geocentric)
    double w = 282.9404 + 4.70935e-5*d; // (longitude of perihelion degrees)
    // a = 1.000000; % (mean distance, a.u.)
    double e = 0.016709 - 1.151e-9*d; // (eccentricity)
    double M = fmod(356.0470 + 0.9856002585*d, 360.0); // (mean anomaly degrees)
        
    double L = w + M; // (Sun's mean longitude degrees)
    double oblecl = 23.4393 - 3.563e-7*d; // (Sun's obliquity of the ecliptic)
    // auxiliary angle
    double  E = M + (180 / M_PI)*e*sin(M*(M_PI / 180))*(1 + e*cos(M*(M_PI / 180)));
    // rectangular coordinates in the plane of the ecliptic(x axis toward perhilion)
    double x = cos(E*(M_PI / 180)) - e;
    double y = sin(E*(M_PI / 180))*sqrt(1 - pow(e, 2));
    // find the distance and true anomaly
    double r = sqrt(pow(x,2) + pow(y,2));
    double v = atan2(y, x)*(180 / M_PI);
    // find the longitude of the sun
    double lon = v + w;
    // compute the ecliptic rectangular coordinates
    double xeclip = r*cos(lon*(M_PI / 180));
    double yeclip = r*sin(lon*(M_PI / 180));
    double zeclip = 0.0;
    //rotate these coordinates to equitorial rectangular coordinates
    double xequat = xeclip;
    double yequat = yeclip*cos(oblecl*(M_PI / 180)) + zeclip * sin(oblecl*(M_PI / 180));
    double zequat = yeclip*sin(23.4406*(M_PI / 180)) + zeclip * cos(oblecl*(M_PI / 180));
    // convert equatorial rectangular coordinates to RA and Decl:
    r = sqrt(pow(xequat, 2) + pow(yequat, 2) + pow(zequat, 2)) - (Alt / 149598000); //roll up the altitude correction
    double RA = atan2(yequat, xequat)*(180 / M_PI);
    double delta = asin(zequat / r)*(180 / M_PI);
    
    // Following the RA DEC to Az Alt conversion sequence explained here :
    // http ://www.stargazing.net/kepler/altaz.html
    //	Find the J2000 value
    //	J2000 = jd - 2451545.0;
    //hourvec = datevec(UTC);
    //UTH = hourvec(:, 4) + hourvec(:, 5) / 60 + hourvec(:, 6) / 3600;
    // Get UTC representation of time / C++ Specific
    tm *ptm;
    ptm = gmtime(&utc_time_point);
    double UTH = (double)ptm->tm_hour + (double)ptm->tm_min / 60 + (double)ptm->tm_sec / 3600;
    // Calculate local siderial time
    double GMST0 = fmod(L + 180, 360.0) / 15;
    double SIDTIME = GMST0 + UTH + Lon / 15;
    
    // Replace RA with hour angle HA
    double HA = (SIDTIME*15 - RA);
    // convert to rectangular coordinate system
    x = cos(HA*(M_PI / 180))*cos(delta*(M_PI / 180));
    y = sin(HA*(M_PI / 180))*cos(delta*(M_PI / 180));
    double z = sin(delta*(M_PI / 180));
    // rotate this along an axis going east - west.
    double xhor = x*cos((90 - Lat)*(M_PI / 180)) - z*sin((90 - Lat)*(M_PI / 180));
    double yhor = y;
    double zhor = x*sin((90 - Lat)*(M_PI / 180)) + z*cos((90 - Lat)*(M_PI / 180));
    
    // Find the h and AZ
    *Az = atan2(yhor, xhor)*(180 / M_PI) + 180;
    *El = asin(zhor)*(180 / M_PI);
}
double julian_day(time_t utc_time_point) {
    // Extract UTC Time
    struct tm* tm = gmtime(&utc_time_point);
    double year = tm->tm_year + 1900;
    double month = tm->tm_mon + 1;
    double day = tm->tm_mday;
    double hour = tm->tm_hour;
    double min = tm->tm_min;
    double sec = tm->tm_sec;
    if (month <= 2) {
        year -= 1;
        month += 12;
    }
    double jd = floor(365.25*(year + 4716.0)) + floor(30.6001*(month + 1.0)) + 2.0 -
        floor(year / 100.0) + floor(floor(year / 100.0) / 4.0) + day - 1524.5 +
        (hour + min / 60 + sec / 3600) / 24;
    return jd;
}

 

Creating time_t value from a UTC date and time in C

Programming with time is difficult and error prone, for this reason I usually try to keep things in UTC so that I don’t have to worry about time zones and daylight saving offsets etc.

When in C++ I mostly use the boost::ptime library but I was surprised recently about tricky it seemed to be to initialise a time_t value for an arbitrary UTC time just using the standard C/C++ libs. We can’t use mktime() as it will figure out which time zone you’re in and assume that the time values you have passed refer to this zone, it will also apply daylight saving offsets.

Anyway to cut a long story short there are no standard functions in the C lib for this, instead your either have to use the posix timegm() function on Unix-like systems and _mkgmtime() on windows systems.

Here is an example, lets say we want to initialise a time_t value for this UTC date/time: 01/10/2020 10:16:03 (10th. Jan 2020)

 

#include <assert.h>
#include <time.h>
#ifndef timegm
// use _mkgmtime() on windows
#define timegm _mkgmtime
#endif
void test_utc() {
struct tm utc;
time_t tim;
struct tm* utc_out;
// Want to create a time_t value for UTC:
// 01/10/2020 10:16:03
// tm_year is time since 1900
utc.tm_year = 2020 - 1900;
// Month is zero based, i.e. Jan is month 0
utc.tm_mon = 1 - 1;
utc.tm_mday = 10;
utc.tm_hour = 10;
utc.tm_min = 16;
utc.tm_sec = 03;
utc.tm_isdst = 0;
// Get time_t val for the UTC date/time
tim = timegm(&utc); // or _mkgmtime() on windows
// Now let's use gmtime() to check all is ok
// by retrieving a UTC tm struct and comparing
// with original
utc_out = gmtime(&tim);
assert(utc.tm_year == utc_out->tm_year);
assert(utc.tm_mon == utc_out->tm_mon);
assert(utc.tm_mday == utc_out->tm_mday);
assert(utc.tm_hour == utc_out->tm_hour);
assert(utc.tm_min == utc_out->tm_min);
assert(utc.tm_sec == utc_out->tm_sec);
}

That seems to do the trick, although I am astounded that this isn’t covered by the standard lib. To achieve the same using just the standard lib it seems you have to either hack around with the timezone env. variable before calling mktime() or assume you know how the time_t val is constructed and build your own timegm() function…

Speed up Encoding of JPEG images on Embedded System

Q: How can I speed up encoding & decoding of JPEG images on my embedded system?

A: Use libjpeg-turbo!

If you are encoding JPEG images from code on your embedded system then chances are you are using libjpeg either directly or indirectly. libjpeg is the standard JPEG implementation, and as properly JPEGing images is VERY hard everybody just uses this library. For example, if you save an image from OpenCV, it will use libjpeg under the hood.

libjpeg concentrates on getting the encoding and decoding correct, it doesn’t worry too much about speed or optimisation and so can appear slow, especially on embedded systems.

libjpeg-turbo is a drop in replacement for libjpeg, it supports the exact same API and uses the Intel and ARM Neon SIMD instructions to greatly increase the speed of encoding and decoding.

So next time you are struggling with JPEG speed, don’t listen to those who may mutter insane things about ‘using the GPU’ or some such rubbish, just check out libjpeg-turbo instead, it may well just do the trick, especially if you can arrange to encode your images on more than one core simultaneously!

libjpeg example – encode JPEG to memory buffer instead of file

Q: How can I use libjpeg to encode directly to memory on my embedded system without using a file?

A: If you’re encoding images into JPEG on your ARM/Linux embedded platform then you’re most likely using libjpeg, and if you’re encoding quickly then you’re most likely using its drop-in replacement libjpeg-turbo!

Most of the examples of how to use the libjpeg API show how to encode directly to a file, but it’s also possible to use the API to encode to a memory buffer instead. This is handy if you want to transmit the JPEG via MQTT or something and don’t actually need a JPEG file – you can avoid the overhead of writing to your flash filesystem and having to read the data from it before sending.

Of course, one easy way of achieving this if your embedded system has a RAM disk (as a lot of ARM/Linux based systems will) is to just get libjpeg to encode to file on the RAM disk, in this way you can avoid writing to flash, however you will still have to open the file and read in all of the data into a buffer afterwards.

The trick to getting libjpeg to encode directly to  memory is make a call to jpeg_mem_dest() (instead of to jpeg_stdio_dest() for a file), this allows the caller to specify an output buffer for the jpeg data (as well as its size).

You can either supply a pointer to a buffer, or if you pass NULL, the library will allocate a buffer for you – either way, you must free() the output buffer once you are finished with it!

Some things to note are:

  • You can pass in a pointer to a buffer that you have already malloc()’ed
  • If you pass in NULL, the lib will allocate a buffer for you.
  • If the buffer that you specify (or that the lib automatically malloced()’ed) turns out to be too small to hold the JPEG data then the lib will free() the buffer and malloc() a new one (this will probably also involve a memory copy).
  • After encoding the size variable will contain the number of JPEG bytes in the output buffer (i.e. it no longer contains the size of the buffer used!)
  • If you want to re-use the same buffer for each encode, then just pass in the same buffer pointer each time with it’s original size and don’t free() it after encoding.

Here is an example of a c++ function that encodes to memory, it uses a buffer that’s allocated by the library:

 

//
// Encodes a 256 Greyscale image to JPEG directly to a memory buffer
// libJEPG will malloc() the buffer so the caller must free() it when
// they are finished with it.
//
// image    - the input greyscale image, 1 byte is 1 pixel.
// width    - the width of the input image
// height   - the height of the input image
// quality  - target JPEG 'quality' factor (max 100)
// comment  - optional JPEG NULL-termoinated comment, pass NULL for no comment.
// jpegSize - output, the number of bytes in the output JPEG buffer
// jpegBuf  - output, a pointer to the output JPEG buffer, must call free() when finished with it.
//
void encode_jpeg_to_memory(unsigned char* image, int width, int height, int quality,
                            const char* comment, unsigned long* jpegSize, unsigned char** jpegBuf) {
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    int row_stride;
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    cinfo.image_width = width;
    cinfo.image_height = height;
    // Input is greyscale, 1 byte per pixel
    cinfo.input_components = 1;
    cinfo.in_color_space = JCS_GRAYSCALE;
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    //
    //
    // Tell libJpeg to encode to memory, this is the bit that's different!
    // Lib will alloc buffer.
    //
    jpeg_mem_dest(&cinfo, jpegBuf, jpegSize);
    jpeg_start_compress(&cinfo, TRUE);
    // Add comment section if any..
    if (comment) {
        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET*)comment, strlen(comment));
    }
    // 1 BPP
    row_stride = width;
    // Encode
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &image[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
}

The we can use this function to encode an 8bit image like this:

 

void test_encode_jpeg_to_memory() {
    int width = 1920;
    int height = 1080;
    // Create an 8bit greyscale image
    unsigned char* image = (unsigned char*)malloc(width * height);
    // With a pattern
    for (int j = 0; j != height; j++) {
        for (int i = 0; i != width; i++)
            image[i + j * width] = i + j;
    }
    // Will hold encoded size
    unsigned long jSize = 0;
    // Will point to JPEG buffer
    unsigned char* jBuf = NULL;
    // Encode image
    encode_jpeg_to_memory(image, width, height, 85, "A Comment!", &jSize, &jBuf);
    printf("JPEG size (bytes): %ld", jSize);
    //
    // Now, do something with the JPEG image in jBuf like stream it over UDP or sommit!
    //
    // Free jpeg memory
    free(jBuf);
    // Free original image
    free(image);
}

 

 

Get the Subversion (SVN) URL for a file using Tortoise SVN?

How can I get the Subversion (SVN) URL for a single file using Tortoise SVN?

If you’re still rocking a venerable Subversion (SVN) repository to keep all of your software safe, then Tortoise SVN is a great user-interface to all of the SVN delights,  but how can you easily retrieve or copy an SVN URL to a single file in the repo?  I find that the easiest way to get an SVN URL to a folder is to right-click on the local folder and choose the ‘Repo-browser’ menu option, when the browser shows, the URL can be easily copied from the URL text box at the top of the browser screen.

 

Now, to get the URL for an individual file, just click on the file within the Repo-browser and it’s URL will be displayed in the URL box!

 

Get URL for single file in SVN

 

From here you can copy and paste to the heart’s content!

Fire-And-Forget wrapper for sending simple UDP data using boost::asio libraries

So I had a problem, as part of an embedded software system I was working on I needed to periodically send some GPS information via UDP datagrams to other devices on the network – really simple stuff, transmit a string to an IP address on a given port, Fire And Forget, send a string from here to there – end of story!

Now my normal port of call these days for networking in C++ is to reach for the boost::asio libs, as mentioned here, this library is very powerful and flexible and can handle a huge number of different networking scenarios.

All well and good, but sometimes I wish that I could just call a simple function and not have to remember or worry about all of boost stuff as it can be a proper head-wreck and there’s a lot of typing as the namespaces are so long! Python has me really spoiled, it makes so many things simple and easy to use!

So I wrote a little C++ wrapper class that just has 1 function called send() that can send a string or the contents of a binary buffer, the class is called: boost_udp_send_faf (faf stands for Fire-and-Forget!).

It is a very basic wrapper around the boost libs and only handles very simple transmission use-cases, but these use-cases probably cover about 80% of my UDP transmission needs!

To use the class for a single Fire-and-Forget send:

//
#include "boost_udp_send_faf.h"
boost_udp_send_faf("192.168.1.44", 8861).send("The message!");
//

This sends the message to 192.168.1.44 on port 8861.

If your program needs send multiple datagrams, then we can keep the socket open and reuse the end-point like this:

//
#include "boost_udp_send_faf.h"
boost_udp_send_faf sender("192.168.1.44", 8861);
for (auto i = 0; i != 10; i++) { sender.send("Lots of messages! :-/"); }
//

The socket will remain open until the ‘sender’ object goes out of scope.

It’s probably best to add exception handling to your calls as they can fail for lots of reasons and as ever networking is very flaky & unpredictable.

//
try {
    boost_udp_send_faf("192.168.1.44", 8861).send("The message!");
} catch (const boost::system::system_error& ex) { cerr << "Send failed: " << ex.what(); }
//

This will also ensure that the socket is closed once the message is sent as the object will go out of scope when execution leaves the try block.

The code for boost_udp_send_faf can be found in this repo on GitHub, but I have in-lined it below as well.

For an easier way to receive UDP data see: boost_udp_receive_rar

 

#pragma once
//   Copyright 2018 Kevin Godden
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#include <boost/asio.hpp>
#include <string>
//
// Fire-and-Forget (FAF) transmission for UDP
// using the boost::asio lib. Very simple wrapper
// around the boost libs.
//
// Can throw the following exception:
//	boost::system::system_error
//
// Synopsis --->
//
// For a single Fire-and-Forget send:
//
// #include "boost_udp_send_faf.h"
//
// boost_udp_send_faf("192.168.1.44", 8861).send("The message!");
//
//
// To send multiple datagrams while keeping the socket open and
// reusing end-point:
//
// #include "boost_udp_send_faf.h"
//
// boost_udp_send_faf sender("192.168.1.44", 8861);
//		
// for (auto i = 0; i != 10; i++) {
//     sender.send("Lots of messages! :-/");
// }
//
// The socket will remain open while the boost_udp_send_faf object is in scope
// so to control when the socket is closed, control the scope of the object.
//
// If you want to do anything fancy like using scatter-gather buffers etc. then
// just use the boost libs!  This is for real simple stuff!
//

class boost_udp_send_faf {
    boost::asio::io_service io_service;
    boost::asio::ip::udp::socket socket;
    boost::asio::ip::udp::endpoint remote_endpoint;
public:
    boost_udp_send_faf(const std::string& ip_address, const int port, const bool broadcast = false) : socket(io_service) {
        
        // Open socket
        socket.open(boost::asio::ip::udp::v4());
        // I wouldn't recommend broadcasting unless you are
        // in complete control of your subnet and know
        // what's on it and how it will react
        if (broadcast) {
            boost::asio::socket_base::broadcast option(true);
            socket.set_option(option);
        }
        // make endpoint
        remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(ip_address.c_str()), port);
    }
    // Send a string to the preconfigured endpoint
    // via the open socket.
    void send(const std::string& message) {
        boost::system::error_code ignored_error;
        socket.send_to(boost::asio::buffer(message), remote_endpoint, 0, ignored_error);
    }
    // Send some binary data to the preconfigured endpoint
    // via the open socket.
    void send(const unsigned char* data, const int len) {
        boost::system::error_code ignored_error;
        socket.send_to(boost::asio::buffer(data, len), remote_endpoint, 0, ignored_error);
    }
};