Timestamps for embedded system
If you have C++11
you can use the <chrono>
and <ctime>
library like this:
#include <ctime>
#include <string>
#include <chrono>
#include <sstream>
#include <iomanip>
#include <iostream>
// use strftime to format time_t into a "date time"
std::string date_time(std::time_t posix)
{
char buf[20]; // big enough for 2015-07-08 10:06:51\0
std::tm tp = *std::localtime(&posix);
return {buf, std::strftime(buf, sizeof(buf), "%F %T", &tp)};
}
std::string stamp()
{
using namespace std;
using namespace std::chrono;
// get absolute wall time
auto now = system_clock::now();
// find the number of milliseconds
auto ms = duration_cast<milliseconds>(now.time_since_epoch()) % 1000;
// build output string
std::ostringstream oss;
oss.fill('0');
// convert absolute time to time_t seconds
// and convert to "date time"
oss << date_time(system_clock::to_time_t(now));
oss << '.' << setw(3) << ms.count();
return oss.str();
}
int main()
{
std::cout << stamp() << '\n';
}
Output:
2015-07-08 10:13:29.930
Note:
If you want higher resolution you can use microseconds
like this:
std::string stamp()
{
using namespace std;
using namespace std::chrono;
auto now = system_clock::now();
// use microseconds % 1000000 now
auto us = duration_cast<microseconds>(now.time_since_epoch()) % 1000000;
std::ostringstream oss;
oss.fill('0');
oss << date_time(system_clock::to_time_t(now));
oss << '.' << setw(6) << us.count();
return oss.str();
}
Output:
2015-07-08 10:20:39.454163
What timestamp would have the best space efficiency with a 10 year span and 1 second resolution?
i need to represent next minimum 10 years with resolution of second
If you use an int32_t
you're good until 2038 with these timestamps, and with uint32_t
you can cover until 2106. Using localtime
, gmtime
and such you can convert them into struct tm
if you need and extract the day, month etc.
Problem with time() function in embedded application with C
Is there a replacement for this function?
The available source of time is hardware dependent, and the library is hardware independent. As such you have to provide implementations for library functions with hardware dependencies yourself, or they may be included in a vendor provided board-support package (BSP) in some cases. The header time.h provides the standard declaration your implementation must conform to, while the library in this case provides a default implementation that is not fully functional.
If you are using armcc (as used in the Keil ARM MDK for example), then the default time()
implementation uses semi-hosting. That is it obtains time from the development host rather then than the target hardware.
Semi-hosting will work only when debugging while connected to a debug host. However in that case time()
should return -1 rather than a processor restart. This function is not the cause of the restart - you could demonstrate that by removing it, and the restart will still occur. The restart is simply that you explicitly return from main()
- what else is the runtime supposed to do? It will either restart directly or it may enter a busy loop, where a watchdog timer expiry might restart it. It depends on your C run-time environment implementation. Moreover the behaviour may differ depending on whether the debugger is connected or not; it is possible to determine when the on-chip debug is active and to conditionally execute a break-point instruction for example to interrupt the debugger.
To have time()
work correctly with your target hardware rather than use semi-hosting, you must re-implement it. It is defined as a weak-link and any implementation you provide will override the default, so somewhere in your project you must have a function:
#include <time.h>
time_t time( time_t* timep )
{
int hour = 0 ;
int minute = 0 ;
int second = 0 ;
int day_of_month = 0 ;
int month = 0 ;
int year = 0 ;
// Your code here to fill time/date from clock source
...
// Normalise to time.h library epoch time_t (normally Unix epoch)
struct tm timeinfo;
timeinfo.tm_mon = month - 1 ; // check assumption here Jan = 0 in tm
timeinfo.tm_mday = day_of_month ;
timeinfo.tm_year = year + 100 ; // check assumption here years start from 1900 in tm
timeinfo.tm_hour = hour ;
timeinfo.tm_min = minute;
timeinfo.tm_sec = second;
// Convert to timestamp
time_t t = mktime(&timeinfo);
if( timep != NULL )
{
*timep = t ;
}
return t;
}
If your time source requires any kind of initialisation before it will work, you can do that in a number of ways, for example:
- Place the initialisation code in the run-time start-up code that runs before
main()
. For example your start-up code may have a function calledSysInit()
or similar where you should do this. - Require the developer to perform necessary initialisation before
time()
is used. - Initialise on first use by modifying the
time()
function as below :
#include <time.h>
#include <stdbool.h>
time_t time( time_t* timep )
{
static bool initialised = false ;
if( !initialised )
{
initialised = true ;
// your clock source initialisation here
...
}
...
This last method is probably the simplest and least error prone and does not saddle the system with code that it might not need if the application does not use time()
.
Your example code includes stdio.h but does not use it, but note that the default stdio implementation similarly relies on semi-hosting, and may need re-targetting
Python embedded. timestamp() return same time over multiple seconds
The type of a timestamp
is float
, which is a floating point type of the width of the Python build. A 32-bit float is not sufficient to express the timestamp with second precision:
>>> import struct
>>> def as_f32(num: float): return struct.unpack('f', struct.pack('f', num))[0]
>>> def as_f64(num: float): return struct.unpack('d', struct.pack('d', num))[0]
>>> # 32-bit expressible timestamps in a 10 second range
>>> set(map(as_f32, range(1614270075, 1614270085)))
{1614270080.0}
>>> # 64-bit expressible timestamps in a 10 second range
>>> set(map(as_f64, range(1614270075, 1614270085)))
{1614270075.0, 1614270076.0, 1614270077.0, 1614270078.0, 1614270079.0, 1614270080.0, 1614270081.0, 1614270082.0, 1614270083.0, 1614270084.0}
Use a 64-bit build if the full precision is needed.
How do you measure the time a function takes to execute?
The best way to do that on an embedded system is to set an external hardware pin when you enter the function and clear it when you leave the function. This is done preferably with a little assembly instruction so you don't skew your results too much.
Edit: One of the benefits is that you can do it in your actual application and you don't need any special test code. External debug pins like that are (should be!) standard practice for every embedded system.
How to sign a PDF with embedded timestamp and LTV enabled?
First, based on @mkl comment, I added the TSA server certificate to the Adobe Trusted Certificates so that the message
the signature includes an embedded timestamp but it could not be
verified
became
the signature includes an embedded timestamp
And to solve
Signature is not LTV enabled and will expire after (...)
I could note that using
List<CrlClient> crlList = new ArrayList<>();
crlList.add(new CrlClientOnline(chain));
there were some CRL's (some of the certificates had more than one distribution point) not being added - making the pdf LTV not enabled. To solve it I've done this way:
// long term validation (LTV)
List<CrlClient> crlList = new ArrayList<>();
for(Certificate cert : chain) {
X509Certificate c = (X509Certificate)cert;
List<String> crls = this.getCrlDistributionPoints(c);
if(crls != null && !crls.isEmpty()) {
crlList.add(new CrlClientOnline(crls.toArray(new String[crls.size()])));
}
}
private List<String> getCrlDistributionPoints(final X509Certificate cert) throws Exception {
final byte[] crldpExt = cert.getExtensionValue(X509Extension.cRLDistributionPoints.getId());
if (crldpExt == null) {
final List<String> emptyList = new ArrayList<String>();
return emptyList;
}
ASN1InputStream oAsnInStream = null;
ASN1InputStream oAsnInStream2 = null;
List<String> crlUrls = new ArrayList<String>();
try {
oAsnInStream = new ASN1InputStream(new ByteArrayInputStream(crldpExt));
final ASN1Object derObjCrlDP = oAsnInStream.readObject();
final DEROctetString dosCrlDP = (DEROctetString) derObjCrlDP;
final byte[] crldpExtOctets = dosCrlDP.getOctets();
oAsnInStream2 = new ASN1InputStream(new ByteArrayInputStream(crldpExtOctets));
final ASN1Object derObj2 = oAsnInStream2.readObject();
final CRLDistPoint distPoint = CRLDistPoint.getInstance(derObj2);
for (final DistributionPoint dp : distPoint.getDistributionPoints()) {
final DistributionPointName dpn = dp.getDistributionPoint();
// Look for URIs in fullName
if (dpn != null) {
if (dpn.getType() == DistributionPointName.FULL_NAME) {
final GeneralName[] genNames = GeneralNames.getInstance(dpn.getName()).getNames();
// Look for an URI
for (int j = 0; j < genNames.length; j++) {
if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier) {
final String url = DERIA5String.getInstance(genNames[j].getName()).getString();
crlUrls.add(url);
}
}
}
}
}
} catch(IOException e) {
throw new Exception(e.getMessage(), e);
} finally {
IOUtils.closeQuietly(oAsnInStream);
IOUtils.closeQuietly(oAsnInStream2);
}
return crlUrls;
}
Related Topics
C++ Convert from Lpctstr to Const Char *
Why Does Sizeof(Int) Vary Across Different Operating Systems
Stoi and Std::To_String on Mingw 4.7.1
Image Retrieval System by Colour from the Web Using C++ with Openframeworks
Why Are Std::Atomic Objects Not Copyable
Exception Error C0000005 in Vc++
Why Are the Return Values of These Doubles -1.#Ind
How to Omit the Double-Braces for Std::Array in C++14
Undefined Reference to Mempcy@Glibc_2.14 When Compiling on Linux
In Which Access Control Context Are Concepts Evaluated
Ordering of Using Namespace Std; and Includes
Why Should I Avoid MACros in C++