Automotive/Testing

BusLoad Monitoring 위한 CAPL 코드

코딩쪼앙 2025. 9. 19. 13:57

구현 과정

  1. 각 채널 별 모든 메시지 주기적으로 송신 
  2. 각 채널 별 전송 중인 모든 메시지 송신 취소
  3. 전체 채널 메시지 주기적으로 송신
  4. 전체 채널 메시지 송신 취소
  5. 각 채널 별 송신 주기 변경
  6. 송신 주기 Default로 변경
  7. 버스로드 모니터링

📌 모든 메시지 주기적으로 송신

1. variable 영역에 사용하려는 모든 메시지 선언

→ 메시지 양이 너무 많은 경우 자동화된 파이썬 스크립트 작성하여 CAPL 코드 내 메시지 선언

def print_valid_messages(dbc):
    capl_vars = "variables\n{\n"
    for msg in valid_messages:
        # capl_vars += f"  message {dbc}::{msg.name} {dbc}_{msg.name};\n"
        capl_vars += f"  {dbc}_{msg.name}.can = channel;\n"
    print(capl_vars)
  message FD_B1::message_name_500ms;

2. 타이머 생성

def define_ms_timer(dbc):
    capl_vars = '{\n'
    timer = 0
    for msg in valid_messages:
        timer_name = f"{msg.name.lower()}Timer"
        capl_vars += f"  msTimer {dbc}_{timer_name};\n"
        timer += 1

    capl_vars += "}\n\n"
 msTimer messagename_500msTimer;

3. 타이머 이벤트가 발생할 때 실행되는 함수 생성 

-> CAPL 내에는 for문이 없어 주기적으로 타이머를 호출하고 싶다면 on timer내 함수를 만들어 재귀적으로 호출 가능하다

on timer message_name_500msTimer {
    message_name_500ms();
}
void  message_name_500ms() {
    FD_B1_message_name_500ms.byte(0) = 0x12;
    FD_B1_message_name_500ms.byte(1) = 0x34;
    output(FD_B1_message_name_500ms);
    setTimer(message_name_500ms.Timer, b1CycleTime[0])
}

4. 특정 채널의 모든 메시지 송신 후 Panel에 Activated로 상태 변경 

on sysvar sendB1Messages {
  if (sysGetVariableInt(this)) {
    sendAllB1Messages();
  }
}
void sendAllB1Messages() {
  sysSetVariableString(sysvar::checkB1MessageStatus, "Activated");
  write("All B1 Messages Sended");
  
  setTimer(b1_message_a_500msTimer, 0);
  setTimer(b1_message_b_500msTimer, 0);
  setTimer(b1_message_c_500msTimer, 0);
  setTimer(b1_message_d_500msTimer, 0);
 }

📌 특정 채널의 모든 메시지 송신 취소

1. Panel에 Deactivated 표시 후 채널에서 전송 중인 모든 메시지 송신 취소

on sysvar cancelB1Messages {
  if (sysGetVariableInt(this)) {
    cancelAllB1Messages();
  }
}
void cancelAllB1Messages() {
  sysSetVariableString(sysvar::checkB1MessageStatus, "Deactivated");
//  write("cancel b1 messages");
  
  cancelTimer(b1_message_a_500msTimer);
  cancelTimer(b1_message_b_500msTimer);
 }

→  Cancel 메시지가 많다면 Python 내에서 DBC를 불러와 아래와 같이 자동으로 생성할 수 있음

def cancel_all_messages(dbc):
    cancel_timer = 0
    cancel_timer_function = "cancelAllCMessages {\n"
    for msg in valid_messages:
        timer_name = f"{dbc}_{msg.name.lower()}Timer"
        cancel_timer += 1
        cancel_timer_function += f"  cancelTimer({timer_name});\n"
    cancel_timer_function += "}\n"

📌 전체 채널 메시지 주기적으로 송신

on sysvar sendAllMessages {
  if (sysGetVariableInt(this)) {
    sendAllMessages();
  }
}
void sendAllMessages() {
  sysSetVariableString(sysvar::checkAllMessagesStatus, "Activated");
  
  sendAllB1Messages();
  write("success b1");
  sendAllB2Messages();
  write("success b2");
  sendAllCMessages();
  write("success c");
  sendAllEMessages();
  write("success e");
  sendAllMMessages();
  write("success m");
  sendAllP1Messages();
  write("success p1");
  sendAllP2Messages();
  write("success p2");
}

📌 전체 채널 메시지 송신 취소

on sysvar cancelAllMessages {
  if (sysGetVariableInt(this)) {
    write("cacnel All Messages Button");
    cancelAllMessages();
  }
}
void cancelAllMessages() {
  write("cancel all messages");
  sysSetVariableString(sysvar::checkAllMessagesStatus, "Deactivated");
  
  cancelAllB1Messages();
  cancelAllB2Messages();
  cancelAllCMessages();
  cancelAllEMessages();
  cancelAllMMessages();
  cancelAllP1Messages();
  cancelAllP2Messages();
  
  resetCanEx(1);
  resetCanEx(2);
  resetCanEx(3);
  resetCanEx(4);
  resetCanEx(5);
  resetCanEx(6);
  resetCanEx(7);
  
}

→ Bus Off 상태를 대비하여 모든 메시지 송신 취소 후 CAN 채널 reset


📌 각 채널 별 송신 주기 변경

on sysvar setB1CycleTime {
  b1Cycle = sysGetVariableInt(this);
  write("%d", b1Cycle);
  if (b1Cycle > 0) {
    int i = 0;
    for (i = 0; i < B1_CYCLE_LENGTH; i++) {
      b1CycleTime[i] = b1Cycle;
//      write("%d", b1Cycle);
    }
  }
}

📌송신 주기 Default로 변경

on sysvar setDefaultB1CycleTime {
  if (sysGetVariableInt(this)) {
    setDefaultB1Periodic();
    setDefaultB1CycleTime();
  }
}

on sysvar setDefaultB2CycleTime {
  if (sysGetVariableInt(this)) {
    setDefaultB2Periodic();
    setDefaultB2CycleTime();
  }
}

on sysvar setDefaultCCycleTime {
  if (sysGetVariableInt(this)) {
    setDefaultCPeriodic();
    setDefaultCCycleTime();
  }
}

on sysvar setDefaultECycleTime {
  if (sysGetVariableInt(this)) {
    setDefaultEPeriodic();
    setDefaultECycleTime();
  }
}

on sysvar setDefaultMCycleTime {
  if (sysGetVariableInt(this)) {
    setDefaultMPeriodic();
    setDefaultMCycleTime();
  }
}

on sysvar setDefaultP1CycleTime {
  if (sysGetVariableInt(this)) {
    setDefaultP1Periodic();
    setDefaultP1CycleTime();
  }
}

on sysvar setDefaultP2CycleTime {
  if (sysGetVariableInt(this)) {
    setDefaultP2Periodic();
    setDefaultP2CycleTime();
  }
}

on sysvar setDefaultAllCycleTime {
  if (sysGetVariableInt(this)) {
    setAllDefaultPeriodic();
    setDefaultAllCycleTime();
  }
}
void setDefaultB1CycleTime() {
  int i;
  for (i = 0; i < B1_CYCLE_LENGTH; i++) {
    b1CycleTime[i] = copyB1CycleTime[i];
  }
}

void setDefaultB2CycleTime() {
  int i;
  write("default b2 cycle time");
  for (i = 0; i < B2_CYCLE_LENGTH; i++) {
    b2CycleTime[i] = copyB2CycleTime[i];
  }
}

void setDefaultCCycleTime() {
  int i;
  for (i = 0; i < C_CYCLE_LENGTH; i++) {
    cCycleTime[i] = copyCCycleTime[i];
  }
}

📌 버스로드 모니터링

1. 주기적으로 BusLoad를 업데이트 하기 위한 타이머 설정 

 // BusLoad 확인을 위한 Timer
  msTimer b1BusLoadUpdateTimer;
  msTimer b2BusLoadUpdateTimer;
  msTimer cBusLoadUpdateTimer;
  mstimer eBusLoadUpdateTimer;
  msTimer mBusLoadUpdateTimer;
  msTimer p1BusLoadUpdateTimer;
  msTimer p2BusLoadUpdateTimer;

2. On Start시 Timer 호출 

on start {
  setTimer(b1BusLoadUpdateTimer, 0);
  setTimer(b2BusLoadUpdateTimer, 0);
  setTimer(cBusLoadUpdateTimer, 0);
  setTimer(eBusLoadUpdateTimer, 0);
  setTimer(mBusLoadUpdateTimer, 0);
  setTimer(p1BusLoadUpdateTimer, 0);
  setTimer(p2BusLoadUpdateTimer, 0);
  }

3. Timer내에서 BusLoad 업데이트 

// b1 on timer
on timer b1BusLoadUpdateTimer {
  @b1BusLoad = CAN5.BusLoad;
//  write ("Chip state of CAN1 = %d", CAN1.ChipState);
//  checkChipState(CAN1.ChipState);
  
  setTimer(b1BusLoadUpdateTimer, 1000);
}

// b2 on timer
on timer b2BusLoadUpdateTimer {
  @b2BusLoad = CAN7.BusLoad;
  setTimer(b2BusLoadUpdateTimer, 1000);
}

// c on timer
on timer cBusLoadUpdateTimer {
  @cBusLoad = CAN2.BusLoad;
  setTimer(cBusLoadUpdateTimer, 1000);
}

Panel 초기화 상태를 위한 함수

1. 메시지 계측 시작 시 상태 Deactivated로 초기화

void initializationIndicateStatus() {
  sysSetVariableString(sysvar::checkB1MessageStatus, "Deactivated");
  sysSetVariableString(sysvar::checkB2MessageStatus, "Deactivated");
  sysSetVariableString(sysvar::checkCMessageStatus, "Deactivated");
  sysSetVariableString(sysvar::checkEMessageStatus, "Deactivated");
  sysSetVariableString(sysvar::checkMMessageStatus, "Deactivated");
  sysSetVariableString(sysvar::checkP1MessageStatus, "Deactivated");
  sysSetVariableString(sysvar::checkP2MessageStatus, "Deactivated");
  sysSetVariableString(sysvar::checkAllMessagesStatus, "Deactivated");
}

2. 모든 메시지의 주기 바꿨을 때 모든 채널의 주기 표시 변경

void setAllDefaultPeriodic() {
  setDefaultB1Periodic();
  setDefaultB2Periodic();
  setDefaultCPeriodic();
  setDefaultEPeriodic();
  setDefaultMPeriodic();
  setDefaultP1Periodic();
  setDefaultP2Periodic();
  sysSetVariableInt(sysvar::setAllCycleTime, 0);
}