icsneolegacy: Implemented get() and set() RTC functions

pull/56/head
Joseph Niksa 2023-04-20 18:37:05 +00:00
parent af31aa23ad
commit b3bbf91e8c
10 changed files with 229 additions and 13 deletions

View File

@ -689,3 +689,28 @@ bool icsneo_setTerminationFor(const neodevice_t* device, neonetid_t netid, bool
return device->device->settings->setTerminationFor(Network(netid), enabled);
}
bool icsneo_getRTC(const neodevice_t* device, uint64_t* output)
{
if(!icsneo_isValidNeoDevice(device))
return false;
const std::optional<std::chrono::time_point<std::chrono::system_clock>> rtc = device->device->getRTC();
if(!rtc)
return false;
auto duration = std::chrono::duration_cast<std::chrono::seconds>(rtc->time_since_epoch());
*output = static_cast<uint64_t>(duration.count());
return true;
}
bool icsneo_setRTC(const neodevice_t* device, uint64_t input)
{
if(!icsneo_isValidNeoDevice(device))
return false;
std::chrono::seconds duration(input);
const std::chrono::system_clock::time_point time(duration);
return device->device->setRTC(time);
}

View File

@ -20,6 +20,7 @@
#ifdef _MSC_VER
#pragma warning(disable : 4100) // unreferenced formal parameter
#pragma warning(disable : 4996) // STL time functions
#endif
using namespace icsneo;
@ -559,6 +560,54 @@ void LegacyDLLExport icsneoSetISO15765RxParameters(void* hObject, int lNetwork,
return;
}
int LegacyDLLExport icsneoGetRTC(void* hObject, icsSpyTime* time)
{
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
uint64_t time64 = 0;
if(!icsneo_getRTC(device, &time64))
return false;
std::time_t seconds = time64;
/* To accommodate local time bugzilla #6600 https://intrepidcs.homeip.net:100/bugzilla/show_bug.cgi?id=6600 */
// local time must be used here
const auto timeInfo = std::localtime(&seconds);
if(!timeInfo)
return false;
time->sec = (unsigned char)timeInfo->tm_sec; // Will never hit 60 (leap second) because tm_sec comes from RTCCTIME
time->min = (unsigned char)timeInfo->tm_min;
time->hour = (unsigned char)timeInfo->tm_hour;
time->day = (unsigned char)timeInfo->tm_mday;
time->month = (unsigned char)timeInfo->tm_mon + 1;
time->year = (unsigned char)timeInfo->tm_year % 100;
return true;
}
int LegacyDLLExport icsneoSetRTC(void* hObject, const icsSpyTime* time)
{
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
std::tm timeInfo{};
timeInfo.tm_sec = time->sec;
timeInfo.tm_min = time->min;
timeInfo.tm_hour = time->hour;
timeInfo.tm_mday = time->day;
timeInfo.tm_mon = time->month - 1;
timeInfo.tm_year = time->year + 100;
#ifdef _MSC_VER
#define timegm _mkgmtime
#endif
return icsneo_setRTC(device, (uint64_t)timegm(&timeInfo));
}
//Device Functions
int LegacyDLLExport icsneoGetConfiguration(void* hObject, unsigned char* pData, int* lNumBytes)
{

View File

@ -1,20 +1,27 @@
#include "icsneo/device/device.h"
#include "icsneo/communication/message/callback/messagecallback.h"
#include <sstream>
#include "icsneo/api/eventmanager.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/device/device.h"
#include "icsneo/device/extensions/deviceextension.h"
#include "icsneo/disk/fat.h"
#include "icsneo/communication/packet/wivicommandpacket.h"
#include "icsneo/communication/message/wiviresponsemessage.h"
#include "icsneo/communication/message/scriptstatusmessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include <string.h>
#include <iostream>
#include <sstream>
#include <chrono>
#ifdef _MSC_VER
#pragma warning(disable : 4996) // STL time functions
#endif
using namespace icsneo;
struct RTCCTIME {
uint8_t FracSec;// --- fractions of seconds (00-99). Note that you can write only 0x00 here!
uint8_t Sec;// --- Seconds (00-59)
uint8_t Min;// --- (00-59)
uint8_t Hour;// --- (00-23)
uint8_t DOW;// --- (01-07)
uint8_t Day;// --- (01-31)
uint8_t Month;// --- (01-12)
uint8_t Year;// --- (00-99)
};
static const uint8_t fromBase36Table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15,
@ -1686,3 +1693,62 @@ std::optional<bool> Device::SetCollectionUploaded(uint32_t collectionEntryByteAd
// Valid device with a properly formed respose, return success
return std::make_optional<bool>(success);
}
std::optional<std::chrono::time_point<std::chrono::system_clock>> Device::getRTC()
{
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::RED_GET_RTC);
std::shared_ptr<Message> generic = com->waitForMessageSync([this]() {
return com->sendCommand(Command::GetRTC);
}, filter, std::chrono::milliseconds(3000));
if(!generic) // Did not receive a message
return std::nullopt;
auto rawMes = std::dynamic_pointer_cast<RawMessage>(generic);
if(!rawMes)
return std::nullopt;
if(rawMes->data.size() != sizeof(RTCCTIME))
return std::nullopt;
const auto* time = (RTCCTIME*)rawMes->data.data();
std::tm stdTime = {};
// std::tm has no member for the `FracSec` member of RTCCTIME struct
stdTime.tm_sec = time->Sec;
stdTime.tm_min = time->Min;
stdTime.tm_hour = time->Hour;
stdTime.tm_mday = time->Day;
stdTime.tm_mon = time->Month - 1; // [0-11]
stdTime.tm_year = time->Year + 100; // Number of years since 1900+100
stdTime.tm_wday = time->DOW;
// RTCCTIME struct has no member for `tm_yday`
#ifdef _MSC_VER
#define timegm _mkgmtime
#endif
return std::chrono::system_clock::from_time_t(timegm(&stdTime));
}
bool Device::setRTC(const std::chrono::time_point<std::chrono::system_clock>& time)
{
auto now = std::chrono::system_clock::to_time_t(time);
const auto timeInfo = std::gmtime(&now);
if(!timeInfo)
return false;
// Populate the RTCCTIME struct using the timeInfo and offsets
// Create a vector of arguments to send as the payload to the communication command
std::vector<uint8_t> bytestream(sizeof(RTCCTIME));
auto rtcVals = (RTCCTIME*)bytestream.data();
rtcVals->FracSec = (uint8_t)0X00;
rtcVals->Sec = (uint8_t)timeInfo->tm_sec;
rtcVals->Min = (uint8_t)timeInfo->tm_min;
rtcVals->Hour = (uint8_t)timeInfo->tm_hour;
rtcVals->DOW = (uint8_t)timeInfo->tm_wday + 1;
rtcVals->Day = (uint8_t)timeInfo->tm_mday;
rtcVals->Month = (uint8_t)timeInfo->tm_mon + 1; // [0-11]
rtcVals->Year = (uint8_t)timeInfo->tm_year % 100; // divide by 100 and take remainder to get last 2 digits of year
com->sendCommand(Command::SetRTC, bytestream);
return true;
}

View File

@ -5,6 +5,10 @@
#include "icsneo/icsneocpp.h"
#ifdef _MSC_VER
#pragma warning(disable : 4996) // STL time functions
#endif
int main() {
// Print version
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
@ -118,6 +122,36 @@ int main() {
}
std::cout << "OK" << std::endl;
// Set the real time clock on the device using the system clock
// First, let's see if we can get the time from the device (if it has an RTC)
std::cout << "\n\tChecking and setting the RTC on the device" << std::endl;
auto dTime = device->getRTC();
if (dTime.has_value()) {
std::time_t time = std::chrono::system_clock::to_time_t(dTime.value());
const auto timeInfo = std::gmtime(&time);
if(!timeInfo)
return false;
std::cout << "\t\tGetting current UTC time: " << std::put_time(timeInfo, "%Y-%m-%d %H:%M:%S") << std::endl;
} else {
std::cout << "\t\tTime not available" << std::endl;
}
// Now, set the time using the system's clock so that we can check it again to ensure it's set
auto now = std::chrono::system_clock::now();
device->setRTC(now);
std::cout << "\t\tTime is now set..." << std::endl;
// Get the time again after setting
auto dTime2 = device->getRTC();
if (dTime2.has_value()) {
std::time_t time2 = std::chrono::system_clock::to_time_t(dTime2.value());
const auto timeInfo2 = std::gmtime(&time2);
if(!timeInfo2)
return false;
std::cout << "\t\tGetting current UTC time: " << std::put_time(timeInfo2, "%Y-%m-%d %H:%M:%S") << std::endl;
} else {
std::cout << "\t\tTime is not available" << std::endl;
}
// Now we can either register a handler (or multiple) for messages coming in
// or we can enable message polling, and then call device->getMessages periodically
@ -127,7 +161,7 @@ int main() {
// Keep in mind that 20k messages comes quickly at high bus loads!
// We can transmit messages
std::cout << "\tTransmitting an extended CAN FD frame... ";
std::cout << "\n\tTransmitting an extended CAN FD frame... ";
auto txMessage5 = std::make_shared<icsneo::CANMessage>();
txMessage5->network = icsneo::Network::NetID::HSCAN;
txMessage5->arbid = 0x1C5001C5;

View File

@ -12,6 +12,8 @@ enum class Command : uint8_t {
NeoWriteMemory = 0x41,
ClearCoreMini = 0x42,
LoadCoreMini = 0x43,
GetRTC = 0x49,
SetRTC = 0x50,
RequestSerialNumber = 0xA1,
GetMainVersion = 0xA3, // Previously known as RED_CMD_APP_VERSION_REQ
SetSettings = 0xA4, // Previously known as RED_CMD_SET_BAUD_REQ, follow up with SaveSettings to write to EEPROM

View File

@ -146,6 +146,7 @@ public:
DWCAN16 = 541,
LIN7 = 542,
LIN8 = 543,
RED_SET_RTC = 544,
Any = 0xfffe, // Never actually set as type, but used as flag for filtering
Invalid = 0xffff
};
@ -325,6 +326,8 @@ public:
case NetID::ExtendedCommand:
case NetID::NeoMemorySDRead:
case NetID::NeoMemoryWriteDone:
case NetID::RED_GET_RTC:
case NetID::RED_SET_RTC:
return Type::Internal;
case NetID::Invalid:
case NetID::Any:
@ -453,6 +456,8 @@ public:
return "RED_HARDWARE_EXCEP";
case NetID::RED_GET_RTC:
return "RED_GET_RTC";
case NetID::RED_SET_RTC:
return "RED_SET_RTC";
case NetID::ISO9141_3:
return "ISO 9141 3";
case NetID::HSCAN2:

View File

@ -50,7 +50,6 @@
#define ICSNEO_FINDABLE_DEVICE_BY_PID(className, type, pid) \
static constexpr const uint16_t PRODUCT_ID = pid; \
ICSNEO_FINDABLE_DEVICE_BASE(className, type)
namespace icsneo {
class DeviceExtension;
@ -545,6 +544,10 @@ public:
*/
virtual bool getEthPhyRegControlSupported() const { return false; }
//RTC declarations
std::optional<std::chrono::time_point<std::chrono::system_clock>> getRTC();
bool setRTC(const std::chrono::time_point<std::chrono::system_clock>& time);
/**
* Returns true if this device supports the Wireless neoVI featureset
*/

View File

@ -2442,6 +2442,16 @@ typedef struct
uint8_t bIPV4_Address[4]; // The Ipv4 address assigned to the Network interface. If not available, all bytes are set to zero.
} NETWORK_ADAPTER_INFO;
typedef struct
{
unsigned char sec;// --- Seconds (00-59)
unsigned char min;// --- (00-59)
unsigned char hour;// --- (00-23)
unsigned char day;// --- (01-31)
unsigned char month;// --- (01-12)
unsigned char year;// --- (00-99)
} icsSpyTime;
#ifndef INTREPID_NO_CHECK_STRUCT_SIZE
#if defined(__cplusplus) && (__cplusplus > 199711L)

View File

@ -808,6 +808,24 @@ extern bool DLLExport icsneo_isTerminationEnabledFor(const neodevice_t* device,
*/
extern bool DLLExport icsneo_setTerminationFor(const neodevice_t* device, neonetid_t netid, bool enabled);
/**
* \brief Get the real-time clock for the given device.
* \param[out] device A pointer to the neodevice_t structure specifying the device to read the RTC from.
* \param[out] output A pointer to a uint64_t where the RTC will be stored. This value is in seconds.
* \returns True if the RTC was successfully retrieved.
*/
extern bool icsneo_getRTC(const neodevice_t* device, uint64_t* output);
/**
* \brief Set the real-time clock for the given device.
* \param[out] device A pointer to the neodevice_t structure specifying the device to write the RTC to.
* \param[in] input A uint64_t object holding the RTC value. This value is in seconds.
* \returns True if the RTC was successfully set.
*/
extern bool icsneo_setRTC(const neodevice_t* device, uint64_t input);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -40,6 +40,10 @@ extern void LegacyDLLExport icsneoGetISO15765Status(void* hObject, int lNetwork,
extern void LegacyDLLExport icsneoSetISO15765RxParameters(void* hObject, int lNetwork, int lEnable, spyFilterLong* pFF_CFMsgFilter, icsSpyMessage* pTxMsg,
int lCFTimeOutMs, int lFlowCBlockSize, int lUsesExtendedAddressing, int lUseHardwareIfPresent);
//RTC Functions
extern int LegacyDLLExport icsneoGetRTC(void* hObject, icsSpyTime* time);
extern int LegacyDLLExport icsneoSetRTC(void* hObject, const icsSpyTime* time);
//Device Functions
extern int LegacyDLLExport icsneoGetConfiguration(void* hObject, unsigned char* pData, int* lNumBytes);
extern int LegacyDLLExport icsneoSendConfiguration(void* hObject, unsigned char* pData, int lNumBytes);