19.3.3.3. `orb_publish()` 함수를 호출하여 실제 데이터 전파(Broadcast)

19.3.3.3. orb_publish() 함수를 호출하여 실제 데이터 전파(Broadcast)

단 한 번의 광고(orb_advertise) 선전포고를 통해 미들웨어 링 버퍼(Ring Buffer)를 향한 합법적이고 영구적인 송출 파이프라인 VFS 마스터 핸들을 얻어냈고, 무한 루프 블록 안에서 최신화된 생동감 넘치는 센서 헬스 페이로드까지 C++ 구조체 포인터 공간에 1바이트의 오차도 없이 꽉꽉 채워 넣었다면, 이제 우리의 손에는 대망의 피날레 타격만이 유일하게 남았다. 이 모든 지긋지긋하고 복잡했던 메모리 포맷팅과 아키텍처 준비 과정은, 오직 단 한 줄의 위대한 시스템 콜 매크로 함수, **orb_publish()**를 퍼펙트하게 발사하기 위한 길고 긴 빌드업(Build-up)에 불과했다.

1. 자비 없는 시스템 전역 브로드캐스트: orb_publish() 폭격

마스터 C++ 데몬의 메인 무한 루프 제일 맨 끄트머리, 즉 px4_usleep()으로 워커 스레드가 깊은 잠에 빠져들기 직전의 숨 막히는 찰나에 이 막강한 함수를 냅다 꽂아 넣는다. 이 코어 단위의 퍼블리싱 매크로 함수가 링커에서 호출되는 바로 그 찰나의 순간, 우리가 그동안 철저히 로컬 힙/스택에 고립시켜 두었던 sensor_data 구조체의 모든 바이트 덩어리 실체들이 빛의 속도로 하드웨어 복사되어, 전 시스템의 미들웨어 VFS 코어 바다로 무자비하게 브로드캐스트(Broadcast) 방출 폭발하게 된다.

// 앞에서 따낸 마스터 키 호적 권한 
// orb_advert_t sensor_pub_handle = orb_advertise(...);

while (!thread_should_exit) {
    // 1. 메모리 오염 제거 및 시스템 클럭 타임스탬프 로직 타설
    sensor_test_data_s sensor_data{};
    sensor_data.timestamp = hrt_absolute_time();

    // 2. 가상 센서 모사 페이로드 및 메타 비트마스크 완전 조립
    sensor_data.temperature = 25.0f;
    sensor_data.current_state = sensor_test_data_s::STATE_OK;
    // ...

    // 3. [절정] uORB 시스템 마스터 링 버퍼망으로의 실제 데이터 출판(Publishing) 융단 폭격
    // - 첫 번째 인자 ORB_ID(sensor_test_data): 전역 메타데이터 심볼 주소 (광고 때와 완벽히 동일해야 함)
    // - 두 번째 인자 sensor_pub_handle: 루프 바깥 최초에 단 1번 개통해 둔 전용 파이프라인 마스터 키 핸들
    // - 세 번째 인자 &sensor_data: 방금 전 우리가 꽉 채워둔, 가장 따끈따끈한 최신 페이로드의 메모리 시작 주소 포인터
    int pub_ret = orb_publish(ORB_ID(sensor_test_data), sensor_pub_handle, &sensor_data);

    // 4. 출판 실패에 대한 엄격한 물리적 폴트(Fault) 체킹과 방어 기제
    if (pub_ret != PX4_OK) {
        PX4_ERR("Failed to publish sensor_test_data! Middleware VFS pipe might be terminally broken.");
        // 퍼블리싱 파이프 붕괴 실패 시의 치명적인 예외 처리 트러블슈팅 로직 (에러 카운터 증가 등)
    }

    // 5. 다음 사이클 인터럽트(10ms 후)를 준비하기 위한 RTOS 커널 수면 모드 진입 (필수 타루 방지)
    px4_usleep(10000); 
}

2. orb_publish() 이면에 숨겨진 잔혹한 커널의 피비린내(Under the Hood)

어설픈 초보자 코더는 orb_publish() C 함수가 성공 코드 PX4_OK(0)를 단 0.001초 만에 쉘에 반환했다며 순진하게 기뻐하겠지만, 그 짧디짧은 눈 깜짝할 찰나에 하부 RTOS(NuttX) 커널 내부와 레지스터 단에서는 다음과 같은 지옥의 하드코어 연산들이 피 터지게 벌어지고 있다.

  1. 뮤텍스 락(Mutex Lock)의 강제 장악: 만에 하나라도 여러 커스텀 센서 데몬 I/O 스레드가 동시에 같은 하나의 토픽(Topic) 파이프에 데이터를 무식하게 들이붓다 메모리 동기화가 깨지고 꼬이는(Race Condition) 것을 막기 위해, 커널은 이 호출 찰나의 순간에 뮤텍스 세마포어 락을 강제로 걸어 잠그고 VFS 노드를 완전히 단독으로 점유 통제해 버린다.
  2. 링 버퍼 쓰로틀 강제 메모리 복사(memcpy): 락이 걸린 안전지대에서, 우리가 힙에 쏜 sensor_data 구조체의 모든 인련 바이트들이, 커널이 직접 은밀하게 관리하는 링 버퍼망 메모리의 다음 빈칸(Head) 슬롯으로 단 1바이트의 오차도 없이 통째로 초고속 블록 복사된다. (만약 버퍼 큐가 이미 꽉 차 터지기 직전이라면, 가장 오래 묵은 썩은 꼬리(Tail) 데이터를 가차 없이 폭력적으로 덮어씌워 죽여버린다).
  3. 구독자 멀티 인터럽트 기상 나팔(Wake-up Signal Explosion): 데이터 복사가 무사히 끝남과 동시에 잔인한 락이 해제되며, 시스템 코어는 이 토픽 데이터를 핏발 선 눈으로 줍어 먹겠다고 저 멀리 블로킹 모드에서 대기(Subscribe)하고 있던 수백 개의 다른 워커 스레드 뎁스와 poll() 함수들에게 **“새 밥상(Data)이 버퍼에 차려졌다!”**라고 미친 듯한 인터럽트 기상 나팔(Signal Event)을 한꺼번에 일제히 때려버린다.

이 모든 잔혹하고 정교한 극한의 시스템 링커 처리망과 동기화 전쟁 프로시저를, 단 한 줄의 우아한 추상화 C 코드로 완벽하게 감싸 숨겨놓은 것이 바로 orb_publish() API 매크로가 지닌 압도적인 설계 철학인 것이다. 만약 이 커널 함수 호출이 단 한 번의 에러도 뿜지 않고 100Hz로 무사히 도달 안착했다면, 당신은 이제 진정한 PX4 마스터 퍼블리셔(Publisher) 모듈의 절대 개발 영역을 아키텍처적으로 완벽하게 수료 통과한 것이다.