2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/Notifier.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
2019-11-10 20:54:25 -08:00
|
|
|
#include <atomic>
|
2017-08-18 21:35:53 -07:00
|
|
|
#include <chrono>
|
2019-11-09 11:41:58 -08:00
|
|
|
#include <cstring>
|
2025-11-29 11:00:18 -08:00
|
|
|
#include <functional>
|
2024-09-20 17:43:39 -07:00
|
|
|
#include <memory>
|
2019-11-09 11:41:58 -08:00
|
|
|
#include <string>
|
2024-09-20 17:43:39 -07:00
|
|
|
#include <utility>
|
2025-11-29 11:00:18 -08:00
|
|
|
#include <vector>
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2026-01-04 00:41:53 -08:00
|
|
|
#include "HALInitializer.hpp"
|
|
|
|
|
#include "NotifierInternal.hpp"
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/Errors.h"
|
|
|
|
|
#include "wpi/hal/HALBase.h"
|
2025-11-29 11:00:18 -08:00
|
|
|
#include "wpi/hal/Threads.h"
|
|
|
|
|
#include "wpi/hal/Types.h"
|
2026-01-04 00:41:53 -08:00
|
|
|
#include "wpi/hal/handles/UnlimitedHandleResource.hpp"
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/simulation/NotifierData.h"
|
2025-11-29 11:00:18 -08:00
|
|
|
#include "wpi/util/SafeThread.hpp"
|
2025-11-07 19:57:55 -05:00
|
|
|
#include "wpi/util/SmallVector.hpp"
|
|
|
|
|
#include "wpi/util/StringExtras.hpp"
|
2025-11-29 11:00:18 -08:00
|
|
|
#include "wpi/util/Synchronization.h"
|
|
|
|
|
#include "wpi/util/priority_queue.hpp"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
struct Notifier {
|
2019-11-09 11:41:58 -08:00
|
|
|
std::string name;
|
2025-11-29 11:00:18 -08:00
|
|
|
std::atomic<uint64_t> alarmTime = UINT64_MAX;
|
|
|
|
|
uint64_t intervalTime = 0;
|
|
|
|
|
std::atomic<int32_t> userOverrunCount = 0;
|
|
|
|
|
int32_t overrunCount = 0;
|
|
|
|
|
std::atomic_flag handlerSignaled{};
|
2017-08-18 21:35:53 -07:00
|
|
|
};
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
using namespace wpi::hal;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
class NotifierThread : public wpi::util::SafeThread {
|
|
|
|
|
public:
|
|
|
|
|
void Main() override;
|
|
|
|
|
|
|
|
|
|
void ProcessAlarms(wpi::util::SmallVectorImpl<HAL_NotifierHandle>* signaled);
|
|
|
|
|
|
|
|
|
|
bool m_paused = false;
|
|
|
|
|
|
|
|
|
|
UnlimitedHandleResource<HAL_NotifierHandle, Notifier,
|
|
|
|
|
HAL_HandleEnum::Notifier>
|
|
|
|
|
m_handles;
|
2020-09-27 13:27:53 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
struct Alarm {
|
|
|
|
|
HAL_NotifierHandle handle;
|
|
|
|
|
std::shared_ptr<Notifier> notifier;
|
|
|
|
|
bool operator==(const Alarm& rhs) const { return handle == rhs.handle; }
|
|
|
|
|
bool operator>(const Alarm& rhs) const {
|
|
|
|
|
return notifier->alarmTime > rhs.notifier->alarmTime;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
wpi::util::priority_queue<Alarm, std::vector<Alarm>, std::greater<Alarm>>
|
|
|
|
|
m_alarmQueue;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class NotifierInstance {
|
2017-11-19 17:58:40 -08:00
|
|
|
public:
|
2025-11-29 11:00:18 -08:00
|
|
|
NotifierInstance() { owner.Start(); }
|
|
|
|
|
wpi::util::SafeThreadOwner<NotifierThread> owner;
|
2017-11-19 17:58:40 -08:00
|
|
|
};
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
static NotifierInstance* notifierInstance;
|
2017-12-10 19:38:53 -08:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
namespace wpi::hal::init {
|
2017-12-10 19:38:53 -08:00
|
|
|
void InitializeNotifier() {
|
2025-11-29 11:00:18 -08:00
|
|
|
static NotifierInstance n;
|
|
|
|
|
notifierInstance = &n;
|
2017-12-10 19:38:53 -08:00
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
} // namespace wpi::hal::init
|
|
|
|
|
|
|
|
|
|
void NotifierThread::Main() {
|
|
|
|
|
std::unique_lock lock(m_mutex);
|
|
|
|
|
while (m_active) {
|
|
|
|
|
if (m_paused || m_alarmQueue.empty()) {
|
|
|
|
|
// No alarms, wait indefinitely
|
|
|
|
|
m_cond.wait(lock);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-11-10 20:54:25 -08:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
// Wait until next alarm
|
|
|
|
|
const Alarm& alarm = m_alarmQueue.top();
|
|
|
|
|
int32_t status = 0;
|
|
|
|
|
uint64_t curTime = HAL_GetFPGATime(&status);
|
|
|
|
|
if (alarm.notifier->alarmTime > curTime) {
|
|
|
|
|
m_cond.wait_for(
|
|
|
|
|
lock, std::chrono::microseconds{alarm.notifier->alarmTime - curTime});
|
|
|
|
|
}
|
|
|
|
|
if (!m_active) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-11-10 20:54:25 -08:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
// Check paused again as we may have been paused while waiting
|
|
|
|
|
if (m_paused) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-11-10 20:54:25 -08:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
ProcessAlarms(nullptr);
|
|
|
|
|
}
|
2019-11-10 20:54:25 -08:00
|
|
|
}
|
2020-09-27 13:27:53 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void NotifierThread::ProcessAlarms(
|
|
|
|
|
wpi::util::SmallVectorImpl<HAL_NotifierHandle>* signaled) {
|
|
|
|
|
int32_t status = 0;
|
|
|
|
|
uint64_t curTime = HAL_GetFPGATime(&status);
|
2020-10-15 20:18:15 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
// Process alarms
|
|
|
|
|
while (!m_alarmQueue.empty() &&
|
|
|
|
|
m_alarmQueue.top().notifier->alarmTime <= curTime) {
|
|
|
|
|
Alarm alarm = m_alarmQueue.pop();
|
|
|
|
|
HAL_NotifierHandle handle = alarm.handle;
|
|
|
|
|
Notifier& notifier = *alarm.notifier;
|
|
|
|
|
|
|
|
|
|
if (notifier.intervalTime > 0) {
|
|
|
|
|
// Schedule next alarm
|
|
|
|
|
notifier.alarmTime += notifier.intervalTime;
|
|
|
|
|
if (curTime >= notifier.alarmTime) {
|
|
|
|
|
// We missed at least one interval
|
|
|
|
|
int32_t missed = static_cast<int32_t>((curTime - notifier.alarmTime) /
|
|
|
|
|
notifier.intervalTime) +
|
|
|
|
|
1;
|
|
|
|
|
notifier.overrunCount += missed;
|
|
|
|
|
notifier.alarmTime +=
|
|
|
|
|
missed * notifier.intervalTime; // Skip missed intervals
|
2020-10-15 20:18:15 -07:00
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
// Reinsert into queue
|
|
|
|
|
m_alarmQueue.push(std::move(alarm));
|
|
|
|
|
} else {
|
|
|
|
|
// Disable one-shot alarm
|
|
|
|
|
notifier.alarmTime = UINT64_MAX;
|
2020-10-15 20:18:15 -07:00
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
|
|
|
|
|
// If the last call was acknowledged, signal the handler
|
|
|
|
|
if (!notifier.handlerSignaled.test_and_set()) {
|
|
|
|
|
if (signaled) {
|
|
|
|
|
signaled->emplace_back(handle);
|
|
|
|
|
}
|
|
|
|
|
// copy the overrun count for the handler to read, reset the local count
|
|
|
|
|
notifier.userOverrunCount = notifier.overrunCount;
|
|
|
|
|
notifier.overrunCount = 0;
|
|
|
|
|
wpi::util::SetSignalObject(handle);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2020-10-15 20:18:15 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void wpi::hal::PauseNotifiers() {
|
|
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
thr->m_paused = true;
|
|
|
|
|
}
|
2020-10-15 20:18:15 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void wpi::hal::ResumeNotifiers() {
|
|
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
thr->m_paused = false;
|
|
|
|
|
thr->m_cond.notify_all();
|
|
|
|
|
}
|
2020-10-15 20:18:15 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void wpi::hal::WakeupNotifiers() {
|
|
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
thr->ProcessAlarms(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DoWaitNotifiers(
|
|
|
|
|
wpi::util::detail::SafeThreadProxy<NotifierThread>& thr,
|
|
|
|
|
wpi::util::SmallVectorImpl<HAL_NotifierHandle>& signaled) {
|
|
|
|
|
// Wait for signaled notifiers to acknowledge their last alarm
|
2020-09-27 13:27:53 -07:00
|
|
|
for (;;) {
|
2025-11-29 11:00:18 -08:00
|
|
|
signaled.erase(std::remove_if(signaled.begin(), signaled.end(),
|
|
|
|
|
[&](HAL_NotifierHandle handle) {
|
|
|
|
|
auto notifier = thr->m_handles.Get(handle);
|
|
|
|
|
return !notifier ||
|
|
|
|
|
!notifier->handlerSignaled.test();
|
|
|
|
|
}),
|
|
|
|
|
signaled.end());
|
|
|
|
|
if (signaled.empty()) {
|
2020-12-28 12:58:06 -08:00
|
|
|
break;
|
|
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
thr->m_cond.wait_for(thr.GetLock(), std::chrono::milliseconds{1});
|
2020-09-27 13:27:53 -07:00
|
|
|
}
|
|
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
|
|
|
|
|
void wpi::hal::WaitNotifiers() {
|
|
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
|
|
|
|
|
wpi::util::SmallVector<HAL_NotifierHandle, 8> signaled;
|
|
|
|
|
thr->m_handles.ForEach([&](HAL_NotifierHandle handle, Notifier* notifier) {
|
|
|
|
|
if (notifier->handlerSignaled.test()) {
|
|
|
|
|
signaled.emplace_back(handle);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DoWaitNotifiers(thr, signaled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void wpi::hal::WakeupWaitNotifiers() {
|
|
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
|
|
|
|
|
wpi::util::SmallVector<HAL_NotifierHandle, 8> signaled;
|
|
|
|
|
thr->ProcessAlarms(&signaled);
|
|
|
|
|
DoWaitNotifiers(thr, signaled);
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2017-11-19 17:58:40 -08:00
|
|
|
extern "C" {
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
HAL_NotifierHandle HAL_CreateNotifier(int32_t* status) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::CheckInit();
|
2017-08-18 21:35:53 -07:00
|
|
|
std::shared_ptr<Notifier> notifier = std::make_shared<Notifier>();
|
2025-11-29 11:00:18 -08:00
|
|
|
HAL_NotifierHandle handle =
|
|
|
|
|
notifierInstance->owner.GetThread()->m_handles.Allocate(notifier);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (handle == HAL_kInvalidHandle) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return HAL_kInvalidHandle;
|
|
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
wpi::util::CreateSignalObject(handle);
|
2017-08-18 21:35:53 -07:00
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-28 22:05:26 -08:00
|
|
|
HAL_Bool HAL_SetNotifierThreadPriority(HAL_Bool realTime, int32_t priority,
|
|
|
|
|
int32_t* status) {
|
2025-11-29 11:00:18 -08:00
|
|
|
auto native = notifierInstance->owner.GetNativeThreadHandle();
|
|
|
|
|
return HAL_SetThreadPriority(&native, realTime, priority, status);
|
2021-02-28 22:05:26 -08:00
|
|
|
}
|
|
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void HAL_SetNotifierName(HAL_NotifierHandle notifierHandle,
|
|
|
|
|
const WPI_String* name, int32_t* status) {
|
|
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
auto notifier = thr->m_handles.Get(notifierHandle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!notifier) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
notifier->name = wpi::util::to_string_view(name);
|
2019-11-09 11:41:58 -08:00
|
|
|
}
|
|
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void HAL_DestroyNotifier(HAL_NotifierHandle notifierHandle) {
|
|
|
|
|
wpi::util::DestroySignalObject(notifierHandle);
|
|
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
auto notifier = thr->m_handles.Free(notifierHandle);
|
|
|
|
|
thr->m_alarmQueue.remove({notifierHandle, notifier});
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
2017-11-19 17:58:40 -08:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void HAL_SetNotifierAlarm(HAL_NotifierHandle notifierHandle, uint64_t alarmTime,
|
|
|
|
|
uint64_t intervalTime, HAL_Bool absolute,
|
2025-12-09 20:28:15 -07:00
|
|
|
HAL_Bool ack, int32_t* status) {
|
2025-11-29 11:00:18 -08:00
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
auto notifier = thr->m_handles.Get(notifierHandle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!notifier) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-12-09 20:28:15 -07:00
|
|
|
|
|
|
|
|
if (ack) {
|
|
|
|
|
notifier->handlerSignaled.clear();
|
2025-12-11 23:31:49 -07:00
|
|
|
wpi::util::ResetSignalObject(notifierHandle);
|
2025-12-09 20:28:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!absolute) {
|
|
|
|
|
alarmTime += HAL_GetFPGATime(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t prevWakeup = UINT64_MAX;
|
|
|
|
|
if (!thr->m_alarmQueue.empty()) {
|
|
|
|
|
prevWakeup = thr->m_alarmQueue.top().notifier->alarmTime;
|
|
|
|
|
thr->m_alarmQueue.remove({notifierHandle, notifier});
|
|
|
|
|
}
|
|
|
|
|
notifier->alarmTime = alarmTime;
|
|
|
|
|
notifier->intervalTime = intervalTime;
|
|
|
|
|
notifier->overrunCount = 0;
|
|
|
|
|
thr->m_alarmQueue.push({notifierHandle, notifier});
|
|
|
|
|
|
|
|
|
|
// wake up notifier thread if needed
|
|
|
|
|
if (alarmTime < prevWakeup) {
|
|
|
|
|
thr->m_cond.notify_all();
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
2017-11-19 17:58:40 -08:00
|
|
|
|
2025-12-09 20:28:15 -07:00
|
|
|
void HAL_CancelNotifierAlarm(HAL_NotifierHandle notifierHandle, HAL_Bool ack,
|
2017-11-19 17:58:40 -08:00
|
|
|
int32_t* status) {
|
2025-11-29 11:00:18 -08:00
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
auto notifier = thr->m_handles.Get(notifierHandle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!notifier) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-11-19 17:58:40 -08:00
|
|
|
|
2025-12-09 20:28:15 -07:00
|
|
|
if (ack) {
|
|
|
|
|
notifier->handlerSignaled.clear();
|
2025-12-11 23:31:49 -07:00
|
|
|
wpi::util::ResetSignalObject(notifierHandle);
|
2025-12-09 20:28:15 -07:00
|
|
|
}
|
|
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
thr->m_alarmQueue.remove({notifierHandle, notifier});
|
|
|
|
|
notifier->alarmTime = UINT64_MAX;
|
2017-11-19 17:58:40 -08:00
|
|
|
}
|
|
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
void HAL_AcknowledgeNotifierAlarm(HAL_NotifierHandle notifierHandle,
|
2017-11-19 17:58:40 -08:00
|
|
|
int32_t* status) {
|
2025-12-04 09:59:59 -07:00
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
auto notifier = thr->m_handles.Get(notifierHandle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!notifier) {
|
2025-11-29 11:00:18 -08:00
|
|
|
return;
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
notifier->handlerSignaled.clear();
|
2025-12-11 23:31:49 -07:00
|
|
|
wpi::util::ResetSignalObject(notifierHandle);
|
2025-11-29 11:00:18 -08:00
|
|
|
}
|
2017-11-19 17:58:40 -08:00
|
|
|
|
2025-11-29 11:00:18 -08:00
|
|
|
int32_t HAL_GetNotifierOverrun(HAL_NotifierHandle notifierHandle,
|
|
|
|
|
int32_t* status) {
|
|
|
|
|
auto notifier =
|
|
|
|
|
notifierInstance->owner.GetThread()->m_handles.Get(notifierHandle);
|
|
|
|
|
if (!notifier) {
|
|
|
|
|
return -1;
|
2017-11-19 17:58:40 -08:00
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
return notifier->userOverrunCount;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
2019-11-09 11:41:58 -08:00
|
|
|
uint64_t HALSIM_GetNextNotifierTimeout(void) {
|
2025-11-29 11:00:18 -08:00
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
|
|
|
|
if (thr->m_alarmQueue.empty()) {
|
|
|
|
|
return UINT64_MAX;
|
|
|
|
|
}
|
|
|
|
|
return thr->m_alarmQueue.top().notifier->alarmTime;
|
2019-11-09 11:41:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t HALSIM_GetNumNotifiers(void) {
|
2025-11-29 11:00:18 -08:00
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
2019-11-09 11:41:58 -08:00
|
|
|
int32_t count = 0;
|
2025-11-29 11:00:18 -08:00
|
|
|
thr->m_handles.ForEach([&](auto, auto) { ++count; });
|
2019-11-09 11:41:58 -08:00
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t HALSIM_GetNotifierInfo(struct HALSIM_NotifierInfo* arr, int32_t size) {
|
2025-11-29 11:00:18 -08:00
|
|
|
auto thr = notifierInstance->owner.GetThread();
|
2019-11-09 11:41:58 -08:00
|
|
|
int32_t num = 0;
|
2025-11-29 11:00:18 -08:00
|
|
|
thr->m_handles.ForEach([&](HAL_NotifierHandle handle, Notifier* notifier) {
|
2019-11-09 11:41:58 -08:00
|
|
|
if (num < size) {
|
|
|
|
|
arr[num].handle = handle;
|
|
|
|
|
if (notifier->name.empty()) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::util::format_to_n_c_str(arr[num].name, sizeof(arr[num].name),
|
2025-11-07 20:01:58 -05:00
|
|
|
"Notifier{}",
|
|
|
|
|
static_cast<int>(getHandleIndex(handle)));
|
2019-11-09 11:41:58 -08:00
|
|
|
} else {
|
|
|
|
|
std::strncpy(arr[num].name, notifier->name.c_str(),
|
2021-12-19 16:46:12 -08:00
|
|
|
sizeof(arr[num].name) - 1);
|
2019-11-09 11:41:58 -08:00
|
|
|
arr[num].name[sizeof(arr[num].name) - 1] = '\0';
|
|
|
|
|
}
|
2025-11-29 11:00:18 -08:00
|
|
|
arr[num].alarmTime = notifier->alarmTime;
|
|
|
|
|
arr[num].intervalTime = notifier->intervalTime;
|
|
|
|
|
arr[num].overrunCount = notifier->overrunCount;
|
2019-11-09 11:41:58 -08:00
|
|
|
}
|
|
|
|
|
++num;
|
|
|
|
|
});
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
} // extern "C"
|