XM10 Extension Module SDK v2.9.0¶
릴리즈 날짜: 2026-10-19 | 대상 보드: Rev 2.0 전용 (Rev 1.1 은 v2.8.1 그대로) | 새로 생긴 것: 구조체 로깅 · USB 메모리 저장
🛑 Rev 2.0 전용 릴리즈입니다. Rev 1.1 SDK 는 v2.8.1 에서 바뀐 것이 없습니다. Rev 1.1 보드를 쓰신다면 이미 받으신
Rev1.1.zip을 계속 쓰시면 됩니다.⚠️ 이번 릴리즈에서 새로 생긴 동작은 아직 실제 보드에서 확인하지 못했습니다. 아래 "아직 확인하지 못한 것" 을 먼저 읽어 주세요. (보드 확인 전)
한눈에 보기¶
- 구조체 로깅이 생겼습니다 (Rev 2.0). 직접 만든 구조체를 등록해 두면, 보드가 필드 이름 · 단위 · 타입을 값과 함께 PC 로 보냅니다.
xm_api_logging.h와 새 예제 Ex.44 입니다. (보드 확인 전) - USB 메모리 저장을 새 API 로 다시 제공합니다 (Rev 2.0). v2.5.0 에서 뺐던 기능입니다. 구조체 하나를 정한 주기마다 USB 메모리에 기록합니다.
xm_api_usb_msc.h(함수 14 개)와 새 예제 Ex.10 · Ex.34 입니다. (보드 확인 전) - USB-CDC 함수 몇 곳이 바뀌었습니다 (Rev 2.0). 채널 이름 JSON 은 1,007 바이트까지 받고
XM_SetUsbCustomMeta()가bool을 돌려줍니다. 디버그 메시지는 1,021 바이트까지입니다. 시스템이 쓰는 모듈 ID 로는 보낼 수 없고, 인터럽트 안에서 부르면false입니다. - 헤더에서 선언 3 개가 빠졌습니다 (Rev 2.0). 시스템이 자동으로 쓰는 함수 · 타입이라 직접 쓸 필요가 없습니다. 쓰던 코드가 있다면 새 SDK 로 빌드할 때 오류가 나므로 그 줄을 지우세요. 이름은 아래 "헤더에서 빠진 선언 3 개" 에 있습니다.
- 빌드 설정이 바뀌었습니다 (Rev 2.0). 선언 없는 함수를 부르면 경고가 아니라 오류로 빌드가 멈춥니다.
xm10도구의.xmlog받은 시각이 UTC 로 바뀌었습니다.pc_time_us는 이제 1970-01-01 UTC 부터의 µs 입니다.- 예제 수 — Rev 2.0 48 개 / Rev 1.1 40 개.
- Rev 2.0 SDK 에 적힌 펌웨어 버전은 2.9.0 입니다.
구조체 로깅 (Rev 2.0)¶
지금까지는 XM_SendUsbDataWithId() 로 float 배열을 보내고 XM_SetUsbCustomMeta() 로 채널 이름만 따로 알려 줬습니다. 이번에는 구조체를 통째로 등록해 보낼 수 있습니다.
보드가 각 필드의 이름 · 단위 · 타입을 함께 PC 로 보내므로, PC 는 값을 정해진 타입으로 풉니다. (보드 확인 전)
Rev 1.1(v2.8.1)에는 구조체 로깅이 없습니다.
#include "xm_api.h"
#include "xm_api_logging_raw.h" // XM_LOG_* 매크로를 쓰는 .c 파일에는 꼭 넣습니다
typedef struct {
float hip_angle;
int16_t emg[8];
uint32_t mode;
} MyLog_t; // 24 B — 크기는 4 의 배수
XM_LOG_DECLARE(MyLog, MyLog_t); // 구조체에 짧은 이름(토큰) MyLog 를 붙입니다
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)) { // 모듈 ID 0xF0, 1000 Hz
XM_SetLedEffect(XM_LED_1, XM_LED_BLINK, 200); // 등록 실패는 LED 로 알립니다
}
}
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 파일 전용입니다. XM_LOG_REGISTER()는Control_Setup()에서,XM_LOG_SEND()는Control_Loop()에서 부릅니다. 둘 다bool을 돌려줍니다.XM_LOG_SEND()를 매 루프 불러도 등록한 주기로만 나갑니다. 주기가 되기 전에는 보내지 않고false입니다.- 구조체 크기는 4 의 배수이고 1,008 바이트 이하입니다. 구조체는 4 개까지 등록하고, 모듈 ID 는
0xF0~0xFE에서 구조체마다 하나씩 고릅니다. - 필드는 구조체 하나에 1 ~ 90 개입니다. 필드 이름은 15 자, 단위는 7 자까지이고, 영문 · 숫자 · 기호(ASCII)만 쓸 수 있습니다.
- 필드 타입은 멤버의 C 타입에서 자동으로 정해집니다. 배열 멤버는
XM_FIELD_ARRAY로 적습니다. - 잘못 쓰면(지원하지 않는 멤버 타입, 4 의 배수가 아닌 크기 등) 컴파일러가 그 줄을 가리킵니다.
- 보내지 못한 이유를 찾을 때는
XM_Log_GetStats()로 카운터를 읽습니다.
알아 둘 점¶
- 등록한 모듈 ID 는 그 구조체 전용입니다. 같은 ID 로
XM_SendUsbDataWithId()를 부르면false입니다. - 구조체를 등록하면
XM_SendUsbDataWithId()·XM_SendUsbDebugMessage()로 보내는 양에 한도가 생깁니다. 짧은 시간에 너무 많이 보내거나 한 번에 너무 크게 보내면false입니다. 큰 데이터는 구조체 로깅으로 보내세요. XM_USB_SetHostProfile()은Control_Setup()에서 첫XM_LOG_REGISTER()보다 먼저 부릅니다. 구조체를 하나라도 등록한 뒤에는 이 호출이 무시됩니다.- 구조체를 등록한 뒤에는
XM_SetUsbCustomMeta()도Control_Setup()안에서만 부를 수 있습니다. 그 밖에서 부르면false입니다. - 일반 시리얼 터미널용 프로파일(
XM_USB_HOST_TERMINAL)에서도 구조체 데이터는 그대로 나가 터미널 화면에 깨진 글자로 섞여 보일 수 있습니다. 텍스트만 볼 때는 구조체를 등록하지 마세요. Control_Setup()에서는 USB 가 아직 준비되지 않아 PC 로 보낸 메시지가 보통 나가지 않습니다. 등록에 실패했는지는 LED 로 알리세요.- 구조체를 등록하면 제어 루프가 1 ms 를 넘겨 늦어져도 Total Data(
0x20)는 1 ms 마다 최대 한 번만 나가고, 그 구간에서는xm_loop_count값이 이어지지 않고 건너뜁니다. 보드가 보내는 간격과 PC 에 도착하는 시각은 1 ms 간격으로 고르지 않을 수 있습니다. (설계 목표, 보드 확인 전)
PC 에서 보기¶
- SDK 에 들어 있는
xm10도구가 모듈 ID 마다 탭을 하나씩 열고(탭 제목은 모듈 ID 와 구조체 이름), 필드 이름으로 그래프와 CSV 열 이름을 만들고, 보드가 보낸 타입으로 값을 풉니다. (보드 확인 전) - PhAI Studio 는 아직 개발 중이라, 직접 정의한 데이터 구조체(커스텀 구조체)는 우선
xm10도구로 보고 저장하세요. - 구조체 로깅을 쓰지 않는 기존 방식(
XM_SetUsbCustomMeta()+XM_SendUsbDataWithId())은 그대로 쓸 수 있습니다. 이때 보드는 지금까지처럼 채널 이름만 보내고, PC 는 값을 float32 로 가정합니다.
예제 Ex.44 — CDC Struct Logging (Rev 2.0)¶
구조체 두 개(SensorLog · StatusLog)를 등록해 버튼 · 확장 ADC · 합성 파형 값을 이름 · 단위와 함께 보냅니다. USE_H10 을 1 로 바꾸면 H10 의 고관절 값을 읽어 1 kHz 로 보내는 형태가 됩니다(읽기만 하고 토크는 내보내지 않습니다). 등록에 실패하면 LED 3 이 빠르게 깜빡입니다. 아직 보드에서 확인되지 않은 예제입니다. (보드 확인 전)
Ex.44 CDC Struct Logging 보기
USB 메모리에 저장하기 (Rev 2.0)¶
v2.5.0 에서 뺐던 USB 메모리 저장을 새 API 로 다시 제공합니다. 구조체 하나를 등록해 두면, 저장하는 동안 정한 주기(정하지 않으면 1000 Hz)마다 그 구조체를 USB 메모리에 기록합니다. 기록 함수를 따로 부르지 않습니다. (보드 확인 전)
v2.5.0 에서 뺀 이유는 저장 중에 표본이 조용히 빠질 수 있어서였습니다. 이번에는 빠진 표본 수와 가장 긴 공백을 XM_GetUsbLogStats() · summary.txt · 디코더 결과에서 볼 수 있습니다. (보드 확인 전)
Rev 1.1(v2.8.1)에는 USB 메모리 저장이 없습니다.
// Control_Setup()
XM_SetUsbLogSource(&s_log, sizeof(s_log)); // s_log 는 전역 또는 static 구조체
XM_SetUsbLogSampleRateHz(100); // 생략하면 1000 Hz
// Control_Loop() — XM_IsUsbLogReady() 와 XM_IsUsbLogSessionIdle() 이 모두 true 일 때
XM_StartUsbDataLog("", "loop_count(uint32_t), hip_L(float), hip_R(float), contact(uint8_t), _pad(3bytes)");
Control_Setup()에서 구조체를 등록하고 주기를 정합니다.Control_Loop()에서 구조체의 값을 채웁니다. 저장은Control_Loop()가 끝난 뒤 시스템이 합니다.XM_IsUsbLogReady()와XM_IsUsbLogSessionIdle()이 모두true일 때XM_StartUsbDataLog()로 시작합니다.false가 돌아오면XM_GetUsbLogLastStartError()로 이유를 봅니다.XM_StopUsbDataLog()로 멈추고XM_IsUsbLogSessionIdle()이true가 될 때까지 기다립니다.true가 되면 파일이 모두 닫힌 것이므로 USB 메모리를 뽑아도 됩니다. (보드 확인 전)
| 종류 | 함수 | 부르는 곳 |
|---|---|---|
| 설정 | XM_SetUsbLogSource() · XM_SetUsbLogSampleRateHz() · XM_SetUsbLogAutoTimestamp() · XM_SetUsbLogRollingSize() |
Control_Setup() · Control_Loop() |
| 시작 · 정지 · 마커 · 통계 | XM_StartUsbDataLog() · XM_StopUsbDataLog() · XM_InsertUsbLogMarker() · XM_GetUsbLogStats() |
Control_Setup() · Control_Loop() |
| 상태 | XM_IsUsbLogReady() · XM_IsUsbLogSessionIdle() · XM_IsUsbLogRecording() · XM_GetUsbLogLastStartError() · XM_GetUsbDiskFreeMB() · XM_GetUsbDiskTotalMB() |
어디서나 |
- 설정 · 시작 · 정지 · 마커 · 통계 함수를 다른 태스크나 인터럽트에서 부르면 아무것도 하지 않고
false를 돌려줍니다. - 메타 줄(
XM_StartUsbDataLog()의 두 번째 인자)에는 구조체의 필드를 선언 순서대로이름(타입)으로 적고 쉼표로 잇습니다. 디코더가 이 줄로 데이터를 풉니다. - 비워 둔 바이트는
_pad(3bytes)처럼_로 시작하는 이름으로 적습니다. 필드 크기의 합이 등록한 구조체 크기와 다르면 시작하지 않습니다(XM_USB_LOG_START_METADATA_MISMATCH). - USB 메모리는 FAT32 로 포맷합니다. exFAT 과 NTFS 는 인식하지 않습니다.
- 저장 주기는 1000 의 약수 중에서 고르고, 정하지 않으면 1000 Hz 입니다. 주기에 비해 구조체가 크면 시작하지 않습니다(
XM_USB_LOG_START_TOO_BIG_FOR_RATE). - 1000 Hz 로 저장하면 표본이 일부 빠질 수 있습니다. 빠진 수와 가장 긴 공백은
XM_GetUsbLogStats()와 디코더 결과에 나옵니다. /LOGS/<세션 이름>/폴더에metadata.txt·data_000_part_000.bin… ·summary.txt가 만들어집니다. 이름을 비우면 시계(RTC)로YYMMDD_HHMMSS를 만듭니다.- 파일은 정한 크기(기본 10 MB)마다 새 파트로 나뉩니다. (보드 확인 전)
- 저장하는 동안에는 USB 메모리를 뽑지 마세요.
USB-C 포트는 하나입니다¶
- XM10 의 USB-C 포트는 하나입니다. USB 메모리를 꽂아 두는 동안에는 PhAI Studio ·
xm10도구 · USB 로 하는 펌웨어 업로드를 쓸 수 없습니다. - 이 동안에는 PC 와의 USB 통신이 끊겨 있어서
XM_IsUsbStreamConnected()는false이고, PC 로 보내는 함수(XM_SendUsbDataWithId()등)는false를 돌려줍니다. - 저장이 끝나면 USB 메모리를 뽑고 PC 를 연결하세요. (보드 확인 전)
예제 Ex.10 · Ex.34 (Rev 2.0)¶
| 예제 | 하는 일 |
|---|---|
| Ex.10 USB Memory Log | 버튼 1 로 저장을 시작 · 정지합니다. 루프 카운터 · 합성 사인파 · 합성 톱니파 · 버튼 상태 · H10 연결 여부를 구조체 하나(16 B)에 담아 100 Hz 로 저장합니다. 버튼 2 는 표시(마커)를 넣습니다. USB 메모리를 뽑고 PC 를 연결해 시리얼 터미널을 연 뒤 버튼 3 을 누르면 마지막 통계를 보냅니다 (보드 확인 전) |
| Ex.34 USB Memory Gait Log | H10 보행 데이터를 구조체 하나(96 B)에 담아 1 kHz 로 저장합니다. 버튼 1 로 시작 · 정지하고, 버튼 2 · 3 은 마커를 넣습니다 |
두 예제 모두 아직 보드에서 확인하지 못했습니다. (보드 확인 전)
⚠️ Ex.34 안전: 기본 설정(
USE_H10_ASSIST 0)은 기록만 하고 토크나 제어 명령을 보내지 않습니다.USE_H10_ASSIST를 1 로 바꾸면 H10 의 기존 보조 알고리즘이 켜져 착용자에게 보조 토크가 걸립니다. 착용자와 주변의 안전을 확인한 뒤에만 켜세요.빌드하기 전에
_SetupBodyData()의 신체 정보(체중 · 키 · 다리 길이)를 착용자의 값으로 고치세요. 예시 값 그대로면 무릎 · 허벅지 각도가 부정확합니다.
저장한 로그를 푸는 PC 프로그램¶
USB 메모리의 /LOGS/<세션 이름>/ 폴더를 PC 로 옮겨 XM10 Log Decoder 로 풉니다. 빠진 표본이 있으면 그 위치와 길이를 알려 줍니다.
- Windows 용 설치형 프로그램이고, 파이썬은 필요 없습니다.
- 릴리즈 페이지의 첨부 파일에서 XM10 Log Decoder 2.2.1 을 받습니다.
USB-CDC 함수에서 바뀐 것 (Rev 2.0)¶
채널 이름 — XM_SetUsbCustomMeta()¶
- JSON 은 1,007 바이트까지 받습니다(
XM_USB_CUSTOM_META_MAX_LEN). 전에는 512 바이트를 넘으면 아무 알림 없이 보내지 않았습니다. - 반환값이
void에서bool로 바뀌었습니다. 등록되면true입니다.NULL이거나 너무 길면false이고, 이전에 등록한 이름이 그대로 남습니다. - 반환값을 쓰지 않는 코드는 그대로 빌드됩니다.
NULL을 넘겨 이름을 지우던 코드는 이제 지울 수 없습니다(false). XM_USB_HOST_TERMINAL프로파일이 아니면 PC 프로그램이 COM 포트를 열 때마다 채널 이름을 다시 보냅니다. 이름이 안 보일 때 USB 케이블을 다시 꽂지 않아도 됩니다. (보드 확인 전)- v2.8.1 에서 안내한 제한(창에서 Disconnect 뒤 Connect 만 다시 눌러 받은
.xmlog에는 채널 이름이 없음)도 Rev 2.0 에서는 없어지도록 했습니다. (보드 확인 전) - 할 일: 이름 목록이 길다면 반환값을 확인하세요.
false면 단위를 이름 안에 적어(예:"IMU0 Roll [deg]") JSON 을 줄이세요. - Rev 1.1 은 v2.8.1 과 같습니다. 반환값이 없고, JSON 은 512 바이트까지이고, 이름은 USB 를 연결할 때 한 번 보냅니다. 이름이 안 보이면 케이블을 다시 꽂으세요.
디버그 메시지 — XM_SendUsbDebugMessage()¶
- 문자열 뒤에 0x00 한 바이트를 붙여 보냅니다. 함께 보내는 데이터 패킷이 깨지지 않게 하려는 것입니다.
XM_USB_HOST_TERMINAL프로파일에서도 똑같이 붙습니다. (보드 확인 전) - 한 번에 1,021 바이트까지 보냅니다(
XM_USB_DEBUG_MESSAGE_MAX_LEN). 넘거나NULL이면false이고 아무것도 보내지 않습니다. 길이는 바이트 기준이라 한글은 글자 수보다 바이트가 많습니다. - 빈 문자열(
"")은 0x00 한 바이트만 보내고true입니다. 전에는false였습니다. - 전에는 스트림을 받는 중에 텍스트를 보내면 메시지 하나마다 데이터 패킷 하나가 손실됐습니다. Rev 2.0 에서는 이 손실이 없도록 바꿨습니다. (보드 확인 전)
- 할 일: 1,021 바이트를 넘는 메시지는 나눠서 보내세요. 구조체 로깅을 쓰면 더 짧은 한도가 적용됩니다.
- Rev 1.1 은 v2.8.1 과 같습니다. 종료 바이트(0x00)를 붙이지 않고 1,021 바이트 한도도 없으며, 스트림을 받는 중에 보내면 메시지마다 데이터 패킷 하나가 손실됩니다.
시스템이 쓰는 모듈 ID — XM_SendUsbDataWithId()¶
0x20·0xB2·0xED·0xEE·0xEF·0xFF로 보내면false입니다.XM_SetUsbStreamModuleId()는 이 값들을 무시하고 이전 ID 를 그대로 씁니다.- 할 일: 내 데이터는
0xF0~0xFE를 쓰세요. SDK 예제는0xF0~0xF3만 씁니다. - Rev 1.1 은 v2.8.1 과 같습니다. 모든 ID 를 받습니다.
인터럽트 안에서 부르면¶
XM_SendUsbData()·XM_SendUsbDataWithId()·XM_SendUsbDebugMessage()를 인터럽트 안에서 부르면 아무것도 보내지 않고false입니다.- 할 일:
Control_Loop()안에서 부르세요. 직접 만든 백그라운드 태스크(XM_Task_*)에서도 부르지 마세요. 보내는 데이터가 깨질 수 있습니다. - Rev 1.1 은 v2.8.1 과 같습니다.
헤더에서 빠진 선언 3 개¶
- 빠진 것:
XM_USB_ProcessPeriodic()·XM_GetUsbLogStatus()·XmLogStatus_e(XM_LOG_STATUS_*). 시스템이 자동으로 쓰는 함수 · 타입이라 직접 쓸 필요가 없습니다. - 쓰던 코드가 있다면 그 줄을 지우세요. 함수는 아래 "빌드 설정" 의 새 설정에서
implicit declaration of function오류가 납니다. 타입XmLogStatus_e는 어느 설정에서나unknown type name오류가 납니다. - USB 메모리 저장 상태가 필요하면
XM_IsUsbLogRecording()·XM_IsUsbLogSessionIdle()을 쓰세요. - Rev 1.1 은 v2.8.1 과 같습니다. 세 선언이 그대로 있습니다.
빌드 설정 — 선언 없는 함수 호출은 오류 (Rev 2.0)¶
Rev 2.0 SDK 의 빌드 설정(STM32CubeIDE 의 Debug · Release 와 CMake)에 -Werror=implicit-function-declaration 이 들어갔습니다.
- 헤더에 선언되지 않은 함수를 부르면 이제 경고가 아니라 빌드 오류입니다. 전에는 경고만 나오고 빌드됐고, 이때 함수는 반환값을
int로 가정하고 불렸습니다. - 화면에는
error: implicit declaration of function '함수 이름'으로 나옵니다. - 이렇게 고치세요.
- 그 함수를 선언한 헤더를
#include합니다. SDK 함수라면 보통#include "xm_api.h"하나면 됩니다. 직접 만든 함수라면 부르기 전에 원형(prototype)을 선언합니다. - 함수 이름이 맞는지 확인합니다. 오타이거나 SDK 에서 빠진 이름일 수 있습니다.
- 위에서 설명한 빠진 선언 3 개를 쓰고 있다면 그 줄을 지웁니다.
- 그 함수를 선언한 헤더를
- 새로 받은
Rev2.0.zip에 들어 있는 설정입니다. 이전 ZIP 으로 만든 프로젝트의 설정은 바뀌지 않습니다. - Rev 1.1 SDK 는 그대로입니다.
PC 데이터 도구 — .xmlog 받은 시각¶
xm10 도구가 .xmlog 에 적는 PC 가 받은 시각(pc_time_us)이 바뀌었습니다.
| v2.8.0 · v2.8.1 | v2.9.0 | |
|---|---|---|
.xmlog 의 pc_time_us |
수신을 시작한 뒤 흐른 µs | 1970-01-01 UTC 부터의 µs |
실시간 CSV 의 pc_time_s |
수신을 시작한 뒤 흐른 초 | 그대로 |
- 저장을 시작할 때 PC 시계로 기준을 한 번 잡고, 그 뒤는 PC 의 단조 시계로 더합니다. 그래서 저장하는 동안 PC 시계가 조정돼도 값이 튀거나 뒤로 가지 않습니다. 대신 오래 저장하면 PC 시계와 조금씩 벌어질 수 있습니다.
.xmlog에서 뽑은 CSV 의pc_time_us도 UTC 값입니다. 날짜 · 시각까지 필요하면 이 값을 쓰세요.- 예전 도구(v2.8.0 · v2.8.1)가 만든
.xmlog는 예전 값(수신을 시작한 뒤 흐른 µs)을 그대로 가지고 있습니다. 두 값을 섞어 비교하지 마세요. .xmlog형식을 칸마다 정리한 문서가 새로 생겼습니다. 형식에 맞지 않는 레코드를 만나면 읽기를 멈추는 규칙도 들어 있습니다 — pc-data-tool/spec/xmlog.md- 이 변경은
Rev2.0.zip의pc-data-tool/폴더에 들어 있습니다. Rev1.1.zip은 v2.8.1 과 같은 파일이라 이전 도구가 들어 있습니다. 새 도구가 필요하면Rev2.0.zip이나 GitHub 레포의pc-data-tool/폴더에서 받으세요. 이 폴더는 보드 리비전과 무관하게 같은 파일입니다.
예제 개수¶
Rev 2.0 48 개 / Rev 1.1 40 개.
- 새 예제 3 개 — 모두 🛑 Rev 2.0 전용입니다. Ex.10 USB Memory Log · Ex.34 USB Memory Gait Log · Ex.44 CDC Struct Logging
- Ex.10 · Ex.34 는 v2.4.1 까지 있던 USB 메모리 예제(v2.5.0 에서 삭제)와 이름도 내용도 다른 새 예제입니다.
- Rev 1.1 SDK 는 40 개 그대로입니다. Rev 2.0 에만 있는 예제는 Ex.10 · 34 · 36 · 40 · 41 · 42 · 43 · 44 로 모두 8 개입니다.
아직 확인하지 못한 것 — 꼭 읽어 주세요¶
이번 릴리즈에서 새로 생긴 동작은 빌드와 PC 쪽 시험으로만 확인했고, 실제 보드에서는 아직 확인하지 못했습니다. 써 보시다가 이상한 점이 있으면 알려 주세요.
- USB 메모리 저장 전체 — 저장 · 정지 · 뽑기와 Ex.10 · Ex.34 입니다. 저장을 멈춘 뒤
XM_IsUsbLogSessionIdle()이true가 되면 뽑아도 된다는 것도 포함합니다. (보드 확인 전) - USB 메모리를 뽑고 PC 를 다시 연결하는 동작 — USB-C 포트가 하나라서, 메모리를 뽑은 뒤 PC 연결(PhAI Studio ·
xm10도구 · USB 로 하는 펌웨어 업로드)이 다시 되는지 시험하기 전입니다. (보드 확인 전) - USB 메모리 종류와 빠지는 표본 — 여러 종류의 USB 메모리를 비교하지 않았습니다. 1000 Hz 로 저장할 때 빠지는 표본 수는 메모리마다 다를 수 있고, 이 버전으로 측정한 숫자는 아직 없습니다. 저장이
Control_Loop()주기에 주는 영향도 측정하지 않았습니다. (보드 확인 전) - 디코더의 허용 공백 — 1000 Hz · 100 Hz 가 아닌 저장 주기에서 디코더가 판정에 쓰는 허용 공백은 실제 보드 로그로 확인하지 않은 계산값입니다. (보드 확인 전)
- 구조체 로깅 전체 — 구조체를 등록하고, 필드 정보를 보내고, 등록한 주기로 데이터를 보내고,
xm10도구가 탭 제목과 열 이름을 만들고 값을 타입대로 풀어 보여 주기까지의 과정과 Ex.44 입니다. 실제 보드에서 받은 데이터로는 확인하지 못했습니다. (보드 확인 전) - 구조체 로깅의 설계 목표 — PC 프로그램이 잠시(기본 50 ms,
XM_Log_SetMinStallMs()로 바꿀 수 있습니다) 멈춰도 보드가 데이터를 빠뜨리지 않고 담아 두는 것, 그리고 Total Data 를 1 ms 마다 최대 한 번만 보내는 것은 설계 목표입니다. 50 ms 는 아직 보드에서 재 보지 않은 초기값이라 보장이 아니라 목표입니다. (설계 목표) - 채널 이름 · 필드 정보를 다시 보내는 동작 — PC 프로그램이 COM 포트를 열 때마다 채널 이름(구조체 로깅을 쓰면 필드 정보도)을 다시 보내는 것과, 포트를 연 뒤 몇 초 안에 도착하는 것은 설계 목표입니다. (설계 목표, 보드 확인 전)
- 디버그 메시지 끝의 0x00 — 메시지를 보내는 중에도 데이터 패킷이 빠지지 않는지 확인하지 못했습니다. (보드 확인 전)
- 새 기능을 쓰지 않는 코드 — 구조체 로깅과 USB 메모리 저장을 쓰지 않는 코드에서 PC 로 나가는 데이터가 v2.8.1 과 같은지(위에서 바뀐 곳은 제외)를 보드에서 다시 확인하지 못했습니다. (보드 확인 전)
- 버전 번호 — 보드에 올린 펌웨어가 2.9.0 으로 보고되는지는 확인하지 못했습니다. (보드 확인 전)
- XM10 Log Decoder 설치 — 설치 파일을 파이썬이 없는 Windows PC 에 설치해 실행해 보지 않았습니다.
호환성¶
| 항목 | 내용 |
|---|---|
| 기존 펌웨어 코드 (Rev 2.0) | 대부분 재빌드만 하면 됩니다. 다음은 고쳐야 합니다 — 헤더에서 빠진 선언 3 개를 쓰는 코드 · 선언 없는 함수를 부르는 코드(이제 오류) · 시스템이 쓰는 모듈 ID(0x20 등)로 보내는 코드 · 송신 함수(XM_SendUsbData() · XM_SendUsbDataWithId() · XM_SendUsbDebugMessage())를 인터럽트 안에서 부르는 코드 · 1,021 바이트를 넘는 디버그 메시지를 보내는 코드 · XM_SetUsbCustomMeta() 에 NULL 을 넘겨 이름을 지우던 코드 |
| 새 헤더 | xm_api.h 가 xm_api_logging.h 와 xm_api_usb_msc.h 를 함께 가져옵니다. XM_LOG_ · XM_FIELD · XM_Log_ · XM_USB_LOG_ 로 시작하는 이름을 직접 만들어 쓰셨다면 겹칠 수 있습니다. xm_api_logging_raw.h 는 xm_api.h 가 가져오지 않으니, XM_LOG_* 매크로를 쓰는 .c 파일에서 직접 include 하세요 |
| Rev 1.1 | v2.8.1 그대로 — SDK · 헤더 · 예제 40 개 · USB-CDC 함수의 동작이 모두 같습니다. 새 헤더가 없어서 구조체 로깅 · USB 메모리 저장 코드는 Rev 1.1 에서 컴파일되지 않습니다 |
| PC 데이터 도구 | .xmlog 의 받은 시각(pc_time_us)이 바뀌었습니다. 필요한 Python 패키지는 그대로입니다 (pyserial pyqt5 pyqtgraph numpy) |
| 부트로더 | v1.1.0 그대로입니다. 이미 설치된 부트로더는 바꾸지 않아도 됩니다 |
다운로드¶
| 파일 | 대상 |
|---|---|
Rev2.0.zip |
Rev 2.0 보드용 SDK (예제 48 개, pc-data-tool/ 포함) |
Rev1.1.zip |
Rev 1.1 보드용 SDK — v2.8.1 과 같은 파일입니다 (변경 없음, 예제 40 개) |
XM10LogDecoder_Setup_v2.2.1_dbb8525.exe (.zip · SHA256SUMS.txt) |
XM10 Log Decoder 2.2.1 — USB 메모리에 저장한 로그를 푸는 PC 프로그램 (Windows) |
AGR_Bootloader.bin |
XM10 부트로더 v1.1.0 — v2.8.1 과 같은 파일 (아직 보드로 확인하지 않음) |
SUIT_H10_Binary_20260820.zip |
KIT H10 펌웨어 — v2.6.0 과 동일본 |
SUIT_ContentsFiles_20260820.zip |
H10 컨텐츠 파일 — v2.6.0 과 동일본 |
이번 변경은 Rev 2.0 에만 해당합니다. Rev 1.1 을 쓰신다면 이미 받으신
Rev1.1.zip(v2.8.1)을 계속 쓰시면 됩니다.
압축을 풀 때 짧은 경로(예: C:\xm10\)에 푸세요. 경로가 깊으면 윈도우의 경로 길이 제한 때문에 빌드가 실패할 수 있는데, 이건 코드 문제가 아니라 경로 길이 문제입니다.