ULog 파일 포맷
ULog는 logging 시스템 데이터에 사용하는 파일 포맷입니다. 이 포맷은 자기기술(self-describing)형태로 예를 들자면 log 포맷과 메시지 타입을 포함하고 있습니다.
logging 입력 장치(센서), 내부 상태와 log 메시지 출력하는데 사용할 수 있습니다.
모든 binary 타입에서 Little Endian을 사용합니다.
Data 타입
다음과 같은 binary 타입을 사용합니다. 이 타입들은 C언어의 타입에 대응됩니다. :
Type | Size in Bytes |
---|---|
int8_t, uint8_t | 1 |
int16_t, uint16_t | 2 |
int32_t, uint32_t | 4 |
int64_t, uint64_t | 8 |
float | 4 |
double | 8 |
bool, char | 1 |
추가로 모두 array(예로 float[5]
)로 사용할 수 있습니다. 일반적으로 모든 string(char[length]
)에 끝을 나타내는 '\0'
을 포함하지 않습니다. string 비교에서는 대소문자를 구별합니다.
파일 구조
파일은 3개 섹션으로 구성:
----------------------
| Header |
----------------------
| Definitions |
----------------------
| Data |
----------------------
헤더 섹션
헤더는 고정길이를 갖는 섹션이며 다음과 같은 포맷을 가집니다. (16 bytes) :
----------------------------------------------------------------------
| 0x55 0x4c 0x6f 0x67 0x01 0x12 0x35 | 0x00 | uint64_t |
| File magic (7B) | Version (1B) | Timestamp (8B) |
----------------------------------------------------------------------
Version은 파일 포맷 버전이며 현재는 0입니다. Timestamp은 uint64_t integer로 microseconds 단위로 logging의 시작을 의미합니다.
Definitions Section
가변길이 섹션으로 version 정보, format 정의와 (초기) 파라미터 값을 포함합니다.
Definitions과 Data 섹션은 일종의 메시지의 stream으로 구성됩니다. 각각은 다음과 같은 헤더로 시작합니다. :
struct message_header_s {
uint16_t msg_size;
uint8_t msg_type
};
msg_size
는 header(hdr_size
= 3 bytes)가 없는 byte 단위의 메시지의 크기입니다. msg_type
는 content를 정의하며 다음 중에 하나를 따릅니다. :
- 'F': 단일(복합) 타입에 대한 포맷 정의로 로깅하거나 nested 타입으로 다른 definition에서 사용.
struct message_format_s {
struct message_header_s header;
char format[header.msg_size-hdr_size];
};
format
: 다음 포맷을 가지는 일반 텍스트 문자열: message_name:field0;field1;
구분자로 ;
를 사용하며 최소 1개 이상의 임의 필드를 가질 수 있음.
필드는 다음 포맷을 가짐: type field_name
혹은 array(고정 길이 array만 지원)에 대한 type[array_length] field_name
. type
은 기본 binary 타입 중에 하나 혹은 다른 포맷 정의(nest로 사용)의 message_name
.
type은 정의하기 전에 사용할 수도 있음. 임의의 nesting일 수는 있지만 순환 종속성은 없어야 함.
일부 필드 이름은 특별하게 :
- `timestamp`: 모든 logged message(`message_add_logged_s`)는 반드시 timestamp field을 포함해야 함(첫번째 필드일 필요는 없음). 타입으로 `uint64_t` (현재 유일하게 사용), `uint32_t`, `uint16_t` 혹은
`uint8_t`. `uint8_t` 인 경우만 milliseconds고 나머지는 항상 microseconds임. log writer는 wrap-arounds를 검출할 수 있게 메시지 로그를 해야하며 log reader는 반드시 wrap-arounds를 처리해야만 함.(드롭아웃에 대해서도 고려해야함) timestamp는 동일 `msg_id`를 가지는 일련의 메시지에 대해서 항상 증가.
- Padding: 필드 이름은 `_padding`로 시작함. 표시되는 부분이 아니며 reader쪽에서 이 값은 무시됨. writerrk 이 필드를 채워줘서 올바른 형태로 만들어줌.
padding 필드가 마지막 필드인 경우라면 불필요한 데이터를 쓰는 것을 피하기 위해서 이 필드는 기록하지 않는다. 즉 padding의 크기만큼 `message_data_s.data`는 줄어들게 됨. message를 nested definition에 사용할때도 padding은 여전히 필요함.
'I': information message.
struct message_info_s { struct message_header_s header; uint8_t key_len; char key[key_len]; char value[header.msg_size-hdr_size-1-key_len] };
key
는 일반 문자열이며 format message내에서;
로 마무리하지 않고 단일 필드로만 구성됨. 예제로float[3] myvalues
.value
는key
에 설정한 데이터를 포함함.미리 정의된 information messages:
key |
Description | Example for value |
---|---|---|
char[value_len] sys_name | Name of the system | "PX4" |
char[value_len] ver_hw | Hardware version | "PX4FMU_V4" |
char[value_len] ver_sw | Software version (git tag) | "7f65e01" |
uint32_t ver_sw_release | Software version (see below) | 0x010401ff |
char[value_len] sys_os_name | Operating System Name | "Linux" |
char[value_len] sys_os_ver | OS version (git tag) | "9f82919" |
uint32_t ver_os_release | OS version (see below) | 0x010401ff |
char[value_len] sys_toolchain | Toolchain Name | "GNU GCC" |
char[value_len] sys_toolchain_ver | Toolchain Version | "6.2.1" |
char[value_len] sys_mcu | Chip name and revision | "STM32F42x, rev A" |
char[value_len] sys_uuid | Unique identifier for vehicle (eg. MCU ID) | "392a93e32fa3"... |
char[value_len] replay | File name of replayed log if in replay mode | "log001.ulg" |
int32_t time_ref_utc | UTC Time offset in seconds | -3600 |
ver_sw_release
와 ver_os_release
의 포맷은 : 0xAABBCCTT. AA는 major, BB는 minor, CC는 path, TT는 타입. type은 다음과 같이 정의 : >= 0
: development, >= 64
: alpha version, >= 128
: beta version, >= 192
: RC version, == 255
: release version.
따라서 0x010402ff는 release version v1.4.2으로 해석할 수 있음.
이 메시지는 Data 섹션에서 사용할 수 있습니다.(하지만 이것이 선호되는 섹션)
- 'P': 파리미터 메시지.
message_info_s
와 동일한 포맷. 만약 실행하는 동안 파라미터가 동적으로 변경되면, 이 메시지는 Data 섹션에서 사용할 수 있음. data type은int32_t
,float
만 사용가능.
message_add_logged_s
나 message_logging_s
메시지가 시작하기 전에 이 섹션은 종료된다. 둘 중에 어떤 것이든 먼저 올 수 있음.
Data Section
다음과 같은 메시지가 이 섹션에 속합니다. :
- 'A': name으로 메시지를 subscribe하고
message_data_s
내 사용할 id를 부여함. 이 과정은 반드시 첫번째 관련message_data_s
전에 해야함.
struct message_add_logged_s {
struct message_header_s header;
uint8_t multi_id;
uint16_t msg_id;
char message_name[header.msg_size-hdr_size-3];
};
multi_id
: 동일한 메시지 포맷은 다양한 인스턴스를 가질 수 있음. 예로 만약 시스템이 동일한 타입의 2개 센서를 가지고 있다면 기본적으로 첫번째 인스턴스는 0이 되어야 함.
msg_id
: message_data_s
data를 매칭하는데 고유 id 사용. 처음 사용에서 반드시 0으로 설정하고 증가시킴. 동일 msg_id
는 중복해서 사용해서는 안되며 unsubscribe 하더라도 중복사용은 안됨.
message_name
: subscribe할 메시지 이름. message_format_s
definition들 중에 하나와 매칭되어야 함.
struct message_remove_logged_s {
struct message_header_s header;
uint16_t msg_id;
};
'D': logged data 포함
struct message_data_s { struct message_header_s header; uint16_t msg_id; uint8_t data[header.msg_size-hdr_size]; };
msg_id
:message_add_logged_s
메시지에서 정의.message_format_s
정의에 따라data
는 logged binary message를 포함. 위에 padding 필드의 처리에 관련 부분을 참고.'L': Logged string message. 예로 printf 출력.
struct message_logging_s { struct message_header_s header; uint8_t log_level; uint64_t timestamp; char message[header.msg_size-hdr_size-9] };
timestamp
: microseconds 단위,log_level
: Linux 커널에서와 동일 :
Name | Level value | Meaning |
---|---|---|
EMERG | '0' | System is unusable |
ALERT | '1' | Action must be taken immediately |
CRIT | '2' | Critical conditions |
ERR | '3' | Error conditions |
WARNING | '4' | Warning conditions |
NOTICE | '5' | Normal but significant condition |
INFO | '6' | Informational |
DEBUG | '7' | Debug-level messages |
'S': 동기화 메시지로 reader가 오류가 있는 메시지를 복구하기 위해 다음 동기화 메시지를 이용함. (현재 사용 안됨)
struct message_sync_s { struct message_header_s header; uint8_t sync_magic[8]; };
sync_magic
: 정의할 예정'O': 주어진 ms 시간 구간의 드롭아웃(로그 메시지 손실)을 표시함. 드롭아웃은 장치의 처리 속도가 느린 경우에 발생할 수 있음.
struct message_dropout_s { struct message_header_s header; uint16_t duration; };
'I': information message. 위를 참고.
'P': parameter message. 위를 참고.