kdriveExpress SDK 22.1.1
kdrive_express_dpt.c
//
// Copyright (c) 2002-2022 WEINZIERL ENGINEERING GmbH
// All rights reserved.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,
// WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
//
#include <stdio.h>
#include <stdlib.h>
#include <kdrive_express.h>
#define ERROR_MESSAGE_LEN (128)
#define ADDR_DPT_1 (0x0901)
#define ADDR_DPT_2 (0x090A)
#define ADDR_DPT_3 ((ADDR_DPT_2) + 1)
#define ADDR_DPT_4 ((ADDR_DPT_3) + 1)
#define ADDR_DPT_5 ((ADDR_DPT_4) + 1)
#define ADDR_DPT_6 ((ADDR_DPT_5) + 1)
#define ADDR_DPT_7 ((ADDR_DPT_6) + 1)
#define ADDR_DPT_8 ((ADDR_DPT_7) + 1)
#define ADDR_DPT_9 ((ADDR_DPT_8) + 1)
#define ADDR_DPT_10_LOCAL ((ADDR_DPT_9) + 1)
#define ADDR_DPT_10_UTC ((ADDR_DPT_10_LOCAL) + 1)
#define ADDR_DPT_10 ((ADDR_DPT_10_UTC) + 1)
#define ADDR_DPT_11_LOCAL ((ADDR_DPT_10) + 1)
#define ADDR_DPT_11_UTC ((ADDR_DPT_11_LOCAL) + 1)
#define ADDR_DPT_11 ((ADDR_DPT_11_UTC) + 1)
#define ADDR_DPT_12 ((ADDR_DPT_11) + 1)
#define ADDR_DPT_13 ((ADDR_DPT_12) + 1)
#define ADDR_DPT_14 ((ADDR_DPT_13) + 1)
#define ADDR_DPT_15 ((ADDR_DPT_14) + 1)
#define ADDR_DPT_16 ((ADDR_DPT_15) + 1)
/*******************************
** Private Functions
********************************/
static void send_telegrams(int32_t ap);
static void on_telegram_callback(const uint8_t* telegram, uint32_t telegram_len, void* user_data);
static void error_callback(error_t e, void* user_data);
/*******************************
** Main
********************************/
int main(int argc, char* argv[])
{
uint8_t value = 1;
uint32_t key = 0;
uint32_t iface_count = 0;
int32_t ap = 0;
/*
Configure the logging level and console logger
*/
/*
We register an error callback as a convenience logger function to
print out the error message when an error occurs.
*/
kdrive_register_error_callback(&error_callback, NULL);
/*
We create a Access Port descriptor. This descriptor is then used for
all calls to that specific access port.
*/
/*
We check that we were able to allocate a new descriptor
This should always happen, unless a bad_alloc exception is internally thrown
which means the memory couldn't be allocated.
*/
{
kdrive_logger(KDRIVE_LOGGER_FATAL, "Unable to create access port. This is a terminal failure");
while (1)
{
;
}
}
iface_count = kdrive_ap_enum_usb(ap);
kdrive_logger_ex(KDRIVE_LOGGER_INFORMATION, "Found %d KNX USB Interfaces", iface_count);
/* If we found at least 1 interface we simply open the first one (i.e. index 0) */
if ((iface_count > 0) && (kdrive_ap_open_usb(ap, 0) == KDRIVE_ERROR_NONE))
{
/* register to receive telegrams */
kdrive_ap_register_telegram_callback(ap, &on_telegram_callback, NULL, &key);
/* send group value write telegrams with various datapoint formats */
send_telegrams(ap);
/* go into bus monitor mode */
kdrive_logger(KDRIVE_LOGGER_INFORMATION, "Entering BusMonitor Mode");
kdrive_logger(KDRIVE_LOGGER_INFORMATION, "Press [Enter] to exit the application ...");
getchar();
/* close the access port */
}
/* releases the access port */
return 0;
}
/*******************************
** Private Functions
********************************/
void send_telegrams(int32_t ap)
{
uint32_t length;
/* DPT-1 (1 bit) */
kdrive_dpt_encode_dpt1(buffer, &length, 1);
kdrive_ap_group_write(ap, ADDR_DPT_1, buffer, length);
/* DPT-2: 1 bit controlled */
kdrive_dpt_encode_dpt2(buffer, &length, 1, 1);
kdrive_ap_group_write(ap, ADDR_DPT_2, buffer, length);
/* DPT-3: 3 bit controlled */
kdrive_dpt_encode_dpt3(buffer, &length, 1, 0x05);
kdrive_ap_group_write(ap, ADDR_DPT_3, buffer, length);
/* DPT-4: Character */
kdrive_dpt_encode_dpt4(buffer, &length, 'A');
kdrive_ap_group_write(ap, ADDR_DPT_4, buffer, length);
/* DPT-5: 8 bit unsigned value */
kdrive_dpt_encode_dpt5(buffer, &length, 0x23);
kdrive_ap_group_write(ap, ADDR_DPT_5, buffer, length);
/* DPT-6: 8 bit signed value */
kdrive_dpt_encode_dpt6(buffer, &length, -5);
kdrive_ap_group_write(ap, ADDR_DPT_6, buffer, length);
/* DPT-7: 2 byte unsigned value */
kdrive_dpt_encode_dpt7(buffer, &length, 0xAFFE);
kdrive_ap_group_write(ap, ADDR_DPT_7, buffer, length);
/* DPT-8: 2 byte signed value */
kdrive_dpt_encode_dpt8(buffer, &length, -1024);
kdrive_ap_group_write(ap, ADDR_DPT_8, buffer, length);
/* DPT-9: 2 byte float value */
kdrive_dpt_encode_dpt9(buffer, &length, 12.25f);
kdrive_ap_group_write(ap, ADDR_DPT_9, buffer, length);
/* DPT-10: Local Time */
kdrive_ap_group_write(ap, ADDR_DPT_10_LOCAL, buffer, length);
/* DPT-10: UTC Time */
kdrive_dpt_encode_dpt10_utc(buffer, &length);
kdrive_ap_group_write(ap, ADDR_DPT_10_UTC, buffer, length);
/* DPT-10: Time */
kdrive_dpt_encode_dpt10(buffer, &length, 1, 11, 11, 11);
kdrive_ap_group_write(ap, ADDR_DPT_10, buffer, length);
/* DPT-11: Local Date */
kdrive_ap_group_write(ap, ADDR_DPT_11_LOCAL, buffer, length);
/* DPT-11: UTC Date */
kdrive_dpt_encode_dpt11_utc(buffer, &length);
kdrive_ap_group_write(ap, ADDR_DPT_11_UTC, buffer, length);
/* DPT-11: Date */
kdrive_dpt_encode_dpt11_yyyy(buffer, &length, 2012, 03, 12);
kdrive_ap_group_write(ap, ADDR_DPT_11, buffer, length);
/* DPT-12: 4 byte unsigned value */
kdrive_dpt_encode_dpt12(buffer, &length, 0xDEADBEEF);
kdrive_ap_group_write(ap, ADDR_DPT_12, buffer, length);
/* DPT-13: 4 byte signed value */
kdrive_dpt_encode_dpt13(buffer, &length, -30000);
kdrive_ap_group_write(ap, ADDR_DPT_13, buffer, length);
/* DPT-14: 4 byte float value */
kdrive_dpt_encode_dpt14(buffer, &length, 2025.12345f);
kdrive_ap_group_write(ap, ADDR_DPT_14, buffer, length);
/* DPT-15: Entrance access */
kdrive_dpt_encode_dpt15(buffer, &length, 1234, 0, 1, 1, 0, 10);
kdrive_ap_group_write(ap, ADDR_DPT_15, buffer, length);
/* DPT-16: Character string, 14 bytes */
kdrive_dpt_encode_dpt16(buffer, &length, "Weinzierl Eng");
kdrive_ap_group_write(ap, ADDR_DPT_16, buffer, length);
}
void on_telegram_callback(const uint8_t* telegram, uint32_t telegram_len, void* user_data)
{
static uint8_t sn[KDRIVE_SN_LEN];
uint16_t address = 0;
if ((kdrive_ap_is_group_write(telegram, telegram_len)) &&
(kdrive_ap_get_dest(telegram, telegram_len, &address) == KDRIVE_ERROR_NONE) &&
(kdrive_ap_get_group_data(telegram, telegram_len, data, &data_len) == KDRIVE_ERROR_NONE))
{
switch (address)
{
case ADDR_DPT_1:
{
bool_t value = 0;
kdrive_dpt_decode_dpt1(data, data_len, &value);
kdrive_logger_ex(level, "[1 Bit] %d", value ? 1 : 0);
}
break;
case ADDR_DPT_2:
{
bool_t control = 0;
bool_t value = 0;
kdrive_dpt_decode_dpt2(data, data_len, &control, &value);
kdrive_logger_ex(level, "[1 Bit controlled] %d %d", control, value);
}
break;
case ADDR_DPT_3:
{
bool_t control = 0;
uint8_t value = 0;
kdrive_dpt_decode_dpt3(data, data_len, &control, &value);
kdrive_logger_ex(level, "[3 Bit controlled] %d %d", control, value);
}
break;
case ADDR_DPT_4:
{
uint8_t character = 0;
kdrive_dpt_decode_dpt4(data, data_len, &character);
kdrive_logger_ex(level, "[Character] %d", character);
}
break;
case ADDR_DPT_5:
{
uint8_t value = 0;
kdrive_dpt_decode_dpt5(data, data_len, &value);
kdrive_logger_ex(level, "[8 bit unsigned] 0x%02x", value);
}
break;
case ADDR_DPT_6:
{
int8_t value = 0;
kdrive_dpt_decode_dpt6(data, data_len, &value);
kdrive_logger_ex(level, "[8 bit signed] %d", value);
}
break;
case ADDR_DPT_7:
{
uint16_t value = 0;
kdrive_dpt_decode_dpt7(data, data_len, &value);
kdrive_logger_ex(level, "[2 byte unsigned] 0x%04x", value);
}
break;
case ADDR_DPT_8:
{
int16_t value = 0;
kdrive_dpt_decode_dpt8(data, data_len, &value);
kdrive_logger_ex(level, "[2 byte signed] %d", value);
}
break;
case ADDR_DPT_9:
{
float32_t value = 0;
kdrive_dpt_decode_dpt9(data, data_len, &value);
kdrive_logger_ex(level, "[2 byte float] %f", value);
}
break;
case ADDR_DPT_10_LOCAL:
case ADDR_DPT_10_UTC:
case ADDR_DPT_10:
{
int32_t day = 0;
int32_t hour = 0;
int32_t minute = 0;
int32_t second = 0;
kdrive_dpt_decode_dpt10(data, data_len, &day, &hour, &minute, &second);
kdrive_logger_ex(level, "[time] %d %d %d %d", day, hour, minute, second);
}
break;
case ADDR_DPT_11_LOCAL:
case ADDR_DPT_11_UTC:
case ADDR_DPT_11:
{
int32_t year = 0;
int32_t month = 0;
int32_t day = 0;
kdrive_dpt_decode_dpt11(data, data_len, &year, &month, &day);
kdrive_logger_ex(level, "[date] %d %d %d", year, month, day);
}
break;
case ADDR_DPT_12:
{
uint32_t value = 0;
kdrive_dpt_decode_dpt12(data, data_len, &value);
kdrive_logger_ex(level, "[4 byte unsigned] 0x%08x", value);
}
break;
case ADDR_DPT_13:
{
int32_t value = 0;
kdrive_dpt_decode_dpt13(data, data_len, &value);
kdrive_logger_ex(level, "[4 byte signed] %d", value);
}
break;
case ADDR_DPT_14:
{
float32_t value = 0;
kdrive_dpt_decode_dpt14(data, data_len, &value);
kdrive_logger_ex(level, "[4 byte float] %f", value);
}
break;
case ADDR_DPT_15:
{
int32_t accessCode = 0;
bool_t error = 0;
bool_t permission = 0;
bool_t direction = 0;
bool_t encrypted = 0;
int32_t index = 0;
kdrive_dpt_decode_dpt15(data, data_len, &accessCode, &error, &permission, &direction, &encrypted, &index);
kdrive_logger_ex(level, "[entrance access] %d %d %d %d %d",
accessCode, error, permission, direction, encrypted, index);
}
break;
case ADDR_DPT_16:
{
/* kdrive_dpt_decode_dpt16 is null terminated, so we need KDRIVE_DPT16_LENGTH + 1 */
char value[KDRIVE_DPT16_LENGTH + 1];
kdrive_dpt_decode_dpt16(data, data_len, value);
kdrive_logger_ex(level, "[character string] %s", value);
}
break;
default:
kdrive_logger_ex(KDRIVE_LOGGER_INFORMATION, "A_GroupValue_Write: 0x%04x ", address);
kdrive_logger_dump(KDRIVE_LOGGER_INFORMATION, "A_GroupValue_Write Data :", data, data_len);
}
}
}
void error_callback(error_t e, void* user_data)
{
{
static char error_message[ERROR_MESSAGE_LEN];
kdrive_get_error_message(e, error_message, ERROR_MESSAGE_LEN);
kdrive_logger_ex(KDRIVE_LOGGER_ERROR, "kdrive error: %s", error_message);
}
}
kdriveExpress_API error_t kdrive_ap_get_group_data(const uint8_t telegram[], uint32_t telegram_len, uint8_t *data, uint32_t *data_len)
Extracts the Group Value data from the KNX telegram.
kdriveExpress_API error_t kdrive_ap_group_write(int32_t ap, uint16_t address, const uint8_t *value, uint32_t bits)
Sends a GroupValue_Write Telegram The length is specified in bits to enable values less than one byte...
kdriveExpress_API uint32_t kdrive_ap_enum_usb(int32_t ap)
Scan for all KNX USB Interface devices.
kdriveExpress_API bool_t kdrive_ap_is_group_write(const uint8_t telegram[], uint32_t telegram_len)
Determines if the specified telegram is a GroupValue_Write telegram.
kdriveExpress_API bool_t kdrive_ap_release(int32_t ap)
Releases the AccessPort interface.
kdriveExpress_API int32_t kdrive_ap_create(void)
Creates an internal AccessPort interface This should be the first function called when working with t...
kdriveExpress_API error_t kdrive_ap_close(int32_t ap)
Closes the access port If the access port is not open nothing happens.
kdriveExpress_API error_t kdrive_ap_open_usb(int32_t ap, uint32_t iface_index)
Opens a connection to a KNX USB Interface device iface_index should be in the range 0....
kdriveExpress_API error_t kdrive_ap_get_dest(const uint8_t telegram[], uint32_t telegram_len, uint16_t *address)
Extracts the Destination Address from the Telegram.
kdriveExpress_API error_t kdrive_ap_register_telegram_callback(int32_t ap, kdrive_ap_telegram_callback c, void *user_data, uint32_t *key)
Registers a callback function.
kdriveExpress_API error_t kdrive_dpt_decode_dpt9(const uint8_t *data, uint32_t length, float32_t *value)
Gets DPT-9: 2 byte float value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt11(const uint8_t *data, uint32_t length, int32_t *year, int32_t *month, int32_t *day)
Gets DPT-11: date in KNX format NOTE: The year is in KNX DPT11 format: 0..99; >=90 : 20th century; <9...
kdriveExpress_API error_t kdrive_dpt_decode_dpt14(const uint8_t *data, uint32_t length, float32_t *value)
Gets DPT-14: 4 byte float value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt2(const uint8_t *data, uint32_t length, bool_t *control, bool_t *value)
Gets DPT-2: 1 bit controlled.
kdriveExpress_API error_t kdrive_dpt_encode_dpt1(uint8_t *data, uint32_t *length, bool_t value)
Sets DPT-1 (1 bit)
kdriveExpress_API error_t kdrive_dpt_decode_dpt4(const uint8_t *data, uint32_t length, uint8_t *character)
Gets DPT-4: Character.
kdriveExpress_API error_t kdrive_dpt_encode_dpt7(uint8_t *data, uint32_t *length, uint16_t value)
Sets DPT-7: 2 byte unsigned value.
kdriveExpress_API error_t kdrive_dpt_encode_dpt3(uint8_t *data, uint32_t *length, bool_t control, uint8_t value)
Sets DPT-3: 3 bit controlled.
kdriveExpress_API error_t kdrive_dpt_encode_dpt2(uint8_t *data, uint32_t *length, bool_t control, bool_t value)
Sets DPT-2: 1 bit controlled.
kdriveExpress_API error_t kdrive_dpt_decode_dpt6(const uint8_t *data, uint32_t length, int8_t *value)
Gets DPT-6: 8 bit signed value.
kdriveExpress_API error_t kdrive_dpt_encode_dpt11_local(uint8_t *data, uint32_t *length)
Sets DPT-11: current local date.
kdriveExpress_API error_t kdrive_dpt_encode_dpt16(uint8_t *data, uint32_t *length, const char value[KDRIVE_DPT16_LENGTH+1])
Sets DPT-16: Character string.
kdriveExpress_API error_t kdrive_dpt_encode_dpt10_local(uint8_t *data, uint32_t *length)
Sets DPT-10: local time.
kdriveExpress_API error_t kdrive_dpt_encode_dpt5(uint8_t *data, uint32_t *length, uint8_t value)
Sets DPT-5: 8 bit unsigned value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt16(const uint8_t *data, uint32_t length, char value[KDRIVE_DPT16_LENGTH+1])
Gets DPT-16: Character string The out value string is null terminated.
kdriveExpress_API error_t kdrive_dpt_encode_dpt4(uint8_t *data, uint32_t *length, uint8_t character)
Sets DPT-4: Character.
kdriveExpress_API error_t kdrive_dpt_encode_dpt14(uint8_t *data, uint32_t *length, float32_t value)
Sets DPT-14: 4 byte float value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt8(const uint8_t *data, uint32_t length, int16_t *value)
Gets DPT-8: 2 byte signed value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt15(const uint8_t *data, uint32_t length, int32_t *accessCode, bool_t *error, bool_t *permission, bool_t *direction, bool_t *encrypted, int32_t *index)
Gets DPT-15: Entrance access.
kdriveExpress_API error_t kdrive_dpt_encode_dpt13(uint8_t *data, uint32_t *length, int32_t value)
Sets DPT-13: 4 byte signed value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt1(const uint8_t *data, uint32_t length, bool_t *value)
Gets DPT-1 (1 bit)
kdriveExpress_API error_t kdrive_dpt_encode_dpt6(uint8_t *data, uint32_t *length, int8_t value)
Sets DPT-6: 8 bit signed value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt13(const uint8_t *data, uint32_t length, int32_t *value)
Gets DPT-13: 4 byte signed value.
kdriveExpress_API error_t kdrive_dpt_encode_dpt15(uint8_t *data, uint32_t *length, int32_t accessCode, bool_t error, bool_t permission, bool_t direction, bool_t encrypted, int32_t index)
Sets DPT-15: Entrance access.
kdriveExpress_API error_t kdrive_dpt_decode_dpt7(const uint8_t *data, uint32_t length, uint16_t *value)
Gets DPT-7: 2 byte unsigned value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt10(const uint8_t *data, uint32_t length, int32_t *day, int32_t *hour, int32_t *minute, int32_t *second)
Gets DPT-10: time.
kdriveExpress_API error_t kdrive_dpt_decode_dpt3(const uint8_t *data, uint32_t length, bool_t *control, uint8_t *value)
Gets DPT-3: 3 bit controlled.
kdriveExpress_API error_t kdrive_dpt_encode_dpt9(uint8_t *data, uint32_t *length, float32_t value)
Sets DPT-9: 2 byte float value.
kdriveExpress_API error_t kdrive_dpt_encode_dpt11_utc(uint8_t *data, uint32_t *length)
Sets DPT-11: current UTC date.
kdriveExpress_API error_t kdrive_dpt_decode_dpt12(const uint8_t *data, uint32_t length, uint32_t *value)
Gets DPT-12: 4 byte unsigned value.
kdriveExpress_API error_t kdrive_dpt_encode_dpt12(uint8_t *data, uint32_t *length, uint32_t value)
Sets DPT-12: 4 byte unsigned value.
kdriveExpress_API error_t kdrive_dpt_decode_dpt5(const uint8_t *data, uint32_t length, uint8_t *value)
Gets DPT-5: 8 bit unsigned value.
kdriveExpress_API error_t kdrive_dpt_encode_dpt11_yyyy(uint8_t *data, uint32_t *length, int32_t year, int32_t month, int32_t day)
Sets DPT-11: date in "normal" format.
kdriveExpress_API error_t kdrive_dpt_encode_dpt10_utc(uint8_t *data, uint32_t *length)
Sets DPT-10: UTC time.
kdriveExpress_API error_t kdrive_dpt_encode_dpt10(uint8_t *data, uint32_t *length, int32_t day, int32_t hour, int32_t minute, int32_t second)
Sets DPT-10: time.
kdriveExpress_API error_t kdrive_dpt_encode_dpt8(uint8_t *data, uint32_t *length, int16_t value)
Sets DPT-8: 2 byte signed value.
kdriveExpress_API void kdrive_logger(uint8_t level, const char *message)
Writes to the kdrive express logger.
kdriveExpress_API void kdrive_logger_dump(uint8_t level, const char *message, const void *buffer, uint32_t buffer_len)
Logs the given message, followed by the data in buffer.
kdriveExpress_API void kdrive_logger_console(void)
Sets the logger to write to the console.
kdriveExpress_API void kdrive_logger_ex(uint8_t level, const char *fmt,...)
Writes to the kdrive express logger.
kdriveExpress_API void kdrive_logger_set_level(uint8_t level)
Sets the root logger level This is once of:
unsigned short uint16_t
16 bit unsigned char
Definition: kdrive_express_config.h:30
int int32_t
32 bit signed int
Definition: kdrive_express_config.h:34
unsigned int uint32_t
32 bit unsigned char
Definition: kdrive_express_config.h:31
float float32_t
32 bit single precision float
Definition: kdrive_express_config.h:35
int32_t error_t
Definition: kdrive_express_config.h:46
int32_t bool_t
Definition: kdrive_express_config.h:57
short int16_t
16 bit signed int
Definition: kdrive_express_config.h:33
unsigned char uint8_t
8 bit unsigned char
Definition: kdrive_express_config.h:29
signed char int8_t
8 bit signed char
Definition: kdrive_express_config.h:32
#define KDRIVE_SN_LEN
The Length of a KNX Serial Number.
Definition: kdrive_express_defs.h:34
#define KDRIVE_INVALID_DESCRIPTOR
Indicates an invalid descriptor.
Definition: kdrive_express_defs.h:39
#define KDRIVE_MAX_GROUP_VALUE_LEN
The Maximum Length of a Datapoint Value in a GroupValue Telegram.
Definition: kdrive_express_defs.h:33
#define KDRIVE_DPT16_LENGTH
The length of a KNX character string for DPT-16 is 112 bits or 14 bytes.
Definition: kdrive_express_defs.h:40
kdriveExpress_API void kdrive_register_error_callback(kdrive_error_callback c, void *user_data)
Registers the error callback function.
#define KDRIVE_TIMEOUT_ERROR
Timeout.
Definition: kdrive_express_error.h:26
#define KDRIVE_ERROR_NONE
No Error, Everything OK.
Definition: kdrive_express_error.h:22
kdriveExpress_API void kdrive_get_error_message(error_t e, char *str, uint32_t str_len)
Gets the error message.
#define KDRIVE_LOGGER_FATAL
A fatal error.
Definition: kdrive_express_logger.h:26
#define KDRIVE_LOGGER_ERROR
An error.
Definition: kdrive_express_logger.h:28
#define KDRIVE_LOGGER_INFORMATION
An informational message, usually denoting the successful completion of an operation.
Definition: kdrive_express_logger.h:31