xm_api_logging.h — USB-CDC 구조체 로깅¶
🟢 Rev 2.0 전용 (v2.9.0 신규) — 본 헤더와
xm_api_logging_raw.h는 XM10 Rev 2.0 SDK 에만 포함되어 있습니다. Rev 1.1 SDK (XM10_SDK/Rev1.1/) 에는 두 헤더가 모두 없으므로, Rev 1.1 프로젝트에서 include 하면 빌드가 실패합니다. 보드 리비전 확인은 보드 리비전 비교 참고.
- 대상 헤더:
XM_FW/XM_API/xm_api_logging.h·XM_FW/XM_API/xm_api_logging_raw.h- 관련 개념 문서: 10. 구조체 로깅
- 관련 예제: Ex.44 CDC Struct Logging — 구조체 둘을 이름 · 단위 · 타입과 함께 PC 로 보냅니다
언제 사용하나¶
직접 만든 구조체를 필드 이름 · 단위 · 타입과 함께 PC 로 보낼 때 사용합니다. 기존 방식(XM_SetUsbCustomMeta + XM_SendUsbDataWithId)과의 차이, 한도, PC 에서 보이는 모습, 흔한 실수 같은 전체 그림은 10. 구조체 로깅 을 먼저 읽어 보세요 — 이 페이지는 헤더에 선언된 모든 매크로 · 함수 · 타입의 시그니처 · 파라미터 · 반환값만 다룹니다.
xm_api.h 가 이 헤더를 함께 불러오므로 XM_LOG_* · XM_FIELD* · XM_Log_* 이름은 SDK 가 씁니다. 같은 이름을 직접 만들지 마세요.
include¶
#include "xm_api.h" // xm_api_logging.h 를 함께 불러옵니다
#include "xm_api_logging_raw.h" // XM_LOG_* 매크로를 쓰는 .c 파일은 꼭 include 하세요
xm_api.h 는 xm_api_logging.h 를 포함하지만 xm_api_logging_raw.h 는 포함하지 않습니다. XM_LOG_REGISTER · XM_LOG_SEND 매크로가 안에서 부르는 함수의 원형이 그 헤더에 있어서, 빠지면 매크로 줄에서 implicit declaration of function 빌드 오류가 납니다.
기본 사용 흐름¶
#include "xm_api.h"
#include "xm_api_logging_raw.h"
typedef struct {
float hip_angle;
int16_t emg[8];
uint32_t mode;
} MyLog_t; // 24 B — 크기는 4 의 배수
XM_LOG_DECLARE(MyLog, MyLog_t); // 토큰 MyLog ↔ 구조체 MyLog_t
XM_LOG_FIELDS(MyLog) = {
XM_FIELD(MyLog, hip_angle, "hip_angle", "deg", 1.0f),
XM_FIELD_ARRAY(MyLog, emg, "emg", "mV", 1.0f),
XM_FIELD(MyLog, mode, "mode", "", 1.0f),
};
void Control_Setup(void)
{
if (!XM_LOG_REGISTER(MyLog, 0xF0, 1000)) {
// 등록 실패는 LED 로 알립니다 — Control_Setup() 에서는 보통 USB 가 아직 준비되지 않아 메시지가 나가지 않습니다
XM_SetLedEffect(XM_LED_1, XM_LED_BLINK, 200);
}
}
void Control_Loop(void)
{
MyLog_t s = { 0 };
(void)XM_LOG_SEND(MyLog, &s); // 등록한 주기보다 일찍 부르면 보내지 않고 false
}
네 매크로(XM_LOG_DECLARE · XM_LOG_FIELDS · XM_LOG_REGISTER · XM_LOG_SEND)는 같은 .c 파일 안에서 씁니다. 매크로는 C 파일 전용입니다. 지원하지 않는 멤버 타입, 4 의 배수가 아닌 크기, 다른 구조체 포인터처럼 틀린 사용은 컴파일러가 그 줄을 가리킵니다.
함수 · 매크로 목록¶
구조체 정의 · 등록 · 전송 (매크로)
| 매크로 | 한 줄 설명 |
|---|---|
XM_LOG_DECLARE |
토큰과 구조체 타입을 묶습니다 (.c 파일 위쪽) |
XM_LOG_FIELDS |
필드 설명 배열을 정의합니다 |
XM_FIELD |
스칼라 멤버 한 줄 |
XM_FIELD_ARRAY |
배열 멤버 한 줄 |
XM_LOG_REGISTER |
구조체를 등록합니다 (Control_Setup()) |
XM_LOG_SEND |
등록한 구조체 하나를 보냅니다 (Control_Loop()) |
설정 · 진단 (함수)
| 함수 | 한 줄 설명 |
|---|---|
XM_Log_SetMinStallMs |
PC 프로그램이 잠시 멈춰도 데이터를 담아 두는 목표 시간(ms) 설정 |
XM_Log_GetMinStallMs |
지금 쓰는 목표 시간(ms) — 진단용 |
XM_Log_EnableLinkHealth |
링크 상태 정보 전송 켜기 / 끄기 |
XM_Log_GetAdmittedWireBps |
이미 정해진 송신 몫(바이트/초) — 진단용 |
XM_Log_GetStats |
관측 카운터 복사 |
지원 헤더 xm_api_logging_raw.h — 직접 호출 금지
| 함수 | 한 줄 설명 |
|---|---|
XM_Log_RegisterSchemaRaw |
XM_LOG_REGISTER 가 부르는 함수 |
XM_Log_SendRaw |
XM_LOG_SEND 가 부르는 함수 |
함수 · 매크로 상세¶
XM_LOG_DECLARE¶
토큰과 구조체 타입을 묶습니다. .c 파일 위쪽에 한 번 씁니다. 토큰이 구조체 이름이 됩니다.
파라미터
| 이름 | 설명 |
|---|---|
tok |
토큰(짧은 이름) — 11자 이하 (XM_LOG_MAX_TOKEN_LEN), 영문 · 숫자 · _ |
Type |
보낼 구조체 타입 — 크기는 4 의 배수, 1,008 B 이하 |
반환값: 없음 (선언 매크로)
아래 경우에는 이 줄에서 컴파일 오류가 납니다.
| 컴파일 오류 | 원인 |
|---|---|
... must be a multiple of 4 - add padding |
구조체 크기가 4 의 배수가 아님 |
... exceeds XM_LOG_MAX_STRUCT_SIZE |
구조체 크기가 1,008 B 를 넘음 |
token ... longer than 11 chars |
토큰이 11자를 넘음 |
크기를 맞출 때는 끝에 uint8_t 배열을 더하세요. 그 배열은 XM_FIELD 로 적지 않아도 됩니다.
⚠️ 호출 컨텍스트: 파일 범위(함수 밖)에 씁니다. 같은 .c 파일 안의 XM_LOG_FIELDS · XM_LOG_REGISTER · XM_LOG_SEND 와 같은 토큰을 씁니다.
예제
typedef struct {
float angle; // [deg]
float torque; // [Nm]
} JointLog_t; // 8 B
XM_LOG_DECLARE(JointLog, JointLog_t);
참고: XM_LOG_FIELDS, XM_LOG_REGISTER
XM_LOG_FIELDS¶
필드 설명 배열을 정의합니다. 뒤에 = { XM_FIELD(...), ... }; 를 씁니다. 중괄호 안에는 같은 토큰의 XM_FIELD · XM_FIELD_ARRAY 만 쓰세요. 컴파일러가 이 규칙은 검사하지 못합니다.
파라미터
| 이름 | 설명 |
|---|---|
tok |
XM_LOG_DECLARE 의 토큰 |
반환값: 없음 (정의 매크로)
필드는 1 ~ 90개입니다. 0개이거나 90개를 넘으면 XM_LOG_REGISTER 줄에서 컴파일 오류(field count must be 1..90)가 납니다.
⚠️ 호출 컨텍스트: 파일 범위(함수 밖)에 씁니다. XM_LOG_REGISTER 보다 앞에 있어야 합니다.
예제
XM_LOG_FIELDS(JointLog) = {
XM_FIELD(JointLog, angle, "angle", "deg", 1.0f),
XM_FIELD(JointLog, torque, "torque", "Nm", 1.0f),
};
참고: XM_FIELD, XM_FIELD_ARRAY
XM_FIELD¶
스칼라 멤버 한 줄입니다. 타입과 위치는 멤버에서 정해집니다.
파라미터
| 이름 | 설명 |
|---|---|
tok |
XM_LOG_DECLARE 의 토큰 |
member |
구조체 멤버 이름 |
nm |
필드 이름 — 영문 · 숫자 · 기호(ASCII) 15자까지 (한글 · ° 처럼 ASCII 가 아닌 글자는 등록이 false) |
un |
단위 — 영문 · 숫자 · 기호(ASCII) 7자까지, 없으면 "" (예: "deg") |
sc |
배율 — 물리값 = 저장값 × sc (보통 1.0f) |
반환값: 없음 (XM_FieldDesc_t 초기화 식)
지원하는 멤버 타입은 float · double · bool · int · unsigned · int8_t ~ uint64_t 입니다. 열거형 멤버는 크기가 같은 정수 타입으로 받습니다. 그 밖의 타입(char · 포인터 · 구조체 · 배열 등)은 컴파일 오류(unsupported member type)입니다.
⚠️ 호출 컨텍스트: XM_LOG_FIELDS 의 중괄호 안에서만 씁니다.
예제
참고: XM_FIELD_ARRAY, XM_FieldType_e
XM_FIELD_ARRAY¶
배열 멤버 한 줄입니다. 원소 타입과 개수(1 ~ 255)는 배열에서 정해집니다. 포인터 멤버나 256개 이상인 배열은 컴파일 오류입니다. 인자는 XM_FIELD 와 같습니다.
파라미터: XM_FIELD 와 같습니다.
반환값: 없음 (XM_FieldDesc_t 초기화 식)
⚠️ 호출 컨텍스트: XM_LOG_FIELDS 의 중괄호 안에서만 씁니다.
예제
참고: XM_FIELD
XM_LOG_REGISTER¶
구조체를 등록합니다. Control_Setup() 안에서 부릅니다. 실제로 부르는 함수는 XM_Log_RegisterSchemaRaw 입니다.
파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
tok |
토큰 | XM_LOG_DECLARE 의 토큰 (XM_LOG_FIELDS 가 앞에 있어야 합니다) |
module_id |
uint8_t |
이 구조체를 보낼 모듈 ID — 0xF0 ~ 0xFE |
nominal_rate_hz |
uint16_t |
보낼 주기(Hz) — XM_LOG_SEND 를 더 자주 불러도 이보다 자주 나가지 않습니다 |
간격을 1 ms 단위로 올려 잡아서 1,000 의 약수가 아니면 덜 자주 나갑니다 (예: 300 Hz → 250 Hz, 600 Hz → 500 Hz). 1,000 Hz 보다 자주는 나가지 않습니다.
반환값: bool — true: 등록됨. false: 아래 표 참고.
false 가 되는 경우 |
해결 |
|---|---|
| 이 토큰을 이미 등록함 | 토큰마다 한 번만 등록합니다 |
모듈 ID 가 0xF0 ~ 0xFE 밖이거나 이미 쓰임 |
남은 ID 를 씁니다 |
| 등록이 4개를 넘음 | 구조체는 4개까지 등록합니다 |
nominal_rate_hz 가 0 |
1 이상으로 정합니다 |
| 필드 이름이 겹치거나 두 필드가 구조체의 같은 바이트를 가리킴 | 필드 이름 · 멤버를 확인합니다 |
| 필드 이름 · 단위가 너무 길거나, 토큰 · 필드 이름 · 단위에 ASCII 가 아닌 글자(한글 등)가 있음 | 토큰은 영문 · 숫자 · _ 로, 이름은 15자 · 단위는 7자 이하의 ASCII 문자로 고칩니다 |
scale 이 0 이거나 숫자가 아님 (무한대 · NaN) |
0 이 아닌 값으로 정합니다 |
| 보낼 양이 USB 로 보낼 수 있는 양을 넘음 (먼저 등록한 구조체와 합쳐서 셉니다) | 주기를 낮추거나 구조체를 줄입니다 |
먼저 등록한 구조체와 합친 양이 PC 프로그램이 잠시 멈춰도 담아 둘 수 있는 양을 넘음 (XM_Log_SetMinStallMs 참고) |
주기를 낮추거나 구조체를 줄입니다 |
Control_Setup() 밖(Control_Setup() 이 끝난 뒤 · 다른 태스크 · 인터럽트)에서 부름 |
Control_Setup() 안에서 부릅니다 |
false면 등록 상태는 바뀌지 않으니Control_Setup()안에서 고쳐 다시 부를 수 있습니다.false여도 이미 등록된 같은 토큰은 그대로 보낼 수 있습니다.- 필드는 1 ~ 90개입니다. 0개이거나 90개를 넘으면 컴파일 오류입니다.
- 등록한 모듈 ID 는
XM_LOG_SEND전용입니다. 같은 ID 로XM_SendUsbDataWithId()를 부르면false입니다. Control_Setup()이 끝난 뒤 부르면seal_reject_count가, 다른 태스크 · 인터럽트에서 부르면owner_violation_count가 오릅니다 (XM_LogStats_t).- 어느 크기 · 주기까지 등록되는지는 보드에서 아직 확인하지 못했습니다. (보드 확인 전)
첫 등록에 성공하면 아래가 달라집니다 (자세한 내용은 10. 구조체 로깅 7장).
XM_USB_SetHostProfile()호출이 무시됩니다.XM_Log_SetMinStallMs()가false를 돌려줍니다.XM_SetUsbCustomMeta()는Control_Setup()안에서만 쓸 수 있습니다. 그 뒤에 부르면false입니다.- 등록한 모듈 ID 는 이 구조체 전용이 됩니다.
XM_SendUsbDataWithId()·XM_SendUsbDebugMessage()로 보내는 양에 한도가 생깁니다.- 보드가 필드 이름 · 단위 · 타입을 PC 로 보냅니다. PC 프로그램이 포트를 열 때 전달되고 그 뒤에도 몇 초 간격으로 다시 보냅니다. (설계 목표, 보드 확인 전)
⚠️ 호출 컨텍스트: Control_Setup() 안에서만 부릅니다.
예제
void Control_Setup(void)
{
if (!XM_LOG_REGISTER(JointLog, 0xF0, 500)) { // 500 Hz — 2 ms 마다
XM_SetLedEffect(XM_LED_3, XM_LED_BLINK, 200);
}
}
참고: XM_LOG_SEND, XM_Log_SetMinStallMs
XM_LOG_SEND¶
등록한 구조체 하나를 보냅니다. Control_Loop() 안에서 부릅니다. 실제로 부르는 함수는 XM_Log_SendRaw 입니다. 구조체는 호출 안에서 복사되므로 지역 변수여도 됩니다.
파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
tok |
토큰 | XM_LOG_DECLARE 의 토큰 |
ptr |
구조체 포인터 | 그 구조체의 포인터 — 다른 타입의 포인터는 컴파일 오류입니다 |
반환값: bool — true: 보냄 (보낼 버퍼에 담았다는 뜻이며 PC 가 받았는지와는 무관합니다). false: 아래 중 하나.
- 등록 안 됨 (
XM_LOG_REGISTER가false였던 토큰 포함) ptr가NULL- 등록 주기보다 일찍 부름
- USB 장치가 준비되지 않음
- 송신 버퍼가 가득 참
Control_Setup()·Control_Loop()밖(다른 태스크 · 인터럽트)에서 부름
매 루프 불러도 등록한 주기로만 나가므로, 주기가 되기 전의 false 는 정상입니다. 송신 버퍼가 가득 차 false 가 나와도 다음 송신은 등록한 주기가 지난 뒤에 나갑니다 (바로 다시 불러도 보내지 않습니다). Control_Setup() · Control_Loop() 밖에서 부르면 owner_violation_count 가 오릅니다 (XM_LogStats_t).
⚠️ 호출 컨텍스트: Control_Loop() 안에서 부릅니다. 인터럽트 · 직접 만든 백그라운드 태스크(XM_Task_*)에서는 부르지 마세요.
예제
void Control_Loop(void)
{
JointLog_t s = { XM.status.h10.leftHipAngle, XM.status.h10.leftHipTorque };
(void)XM_LOG_SEND(JointLog, &s); // 매 루프 불러도 500 Hz 로만 나갑니다
}
참고: XM_LOG_REGISTER, XM_Log_GetStats
XM_Log_SetMinStallMs¶
PC 프로그램이 잠시 멈춰도 보드가 데이터를 빠뜨리지 않고 담아 두는 목표 시간(ms)을 정합니다. 기본값은 50 ms 입니다. 이 목표를 지킬 수 없을 만큼 많이 보내는 구조체의 등록은 false 가 됩니다. 50 ms 는 아직 보드에서 재 보지 않은 초기값이라 보장이 아니라 목표입니다. (설계 목표)
파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
ms |
uint16_t |
목표 시간(ms) |
반환값: bool — true: 바뀜. false: Control_Setup() 밖에서 부름, 또는 등록에 성공한 구조체가 이미 있음
⚠️ 호출 컨텍스트: Control_Setup() 안에서, 첫 XM_LOG_REGISTER 보다 먼저 부릅니다.
예제
void Control_Setup(void)
{
(void)XM_Log_SetMinStallMs(100); // 값은 예시입니다 — 기본 50 ms 로 충분하면 부르지 않아도 됩니다
(void)XM_LOG_REGISTER(JointLog, 0xF0, 500);
}
참고: XM_Log_GetMinStallMs, XM_LOG_REGISTER
XM_Log_GetMinStallMs¶
지금 쓰는 목표 시간(ms)을 돌려줍니다. 진단용입니다.
파라미터: 없음
반환값: uint16_t — 목표 시간(ms)
⚠️ 호출 컨텍스트: Control_Setup() / Control_Loop() 컨텍스트 기준.
XM_Log_EnableLinkHealth¶
링크 상태 정보(송신 실패 수 · 버퍼 사용률 등)를 1초마다 보낼지 정합니다. 기본은 보내지 않습니다. 구조체를 하나 이상 등록했을 때만 보냅니다 — 등록하지 않으면 켜도 보내지 않습니다. (설계 목표, 보드 확인 전)
파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
enable |
bool |
true: 보냄, false: 보내지 않음 |
반환값: bool — true: 설정됨. false: Control_Setup() 밖에서 부름
xm10 도구는 이 값을 따로 풀어 보여 주지 않습니다. 보드 안에서 로깅 관련 카운터를 보려면 XM_Log_GetStats 를 쓰세요.
⚠️ 호출 컨텍스트: Control_Setup() 안에서 부릅니다.
예제
void Control_Setup(void)
{
(void)XM_LOG_REGISTER(JointLog, 0xF0, 500);
(void)XM_Log_EnableLinkHealth(true); // 링크 상태 전송 켜기
}
참고: XM_Log_GetStats
XM_Log_GetAdmittedWireBps¶
USB 송신 예산 가운데 이미 정해진 몫(바이트/초)을 돌려줍니다. 등록한 구조체들의 몫과 보드가 미리 잡아 둔 몫의 합입니다.
미리 잡아 둔 몫은 등록하지 않은 데이터 · 디버그 텍스트, 구조체 정보 · 링크 상태 전송, 그리고 기본 프로파일(XM_USB_HOST_PHAI_STUDIO)이면 Total Data 입니다. 구조체를 하나도 등록하지 않았으면 미리 잡아 둔 몫만 나옵니다. 진단용입니다.
파라미터: 없음
반환값: uint32_t — 이미 정해진 송신 몫 (바이트/초)
⚠️ 호출 컨텍스트: Control_Setup() / Control_Loop() 컨텍스트 기준.
참고: XM_LOG_REGISTER
XM_Log_GetStats¶
관측 카운터를 복사합니다. 칸마다 따로 읽으므로 여러 칸이 정확히 같은 순간의 값은 아닐 수 있습니다. 칸의 뜻은 XM_LogStats_t 를 보세요.
파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
out |
XM_LogStats_t* |
받을 곳 — NULL 이면 아무것도 하지 않습니다 |
반환값: 없음 (void) — 결과는 out 을 통해 돌아옵니다.
⚠️ 호출 컨텍스트: Control_Loop() 에서 부릅니다.
예제
static XM_LogStats_t s_stats;
void Control_Loop(void)
{
XM_Log_GetStats(&s_stats); // 디버거 Live Expressions 에 s_stats 를 넣어 봅니다
}
참고: XM_LogStats_t
타입 / 상수¶
XM_FieldType_e¶
필드 타입입니다. XM_FIELD · XM_FIELD_ARRAY 가 멤버의 C 타입에서 정합니다 (직접 적지 않습니다).
| 값 | 이름 | 멤버의 C 타입 | 크기 |
|---|---|---|---|
| 0 | XM_FIELD_F32 |
float |
4 B |
| 1 | XM_FIELD_F64 |
double |
8 B |
| 2 | XM_FIELD_I8 |
int8_t |
1 B |
| 3 | XM_FIELD_U8 |
uint8_t |
1 B |
| 4 | XM_FIELD_I16 |
int16_t |
2 B |
| 5 | XM_FIELD_U16 |
uint16_t |
2 B |
| 6 | XM_FIELD_I32 |
int32_t · int |
4 B |
| 7 | XM_FIELD_U32 |
uint32_t · unsigned |
4 B |
| 8 | XM_FIELD_I64 |
int64_t |
8 B |
| 9 | XM_FIELD_U64 |
uint64_t |
8 B |
| 10 | XM_FIELD_BOOL |
bool |
1 B |
XM_FieldDesc_t¶
필드 설명 한 줄입니다. XM_FIELD · XM_FIELD_ARRAY 로 만드세요. 직접 채우면 컴파일러가 타입 · 위치를 검사하지 못합니다.
| 멤버 | 타입 | 설명 |
|---|---|---|
name |
const char* |
필드 이름 (영문 · 숫자 · 기호 15자까지, ASCII 만) |
unit |
const char* |
단위 (영문 · 숫자 · 기호 7자까지, ASCII 만, 없으면 "") |
type |
uint8_t |
원소 타입 — XM_FieldType_e 값. 컴파일 옵션과 상관없이 1 바이트입니다 |
offset |
uint16_t |
구조체 안 위치(바이트) |
array_len |
uint8_t |
원소 개수 (스칼라 = 1) |
scale |
float |
물리값 = 저장값 × scale |
XM_LogStats_t¶
로깅 관측 카운터입니다. XM_Log_GetStats() 로 받습니다. 모두 부팅 뒤 누적값이고, 따로 적지 않은 칸은 구조체를 등록하지 않아도 셉니다.
| 멤버 | 타입 | 설명 |
|---|---|---|
rate_gate_suppressed_calls |
uint32_t |
XM_LOG_SEND 를 등록한 주기보다 자주 불러 보내지 않은 횟수 (등록한 구조체가 있을 때만 생깁니다) |
owner_violation_count |
uint32_t |
XM_LOG_REGISTER · XM_LOG_SEND · 이 헤더의 설정 함수를 Control_Setup() · Control_Loop() 밖(다른 태스크 · 인터럽트)에서 부른 횟수 (구조체를 등록한 뒤라면 XM_SetUsbCustomMeta() 도 셉니다) |
profile_change_blocked_count |
uint32_t |
등록 뒤 XM_USB_SetHostProfile() 를 불러 무시된 횟수 |
admission_reject_count |
uint32_t |
XM_SendUsbDataWithId() · XM_SendUsbDebugMessage() 등이 송신량 한도(한 번에 보내기에 너무 큰 것 포함)로 거절된 횟수 (구조체를 등록했을 때만 셉니다. 인자가 함수의 최대 길이를 넘어 거절된 호출은 세지 않습니다) |
reserved_id_reject_count |
uint32_t |
시스템이 쓰는 모듈 ID 나 등록한 구조체의 모듈 ID 로 보내려다 거절된 횟수 + XM_SetUsbStreamModuleId() 에 시스템이 쓰는 ID 를 주어 무시된 횟수 (등록한 구조체의 ID 는 정할 때가 아니라 그 ID 로 보낼 때마다 셉니다) |
seal_reject_count |
uint32_t |
Control_Setup() 이 끝난 뒤 XM_LOG_REGISTER 를 부른 횟수 (구조체를 등록한 뒤라면 XM_SetUsbCustomMeta() 도 셉니다) |
admission_attempt_calls |
uint32_t |
위 송신이 송신량 한도 검사를 받은 횟수 (허용 + 거절, 구조체를 등록했을 때만 셉니다) |
x20_same_tick_suppressed_calls |
uint32_t |
제어 루프가 같은 1 ms 안에 다시 돌아 Total Data 송신을 건너뛴 횟수 (구조체를 등록했을 때만 셉니다) |
rate_gate_suppressed_calls는 매 루프XM_LOG_SEND를 부르면 계속 늘어나는 것이 정상입니다.- Total Data 를 1 ms 마다 최대 한 번만 보내고 건너뛰는 동작은 보드에서 아직 확인하지 못했습니다. (보드 확인 전)
한도 상수¶
| 이름 | 값 | 뜻 |
|---|---|---|
XM_LOG_MAX_STRUCT_SIZE |
1008U |
등록할 수 있는 구조체 크기 상한(바이트) |
XM_LOG_MAX_FIELDS |
90U |
구조체 하나에 적을 수 있는 필드 수 상한 |
XM_LOG_MAX_ARRAY_LEN |
255U |
배열 필드 하나의 원소 수 상한 |
XM_LOG_MAX_TOKEN_LEN |
11U |
토큰 길이 상한(글자) — 토큰이 구조체 이름이 됩니다 |
XM_LOG_SLOT_NONE |
0xFFU |
등록되지 않은 토큰의 슬롯 값 |
XM_TYPE_TAG¶
멤버 식의 필드 타입입니다. XM_FIELD · XM_FIELD_ARRAY 가 안에서 쓰므로 직접 쓸 일은 거의 없습니다. 지원 타입은 float · double · bool · int · unsigned · int8_t ~ uint64_t 입니다. 열거형 멤버는 크기가 같은 정수 타입으로 받습니다. 그 밖의 타입(char · 포인터 · 구조체 · 배열 등)은 컴파일 오류입니다.
지원 헤더 — xm_api_logging_raw.h (직접 호출 금지)¶
⚠️ 지원 대상이 아닙니다.
XM_LOG_REGISTER·XM_LOG_SEND매크로가 안에서 부르는 함수의 원형입니다. 매크로를 쓰는.c파일은 이 헤더를 include 해야 컴파일됩니다. 아래 함수는 타입 · 크기 검사를 거치지 않아 다른 구조체를 보내도 컴파일러가 막지 못합니다. 직접 부르지 말고 항상XM_LOG_*매크로를 쓰세요.
XM_Log_RegisterSchemaRaw¶
bool XM_Log_RegisterSchemaRaw(uint8_t* slot_io, uint8_t module_id, const char* struct_name, uint16_t struct_size,
uint16_t nominal_rate_hz, const XM_FieldDesc_t* fields, uint8_t field_count);
XM_LOG_REGISTER 가 부릅니다.
파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
slot_io |
uint8_t* |
토큰의 슬롯 변수 — XM_LOG_SLOT_NONE 일 때만 등록하고, 성공하면 슬롯 번호를 씁니다 |
module_id |
uint8_t |
모듈 ID (0xF0 ~ 0xFE) |
struct_name |
const char* |
구조체 이름(토큰) |
struct_size |
uint16_t |
구조체 크기(바이트) |
nominal_rate_hz |
uint16_t |
보낼 주기(Hz) |
fields |
const XM_FieldDesc_t* |
필드 설명 배열 |
field_count |
uint8_t |
필드 수 |
반환값: bool — true: 등록됨. false: 이미 등록된 슬롯이거나 등록 실패 — *slot_io 는 바뀌지 않습니다.
XM_Log_SendRaw¶
XM_LOG_SEND 가 부릅니다.
파라미터
| 이름 | 타입 | 설명 |
|---|---|---|
slot |
uint8_t |
등록된 슬롯 번호 |
data |
const void* |
보낼 구조체 |
size |
uint16_t |
구조체 크기(바이트) |
반환값: bool — true: 보냄. false: 등록 안 된 슬롯, size 가 그 슬롯의 구조체 크기와 다름, data 가 NULL, 등록 주기보다 일찍 부름, USB 장치가 준비되지 않음, 송신 버퍼가 가득 참, Control_Setup() · Control_Loop() 밖(다른 태스크 · 인터럽트)에서 부름. 송신 버퍼가 가득 차 false 가 나와도 다음 송신은 등록한 주기가 지난 뒤에 나갑니다.
내부 전용 (직접 쓰지 마세요)¶
이름 끝이 _ 인 매크로(XM_LOG_REQUIRE_ · XM_FIELD_TYPE_NONE_ · XM_TYPE_TAG_ · XM_LOG_MEMBER_ · XM_LOG_ARRLEN_ · XM_LOG_IS_ARRAY_ · XM_LOG_FIELD_COUNT_)는 다른 매크로가 쓰는 보조 정의입니다. 사용자 코드에서 쓰지 마세요.
Rev1.1 / Rev2.0 차이 요약¶
| 항목 | Rev1.1 | Rev2.0 |
|---|---|---|
구조체 로깅 (xm_api_logging.h · xm_api_logging_raw.h) |
❌ 없음 | 🟢 전용 |
기존 방식 (XM_SetUsbCustomMeta + XM_SendUsbDataWithId) |
✅ | ✅ |
관련 문서¶
- 10. 구조체 로깅 (개념) — 동작 원리, 한도, 흔한 실수
xm_api_usb.h— USB-CDC 실시간 스트리밍 —XM_SendUsbDataWithId·XM_SetUsbCustomMeta등 기존 USB-CDC 함수- PC 에서 데이터 받기 —
xm10도구