Skip to content

File syn_uds_util.c

File List > proto > syn_uds_util.c

Go to the documentation of this file

#include "syntropic/proto/syn_uds_util.h"

#include "syntropic/util/syn_fmt.h"

#include <ctype.h>
#include <string.h>

static int hex_char_to_nibble(char c)
{
    if (c >= '0' && c <= '9') {
        return c - '0';
    }
    if (c >= 'a' && c <= 'f') {
        return c - 'a' + 10;
    }
    if (c >= 'A' && c <= 'F') {
        return c - 'A' + 10;
    }
    return -1;
}

bool syn_uds_dtc_from_str(const char *str, uint32_t *dtc_out)
{
    if (!str || !dtc_out) {
        return false;
    }

    /* Category prefix check */
    char prefix = (char)toupper((unsigned char)str[0]);
    uint8_t category_bits = 0;
    switch (prefix) {
    case 'P':
        category_bits = 0x00U;
        break;
    case 'C':
        category_bits = 0x01U;
        break;
    case 'B':
        category_bits = 0x02U;
        break;
    case 'U':
        category_bits = 0x03U;
        break;
    default:
        return false;
    }

    size_t len = strlen(str);
    if (len < 5U || len > 7U) {
        return false;
    }

    /* Parse up to 6 remaining hex characters */
    uint8_t nibbles[6] = {0};
    for (size_t i = 1U; i < len; i++) {
        int n = hex_char_to_nibble(str[i]);
        if (n < 0) {
            return false;
        }
        nibbles[i - 1U] = (uint8_t)n;
    }

    /* High Byte = (Category << 6) | (Type << 4) | Subsystem */
    uint8_t high_byte = (category_bits << 6) | ((nibbles[0] & 0x03U) << 4) | (nibbles[1] & 0x0FU);

    /* Middle Byte = (Digit 3 << 4) | Digit 4 */
    uint8_t mid_byte = ((nibbles[2] & 0x0FU) << 4) | (nibbles[3] & 0x0FU);

    /* Low Byte = (Digit 5 << 4) | Digit 6 (or 0x00 if 5 digits) */
    uint8_t low_byte = 0;
    if (len >= 6U) {
        low_byte |= (uint8_t)((nibbles[4] & 0x0FU) << 4);
    }
    if (len >= 7U) {
        low_byte |= (uint8_t)(nibbles[5] & 0x0FU);
    }

    *dtc_out = ((uint32_t)high_byte << 16) | ((uint32_t)mid_byte << 8) | low_byte;
    return true;
}

bool syn_uds_dtc_to_str(uint32_t dtc, char *out_buf, size_t buf_size)
{
    if (!out_buf || buf_size < 8U) {
        return false;
    }

    uint8_t high_byte = (uint8_t)((dtc >> 16) & 0xFFU);
    uint8_t mid_byte = (uint8_t)((dtc >> 8) & 0xFFU);
    uint8_t low_byte = (uint8_t)(dtc & 0xFFU);

    static const char CATEGORY_CHARS[4] = {'P', 'C', 'B', 'U'};
    uint8_t cat_idx = (high_byte >> 6) & 0x03U;
    uint8_t type_digit = (high_byte >> 4) & 0x03U;
    uint8_t sub_digit = high_byte & 0x0FU;

    out_buf[0] = CATEGORY_CHARS[cat_idx];
    out_buf[1] = (char)('0' + type_digit);

    static const char HEX_DIGITS[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
                                        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    out_buf[2] = HEX_DIGITS[sub_digit];
    out_buf[3] = HEX_DIGITS[(mid_byte >> 4) & 0x0FU];
    out_buf[4] = HEX_DIGITS[mid_byte & 0x0FU];
    out_buf[5] = HEX_DIGITS[(low_byte >> 4) & 0x0FU];
    out_buf[6] = HEX_DIGITS[low_byte & 0x0FU];
    out_buf[7] = '\0';

    return true;
}