<commit_before>#include "can/canutil.h"
#include "can/canwrite.h"
#include "util/timer.h"
#include "util/statistics.h"
#include "util/log.h"

#define BUS_STATS_LOG_FREQUENCY_S 15
#define CAN_MESSAGE_TOTAL_BIT_SIZE 128
#define DYNAMIC_MESSAGE_MAP_CAPACITY 25

namespace time = openxc::util::time;
namespace statistics = openxc::util::statistics;

using openxc::util::log::debugNoNewline;
using openxc::util::statistics::DeltaStatistic;

const int openxc::can::CAN_ACTIVE_TIMEOUT_S = 30;

void openxc::can::initializeCommon(CanBus* bus) {
    debugNoNewline("Initializing CAN node %d...", bus->address);
    QUEUE_INIT(CanMessage, &bus->receiveQueue);
    QUEUE_INIT(CanMessage, &bus->sendQueue);
    bus->writeHandler = openxc::can::write::sendMessage;
    bus->lastMessageReceived = 0;
    // TODO could create this on the fly since most of the time we won't use it
    bus->dynamicMessages = emhashmap_create(DYNAMIC_MESSAGE_MAP_CAPACITY);
#ifdef __LOG_STATS__
    statistics::initialize(&bus->totalMessageStats);
    statistics::initialize(&bus->droppedMessageStats);
    statistics::initialize(&bus->receivedMessageStats);
    statistics::initialize(&bus->receivedDataStats);
    statistics::initialize(&bus->sendQueueStats);
    statistics::initialize(&bus->receiveQueueStats);
#endif // __LOG_STATS__
}

void openxc::can::destroy(CanBus* bus) {
    if(bus->dynamicMessages != NULL) {
        MapIterator iterator = emhashmap_iterator(bus->dynamicMessages);
        MapEntry* next = NULL;
        while((next = emhashmap_iterator_next(&iterator)) != NULL) {
            delete (CanMessageDefinition*)next->value;
        }
        emhashmap_destroy(bus->dynamicMessages);
    }
}

bool openxc::can::busActive(CanBus* bus) {
    return bus->lastMessageReceived != 0 &&
        time::systemTimeMs() - bus->lastMessageReceived < CAN_ACTIVE_TIMEOUT_S * 1000;
}

int lookup(void* key,
        bool (*comparator)(void* key, int index, void* candidates),
        void* candidates, int candidateCount) {
    for(int i = 0; i < candidateCount; i++) {
        if(comparator(key, i, candidates)) {
            return i;
        }
    }
    return -1;
}

bool signalStateNameComparator(void* name, int index, void* states) {
    return !strcmp((const char*)name, ((CanSignalState*)states)[index].name);
}

const CanSignalState* openxc::can::lookupSignalState(const char* name, CanSignal* signal,
        CanSignal* signals, int signalCount) {
    int index = lookup((void*)name, signalStateNameComparator,
            (void*)signal->states, signal->stateCount);
    if(index != -1) {
        return &signal->states[index];
    } else {
        return NULL;
    }
}

bool signalStateValueComparator(void* value, int index, void* states) {
    return (*(int*)value) == ((CanSignalState*)states)[index].value;
}

const CanSignalState* openxc::can::lookupSignalState(int value, CanSignal* signal,
        CanSignal* signals, int signalCount) {
    int index = lookup((void*)&value, signalStateValueComparator,
            (void*)signal->states, signal->stateCount);
    if(index != -1) {
        return &signal->states[index];
    } else {
        return NULL;
    }
}

bool signalComparator(void* name, int index, void* signals) {
    return !strcmp((const char*)name, ((CanSignal*)signals)[index].genericName);
}

bool writableSignalComparator(void* name, int index, void* signals) {
    return signalComparator(name, index, signals) &&
            ((CanSignal*)signals)[index].writable;
}

CanSignal* openxc::can::lookupSignal(const char* name, CanSignal* signals, int signalCount,
        bool writable) {
    bool (*comparator)(void* key, int index, void* candidates) = signalComparator;
    if(writable) {
        comparator = writableSignalComparator;
    }
    int index = lookup((void*)name, comparator, (void*)signals, signalCount);
    if(index != -1) {
        return &signals[index];
    } else {
        return NULL;
    }
}

CanSignal* openxc::can::lookupSignal(const char* name, CanSignal* signals, int signalCount) {
    return lookupSignal(name, signals, signalCount, false);
}

bool commandComparator(void* name, int index, void* commands) {
    return !strcmp((const char*)name, ((CanCommand*)commands)[index].genericName);
}

CanCommand* openxc::can::lookupCommand(const char* name, CanCommand* commands, int commandCount) {
    int index = lookup((void*)name, commandComparator, (void*)commands,
            commandCount);
    if(index != -1) {
        return &commands[index];
    } else {
        return NULL;
    }
}

CanMessageDefinition* lookupMessage(CanBus* bus, uint32_t id,
        CanMessageDefinition* messages, int messageCount) {
    CanMessageDefinition* message = NULL;
    for(int i = 0; i < messageCount; i++) {
        if(messages[i].bus == bus && messages[i].id == id) {
            message = &messages[i];
        }
    }
    return message;
}

CanMessageDefinition* openxc::can::lookupMessageDefinition(CanBus* bus,
        uint32_t id, CanMessageDefinition* predefinedMessages,
        int predefinedMessageCount) {
    CanMessageDefinition* message = lookupMessage(bus, id,
            predefinedMessages, predefinedMessageCount);
    if(message == NULL) {
        message = (CanMessageDefinition*)emhashmap_get(bus->dynamicMessages, id);
    }
    return message;
}

bool openxc::can::registerMessageDefinition(CanBus* bus, uint32_t id,
        CanMessageDefinition* predefinedMessages, int predefinedMessageCount) {
    CanMessageDefinition* message = lookupMessageDefinition(bus, id, NULL, 0);
    if(message == NULL) {
        message = new CanMessageDefinition();
        if(message != NULL) {
            message->bus = bus;
            message->id = id;
            message->frequencyClock = {bus->maxMessageFrequency};

            emhashmap_put(bus->dynamicMessages, id, message);
        }
    }
    return message != NULL;
}

bool openxc::can::unregisterMessageDefinition(CanBus* bus, uint32_t id) {
    CanMessageDefinition* message = (CanMessageDefinition*) emhashmap_remove(
            bus->dynamicMessages, id);
    if(message != NULL) {
        delete message;
    } else {
        return false;
    }
    return true;
}

void openxc::can::logBusStatistics(CanBus* buses, const int busCount) {
#ifdef __LOG_STATS__
    static DeltaStatistic totalMessageStats;
    static DeltaStatistic receivedMessageStats;
    static DeltaStatistic droppedMessageStats;
    static DeltaStatistic receivedDataStats;
    static unsigned long lastTimeLogged;
    static bool initializedStats = false;
    if(!initializedStats) {
        statistics::initialize(&totalMessageStats);<commit_msg>For runtime CAN msgs, default to sending changed values immediately.<commit_after>#include "can/canutil.h"
#include "can/canwrite.h"
#include "util/timer.h"
#include "util/statistics.h"
#include "util/log.h"

#define BUS_STATS_LOG_FREQUENCY_S 15
#define CAN_MESSAGE_TOTAL_BIT_SIZE 128
#define DYNAMIC_MESSAGE_MAP_CAPACITY 25

namespace time = openxc::util::time;
namespace statistics = openxc::util::statistics;

using openxc::util::log::debugNoNewline;
using openxc::util::statistics::DeltaStatistic;

const int openxc::can::CAN_ACTIVE_TIMEOUT_S = 30;

void openxc::can::initializeCommon(CanBus* bus) {
    debugNoNewline("Initializing CAN node %d...", bus->address);
    QUEUE_INIT(CanMessage, &bus->receiveQueue);
    QUEUE_INIT(CanMessage, &bus->sendQueue);
    bus->writeHandler = openxc::can::write::sendMessage;
    bus->lastMessageReceived = 0;
    // TODO could create this on the fly since most of the time we won't use it
    bus->dynamicMessages = emhashmap_create(DYNAMIC_MESSAGE_MAP_CAPACITY);
#ifdef __LOG_STATS__
    statistics::initialize(&bus->totalMessageStats);
    statistics::initialize(&bus->droppedMessageStats);
    statistics::initialize(&bus->receivedMessageStats);
    statistics::initialize(&bus->receivedDataStats);
    statistics::initialize(&bus->sendQueueStats);
    statistics::initialize(&bus->receiveQueueStats);
#endif // __LOG_STATS__
}

void openxc::can::destroy(CanBus* bus) {
    if(bus->dynamicMessages != NULL) {
        MapIterator iterator = emhashmap_iterator(bus->dynamicMessages);
        MapEntry* next = NULL;
        while((next = emhashmap_iterator_next(&iterator)) != NULL) {
            delete (CanMessageDefinition*)next->value;
        }
        emhashmap_destroy(bus->dynamicMessages);
    }
}

bool openxc::can::busActive(CanBus* bus) {
    return bus->lastMessageReceived != 0 &&
        time::systemTimeMs() - bus->lastMessageReceived < CAN_ACTIVE_TIMEOUT_S * 1000;
}

int lookup(void* key,
        bool (*comparator)(void* key, int index, void* candidates),
        void* candidates, int candidateCount) {
    for(int i = 0; i < candidateCount; i++) {
        if(comparator(key, i, candidates)) {
            return i;
        }
    }
    return -1;
}

bool signalStateNameComparator(void* name, int index, void* states) {
    return !strcmp((const char*)name, ((CanSignalState*)states)[index].name);
}

const CanSignalState* openxc::can::lookupSignalState(const char* name, CanSignal* signal,
        CanSignal* signals, int signalCount) {
    int index = lookup((void*)name, signalStateNameComparator,
            (void*)signal->states, signal->stateCount);
    if(index != -1) {
        return &signal->states[index];
    } else {
        return NULL;
    }
}

bool signalStateValueComparator(void* value, int index, void* states) {
    return (*(int*)value) == ((CanSignalState*)states)[index].value;
}

const CanSignalState* openxc::can::lookupSignalState(int value, CanSignal* signal,
        CanSignal* signals, int signalCount) {
    int index = lookup((void*)&value, signalStateValueComparator,
            (void*)signal->states, signal->stateCount);
    if(index != -1) {
        return &signal->states[index];
    } else {
        return NULL;
    }
}

bool signalComparator(void* name, int index, void* signals) {
    return !strcmp((const char*)name, ((CanSignal*)signals)[index].genericName);
}

bool writableSignalComparator(void* name, int index, void* signals) {
    return signalComparator(name, index, signals) &&
            ((CanSignal*)signals)[index].writable;
}

CanSignal* openxc::can::lookupSignal(const char* name, CanSignal* signals, int signalCount,
        bool writable) {
    bool (*comparator)(void* key, int index, void* candidates) = signalComparator;
    if(writable) {
        comparator = writableSignalComparator;
    }
    int index = lookup((void*)name, comparator, (void*)signals, signalCount);
    if(index != -1) {
        return &signals[index];
    } else {
        return NULL;
    }
}

CanSignal* openxc::can::lookupSignal(const char* name, CanSignal* signals, int signalCount) {
    return lookupSignal(name, signals, signalCount, false);
}

bool commandComparator(void* name, int index, void* commands) {
    return !strcmp((const char*)name, ((CanCommand*)commands)[index].genericName);
}

CanCommand* openxc::can::lookupCommand(const char* name, CanCommand* commands, int commandCount) {
    int index = lookup((void*)name, commandComparator, (void*)commands,
            commandCount);
    if(index != -1) {
        return &commands[index];
    } else {
        return NULL;
    }
}

CanMessageDefinition* lookupMessage(CanBus* bus, uint32_t id,
        CanMessageDefinition* messages, int messageCount) {
    CanMessageDefinition* message = NULL;
    for(int i = 0; i < messageCount; i++) {
        if(messages[i].bus == bus && messages[i].id == id) {
            message = &messages[i];
        }
    }
    return message;
}

CanMessageDefinition* openxc::can::lookupMessageDefinition(CanBus* bus,
        uint32_t id, CanMessageDefinition* predefinedMessages,
        int predefinedMessageCount) {
    CanMessageDefinition* message = lookupMessage(bus, id,
            predefinedMessages, predefinedMessageCount);
    if(message == NULL) {
        message = (CanMessageDefinition*)emhashmap_get(bus->dynamicMessages, id);
    }
    return message;
}

bool openxc::can::registerMessageDefinition(CanBus* bus, uint32_t id,
        CanMessageDefinition* predefinedMessages, int predefinedMessageCount) {
    CanMessageDefinition* message = lookupMessageDefinition(bus, id, NULL, 0);
    if(message == NULL) {
        message = new CanMessageDefinition();
        if(message != NULL) {
            message->bus = bus;
            message->id = id;
            message->frequencyClock = {bus->maxMessageFrequency};
            // TODO document that this is the default somewhere
            message->forceSendChanged = true;

            emhashmap_put(bus->dynamicMessages, id, message);
        }
    }
    return message != NULL;
}

bool openxc::can::unregisterMessageDefinition(CanBus* bus, uint32_t id) {
    CanMessageDefinition* message = (CanMessageDefinition*) emhashmap_remove(
            bus->dynamicMessages, id);
    if(message != NULL) {
        delete message;
    } else {
        return false;
    }
    return true;
}

void openxc::can::logBusStatistics(CanBus* buses, const int busCount) {
#ifdef __LOG_STATS__
    static DeltaStatistic totalMessageStats;
    static DeltaStatistic receivedMessageStats;
    static DeltaStatistic droppedMessageStats;
    static DeltaStatistic receivedDataStats;
    static unsigned long lastTimeLogged;
    static bool initializedStats = false;
    if(!initializedStats) {
        statistics::initialize(&totalMessageStats);
{'fraction_non_alphanumeric': 0.12361142175501379, 'fraction_numerical': 0.0046223812719003955, 'mean_word_length': 3.8566256335988416, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5244754', 'n_tokens_mistral': 3931, 'n_tokens_neox': 3910, 'n_words': 884}