How to fix SCons error: Do not know how to make File target `clean’

Problem:

You are trying to clean your SCons build using

scons clean

but you see the following error message:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: *** Do not know how to make File target `clean' (/home/user/myproject/clean).  Stop.
scons: building terminated because of errors.

Solution:

When using SCons, the correct command to clean is

scons --clean

 

Posted by Uli Köhler in Build systems, SCons

How to force GCC/G++ to provide colored output

Just add the

-fdiagnostics-color=always

compiler flag

Posted by Uli Köhler in C/C++

How to fix SCons not providing colored GCC/C++ output

You can force SCons to provide colored output when using GCC or G++ by adding

-fdiagnostics-color=always

to your CFLAGS or CXXFLAGS. Typically, my recommendation is to add it to both CFLAGS and CXXFLAGS.

Posted by Uli Köhler in Build systems, SCons

Minimal CMake .gitignore

# CMake generated files
build/
CMakeCache.txt
CMakeFiles/
Makefile
cmake_install.cmake
install_manifest.txt

 

Posted by Uli Köhler in CMake, git

Minimal C++ SLIP encoder operating on buffers

The following encoder can be used to encode frames into a byte stream. It operates on complete buffers (i.e. this is not a streaming encoder) but is fast and easy to use.

/*
 * Author: Uli Köhler - techoverflow.net
 * License: CC0 1.0 Universal
 *
 * Description:
 * This is a C++ implementation of a buffer-based SLIP encoder.
 * It can be used to encode frames unambiguously into a stream of bytes.
 * The encoder does not use any memory allocation, but instead requires
 * the caller to provide a buffer for the encoded data - hence being
 * ideally suited for use in embedded systems
 */
#pragma once
#include <cstdint>
#include <cstddef>

#define SLIP_END             ((uint8_t)0300)   // SLIP end of packet character
#define SLIP_ESC             ((uint8_t)0333)   // SLIP escape character
#define SLIP_ESCEND         ((uint8_t)0334)    // Escaped END data byte
#define SLIP_ESCESC         ((uint8_t)0335)    // Escaped ESC data byte

// Return value of slip_encode_packet if the output buffer is not large enough
#define SLIP_ENCODE_ERROR SIZE_MAX // Maximum value of size_t

/**
 * Determine the packet length when sending the given buffer [p] using SLIP.
 * This DOES NOT ENCODE ANYTHING, it just determines the length
 * which an encoded version of the data would have
 * @return The number of bytes a SLIP encoded version of [in] would consume
 */
size_t slip_packet_length(const uint8_t* in, size_t inlen);

/**
 * Encode given input data using SLIP, saving it into the given output buffer.
 * WARNING! The output buffer MUST have a length of at least the return value of
 *    slip_packet_len(in, inlen)
 * In case the output buffer is not large enough, this function will return SLIP_ENCODE_ERROR and
 * the output buffer will be left in an undefined space.
 * Take special care that the input data does not change between the calls to
 * slip_packet_len() and slip_encode_packet()
 * @return The number of bytes in [out], or SLIP_ENCODE_ERROR
 */
size_t slip_encode_packet(const uint8_t* in, size_t inlen, uint8_t* out, size_t outlen);
/*
 * Author: Uli Köhler - techoverflow.net
 * License: CC0 1.0 Universal
 *
 * Description:
 * This is a C++ implementation of a buffer-based SLIP encoder.
 * It can be used to encode frames unambiguously into a stream of bytes.
 * The encoder does not use any memory allocation, but instead requires
 * the caller to provide a buffer for the encoded data - hence being
 * ideally suited for use in embedded systems
 */
#include "SLIPEncoder.hpp"

size_t slip_packet_length(const uint8_t* in, size_t inlen) {
    // This variable contains the length of the data
    size_t outlen = 0;
    const uint8_t* inend = in + inlen; // First character AFTER the
    for (; in < inend ; in++) {
        switch (*in) {
        case SLIP_END: // Need to escape END character to avoid RX seeing end of frame
            // Same as "case SLIP_ESC" so just continue.
        case SLIP_ESC: // Need to escape ESC character, we'll send
            outlen += 2; // Will send ESC + ESCESC
            break;
        default: // Any other character => will just copy
            outlen++; // Will only send the given character
        }
    }
    // + 1: SLIP END bytes
    return outlen + 1;
}

size_t slip_encode_packet(const uint8_t* in, size_t inlen, uint8_t* out, size_t outlen) {
    // This variable contains the length of the data
    uint8_t* out_start = out; // We will increment [out], hence copy the original value.

    // Output buffer must be AT LEAST as long as input data (sanity check)
    if(outlen < inlen) {
        return SLIP_ENCODE_ERROR;
    }

    uint8_t* outend = out + outlen; // First character AFTER the
    const uint8_t* inend = in + inlen; // First character AFTER the
    for (; in < inend ; in++) {
        switch (*in) {
        case SLIP_END: // Need to escape END character to avoid RX seeing end of frame
            // Check out of bounds memory acces
            if(out + 2 >= outend) {
                return SLIP_ENCODE_ERROR;
            }
            // Copy escaped END character
            *out++ = SLIP_ESC;
            *out++ = SLIP_ESCEND;
            break;
        case SLIP_ESC: // Need to escape ESC character, we'll send
            // Check out of bounds memory access
            if(out + 2 >= outend) {
                return SLIP_ENCODE_ERROR;
            }
            // Copy escaped END character
            *out++ = SLIP_ESC;
            *out++ = SLIP_ESCESC;
            break;
        default: // Any other character => just copy the character
            if(out + 1 >= outend) {
                return SLIP_ENCODE_ERROR;
            }
            *out++ = *in;
        }
    }
    // Check out of bounds access for END byte
    if(out + 1 > outend) { // NOTE: > instead of >= since there is only ONE character to be written
        return SLIP_ENCODE_ERROR;
    }
    // Insert END byte
    *out++ = SLIP_END;
    // Return number of bytes
    return (out - out_start);
}

 

 

Posted by Uli Köhler in C/C++

How to fix C++ error: invalid use of template-name ‘std::chrono::time_point’ without an argument list

Problem:

You are trying to use std::chrono::time_point in your C++ code, but the compiler throws an error message like

MyClass.hpp:58:5: error: invalid use of template-name ‘std::chrono::time_point’ without an argument list
   58 |     std::chrono::time_point t0;

Solution:

std::chrono::time_point is a template that requires two template arguments: the clock and the duration. The duration argument, however, defaults to Clock::duration so you only have to explicitly specify the clock.

Typically you can just use std::chrono::system_clock:

std::chrono::time_point<std::chrono::system_clock> t0;

 

Posted by Uli Köhler in C/C++, GCC errors

How to generate filename based on current date & time in C++ using chrono

Problem:

You want to generate a filename, e.g., for datalogging, that contains the current date and time in C++ – for example:

2023-04-22_19-38-34.csv

Solution:

To generate a filename with the current date and time in C++, you can use the chrono library to get the current time and format it as a string. Here’s a code snippet that shows how to do this:

#include <chrono>
#include <iomanip>
#include <sstream>

std::string GetFilenameByCurrentDate(const char* extension=".bin") {
    // Get the current time
    auto now = std::chrono::system_clock::now();

    // Convert to local time
    auto localTime = std::chrono::system_clock::to_time_t(now);

    // Format the timestamp as a string
    std::stringstream ss;
    ss << std::put_time(std::localtime(&localTime), "%F_%H-%M-%S") << extension;
    return ss.str();
}

 

This function takes an optional extension parameter that specifies the file extension to use (by default, “.bin”). It uses the chrono library to get the current time (now), convert it to local time (localTime), and format it as a string (ss). The put_time function is used to format the time as a string in the format “%F_%H-%M-%S”, which represents the date and time in ISO 8601 format (e.g., 2023-04-23_19-13-22).

This will produce a filename such as 2023-04-23_19-13-22.bin, which can be used to create a new file or to store data in an existing file. By including a timestamp in the filename, you can easily keep track of when the file was created and quickly identify files that were created at a particular time.

Posted by Uli Köhler in C/C++

How to fix C++ error: no member named ‘put_time’ in namespace ‘std’

Problem:

You are trying to use the std::put_time function in your C++ application, but you get the following compiler error message:

main.cpp:17:16: error: no member named 'put_time' in namespace 'std'
    ss << std::put_time(std::localtime(&localTime), "%F_%H-%M-%S") << extension;
          ~~~~~^

Solution:

The std::put_time function is part of the <iomanip> header in C++, so you need to include this header in your code to use this function. Add the following code at the top of the file where the error occurs:

#include <iomanip>

Full example:

#include <iostream>
#include <iomanip>
#include <chrono>

int main() {
    auto now = std::chrono::system_clock::now();
    auto localTime = std::chrono::system_clock::to_time_t(now);
    std::cout << std::put_time(std::localtime(&localTime), "%F %T") << std::endl;
    return 0;
}

 

Posted by Uli Köhler in C/C++, GCC errors

How to fix GCC error: implicit instantiation of undefined template ‘std::basic_stringstream<char>’

Problem:

When trying to compile your C++ application, you see an error message such as

main.cpp:15:23: error: implicit instantiation of undefined template 'std::basic_stringstream<char>'
    std::stringstream ss;
                      ^

Solution:

At the top of the file where this error occurs, add the following line:

#include <sstream>

 

Posted by Uli Köhler in C/C++, GCC errors

How to monitor storj storage node satellite exit status using docker-compose

First try

docker-compose exec storagenode /app/storagenode exit-status --identity.cert-path /app/identity/identity.cert --identity.key-path /app/identity/identity.key

or for older storj versions use

docker-compose exec storagenode /app/storagenode exit-status --identity-dir /app/identity

 

Posted by Uli Köhler in Networking

How to fix Python “match” statement: SyntaxError: invalid syntax

Problem:

Your Python script crashes with SyntaxError: invalid syntax at a match statement, e.g.:

  File "main.py", line 234
    match param:
          ^
SyntaxError: invalid syntax

Solution:

Match statement exist since Python 3.10 – you are using a Python 3.9 or earlier version. You either need to upgrade your Python to 3.10 or later, or rewrite the code and remove the match statement!

Posted by Uli Köhler in Python

How to fix Angular ROR Error: ngIfElse must be a TemplateRef, but received ‘[object HTMLDivElement]’.

Problem:

Your Angular template looks like this:

<div *ngIf="files.length > 0 ; else noFiles">
    <!-- ... -->
</div>
<div #noFiles>
    <!-- ... -->
</div>

but when you open it in the browser, you see the following stacktrace:

c_my_module.js:2 ERROR Error: ngIfElse must be a TemplateRef, but received '[object HTMLDivElement]'.
    at assertTemplate (common.mjs:3392:15)
    at set ngIfElse [as ngIfElse] (common.mjs:3328:9)
    at setInputsForProperty (core.mjs:11741:34)
    at elementPropertyInternal (core.mjs:10874:9)
    at ɵɵproperty (core.mjs:13637:9)
    at PlanungsunterlagenDashboardComponent_Template (planungsunterlagen-dashboard.component.html:8:55)
    at executeTemplate (core.mjs:10534:9)
    at refreshView (core.mjs:10419:13)
    at refreshComponent (core.mjs:11480:13)
    at refreshChildComponents (core.mjs:10210:9)

Solution:

The error message is telling you that #noFiles is a <div> but it must be a <ng-template>:

In order to fix it, change it to a ng-template:

<ng-template #noFiles>
    <!-- ... -->
</ng-template>

If you need a <div> specifically, you need to place it inside the ng-template:

<ng-template #noFiles>
    <div>
        <!-- ... -->
    </div>
</ng-template>

 

Posted by Uli Köhler in Angular, Javascript

How to fix docker NodeJS container not shutting down

When you are running a NodeJS server inside a docker container, you will often encouter the issue that the container does not shutdown properly but taking a long time (several minutes) to shutdown.

In order to fix this, add the following code to your main NodeJS file (typically you should add it at the top of the file to make sure nothing prevents it from getting executed)

process.on('SIGTERM', function() {
  console.log('SIGTERM received, shutting down...');
  process.exit(0);
});
process.on('SIGINT', function() {
  console.log('SIGINT received, shutting down...');
  process.exit(0);
});

This will force NodeJS to exit (more or less immediately) once either SIGINT or SIGTERM is received. Typically, Docker sends SIGTERM on container shutdown.

Background information

See this GitHub guide

Posted by Uli Köhler in NodeJS

How to cross-compile native C++ executable for Teltonika RUTX10 / RUTX11

First, download the pre-configure OpenWRT buildroot from Teltonika.

Unzip it:

tar xzvf RUTX_R_GPL_00.07.04.1.tar.gz
cd rutos-ipq40xx-rutx-gpl/

and now build using

./scripts/feeds update -a
make -i

This will build not only the toolchain but also all packages etc, hence it will take a while.

Now create main.cpp, e.g.:

#include <iostream>

int main(int argc, char** argv) {
    std::cout << "Hello World!" <<std::endl;
}

The build script build.sh looks like this:

#!/bin/sh
export STAGING_DIR=~/rutos-ipq40xx-rutx-gpl/staging_dir
export TOOLCHAIN=${STAGING_DIR}/toolchain-arm_cortex-a7+neon-vfpv4_gcc-8.4.0_musl_eabi
export CC=${TOOLCHAIN}/bin/arm-openwrt-linux-muslgnueabi-gcc
export CPP=${TOOLCHAIN}/bin/arm-openwrt-linux-muslgnueabi-g++

# Build !
${CPP} -o main main.cpp

This will produce main , an executable which you can copy to and run on your RUTX10.

 

Posted by Uli Köhler in OpenWRT

How to enable verbose output while compiling OpenWRT

You will see verbose output (compiler calls etc) during an OpenWRT build if you call make with the V=s flag:

make V=s

 

Posted by Uli Köhler in OpenWRT

Teltonika RUTX10 /proc/cpuinfo

processor       : 0
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 96.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

processor       : 1
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 96.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

processor       : 2
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 96.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

processor       : 3
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 96.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

Hardware        : Generic DT based system
Revision        : 0000
Serial          : 0000000000000000

 

Posted by Uli Köhler in Networking

JLCPCB: Which milling tool radius is used for internal cutouts?

On 2023-04-23 I asked the JLCPCB support which milling tool radius is used for internal cutouts.

They answered that normally they use 0.5mm milling tool radius, leading to a minimum internal cutout width of 1mm.

Posted by Uli Köhler in Electronics

How to compute Buck/Boost/LDO output voltage by feedback resistors using Python

You can use the UliEngineering library in order to compute the output voltage of your voltage converter.

First, you need to know Vfb, the feedback voltage of your converter IC, which you need to read from the datasheet. For this example, we’ll use the AP3012‘s feedback voltage of 1.25V.

from UliEngineering.Electronics.VoltageDivider import feedback_actual_voltage
from UliEngineering.EngineerIO import auto_format


# Compute voltage
output_voltage = feedback_actual_voltage("220k", "12.1k", vfb="1.25V")
# output_voltage == 23.97727272727273

# ... or format and print it
auto_format(feedback_actual_voltage, "220k", "12.1k", vfb="1.25V") #  Prints "24.0V"

 

Posted by Uli Köhler in Electronics, Python

How to construct C++ chrono::time_point from a milliseconds-since-epoch timestamp

#include <chrono>

size_t myMillisecondsSinceEpochTimestamp = 1680978404374;
std::chrono::time_point<std::chrono::system_clock> myChronoTimestamp(
    std::chrono::milliseconds(myMillisecondsSinceEpochTimestamp)
);

 

Posted by Uli Köhler in C/C++

heatshrink compression library: How to compress data from a buffer

This is a starting point for how to compress data from a buffer using heatshrink and write the data into an output buffer:

Note that this has not been thoroughly tested, but at least it doesn’t crash 🙂

// TODO Your code goes here
const size_t outbuf_size = filesize + 128;
char* outbuf = new char[outbuf_size];
heatshrink_encoder* encoder = heatshrink_encoder_alloc(10, 4);
size_t tosink = filesize;
size_t output_size = 0;
while(tosink > 0) {
    size_t sunk = 0;
    auto err = heatshrink_encoder_sink(encoder, reinterpret_cast<uint8_t*>(buf), (size_t)filesize, &sunk);
    if(err != HSER_SINK_OK) {
        std::cerr << "Error sinking data" << std::endl;
        break;
    }
    if(sunk == 0) {
        std::cerr << "No data sunk" << std::endl;
        break;
    }
    // Check how much has been sunk & update tosink
    tosink -= sunk;
    // Poll for output
    size_t polled = 0;
    auto err2 = heatshrink_encoder_poll(encoder, reinterpret_cast<uint8_t*>(outbuf + output_size), outbuf_size - output_size, &polled);
    if(err2 == HSER_POLL_ERROR_NULL || err2 == HSER_POLL_ERROR_MISUSE) {
        std::cerr << "Error polling data" << std::endl;
        break;
    }
    output_size += polled;
}
// Input data finished
auto err3 = heatshrink_encoder_finish(encoder);
// Poll for final output
// Poll for output
size_t polled = 0;
auto err2 = heatshrink_encoder_poll(encoder, reinterpret_cast<uint8_t*>(outbuf + output_size), outbuf_size - output_size, &polled);
if(err2 == HSER_POLL_ERROR_NULL || err2 == HSER_POLL_ERROR_MISUSE) {
    std::cerr << "Error finally polling data" << std::endl;
}
output_size += polled;

cout << "Original size: " << filesize << ", compressed size: " << output_size << endl;

 

Posted by Uli Köhler in C/C++, Embedded
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPTPrivacy &amp; Cookies Policy