This commit is contained in:
r9andy.lee 2024-10-22 16:10:27 +09:00
parent 70a4f70825
commit 16a51a4912
20 changed files with 3011 additions and 0 deletions

0
a.txt
View File

2
src/Xilinx.spec Normal file
View File

@ -0,0 +1,2 @@
*startfile:
crti%O%s crtbegin%O%s

474
src/ctrl_module.c Normal file
View File

@ -0,0 +1,474 @@
#include "bldc.h"
#include "ctrl_module.h"
// 레지스터 BIT값 가져오기
static u8_t GetBit(u8_t nIdx, u8_t cMask, u8_t cShift)
{
u8_t cRetVal = 0;
/* MISRA C Dir 4.14 : 레지스터 유효범 위 확인 */
if(nIdx > NUM_INDEX)
{
#if DEBUG_COVER
cRetVal = ERR_INDEX;
xil_printf("Ctrl_Module: Values greater than register range 13\r\n");
#endif
}
else
{
cRetVal = (u8_t)BLDC_mReadReg(BASE_ADDR, BLDC_S00_AXI_SLV_REG0_OFFSET + (nIdx * 4u)); // 레지스터값 읽고
cRetVal = (cRetVal & cMask) >> cShift; // 0 혹은 1 설정
}
return cRetVal;
}
// 레지스터 BIT값 설정하기
static void SetBit(u8_t nIdx, u8_t cMask, u8_t cShift)
{
u32_t cVal = 0, cVal2 = 0, cVal3 = 0x01;
/* MISRA C Dir 4.14 : 레지스터 유효범 위 확인 */
if(nIdx <= NUM_INDEX)
{
cVal = (u32_t)BLDC_mReadReg(BASE_ADDR, BLDC_S00_AXI_SLV_REG0_OFFSET + (nIdx * 4u)); // 레지스터값 읽고
if(cMask == 0x01u)
{
cVal2 = (u32_t)(cVal3 << cShift); // 1 설정
cVal |= cVal2;
}
else
{
cVal2 = (u32_t)(cVal3 << cShift); // 0 설정
cVal2 = ~cVal2;
cVal &= cVal2;
}
BLDC_mWriteReg(BASE_ADDR, (BLDC_S00_AXI_SLV_REG0_OFFSET + (nIdx * 4u)), (u32)cVal);
}
}
// 레지스터 byte값 가져오기
static u32_t GetByte(u8_t nIdx)
{
u32_t cRetVal = 0;
if(nIdx <= NUM_INDEX)
{
cRetVal = BLDC_mReadReg(BASE_ADDR, BLDC_S00_AXI_SLV_REG0_OFFSET + (nIdx * 4u));
}
else
{
#if DEBUG_COVER
cRetVal = ERR_INDEX;
#endif
}
return cRetVal;
}
// 레지스터 Byte값 설정하기
static void SetByte(u8_t nIdx, u8_t cData)
{
BLDC_mWriteReg(BASE_ADDR, (BLDC_S00_AXI_SLV_REG0_OFFSET + (nIdx * 4u)), (u32)cData);
}
// 리모컨 연결 상태 확인
static void CheckOverCurrent(void)
{
if(g_cOverCurrFlag == 0u) // 과전류 알람 발생하면 레지스터값 가져오기 중지, 마스트 상승/하강 시점에 g_cOverCurrFlag = 0 설정하고 가져오기 재시작
{
g_cOverCurrFlag = (u8_t)GetBit(REG_IDX_4, REG_MASK_OVER_CURR, SHIFT_OVER_CURR);
}
else
{
if((g_cOverCurrFlag == 1u) && (g_cMastRcvCmd != 0x00u)) // 과전류 발생 후 마스트 상태가 정지가 아닌 경우만 (1회 진입용)
{
SetBit(REG_IDX_7, 0x01, SHIFT_MAST_OVER_CURR); // 01. 모터 과전류 클리어, Register8, High, bit3
g_cMastRcvCmd = 0x00u; // 02. 마스트 정지
SetMotor(g_cMastRcvCmd); // Motor Up/Down/Stop 구동 제어
SetBit(REG_IDX_7, 0x00, SHIFT_MAST_OVER_CURR); // 03. 모터 과전류 클리어, Register8, Low, bit3
}
}
}
// 엔코더 값 일치 확인
static void CheckEncoder(void)
{
g_cEncoderErrFlag = (u8_t)GetBit(REG_IDX_4, REG_MASK_ENCODER_ERR, SHIFT_ENCODER_ERR);
g_cEncoderHWResetFlag = (u8_t)GetBit(REG_IDX_4, REG_MASK_ENCODER_HW_RESET, SHIFT_ENCODER_HW_RESET); // 높이값 H/W 리셋 입력 검사
if(g_cEncoderHWResetFlag == 1u)
{
SetBit(REG_IDX_7, 0x01, SHIFT_ENCODER_HW_RESET_CLEAR); // 엔코더 H/W Reset Clear Set, Register7
g_cEncoderHWResetFlag = 0;
g_nEncoderMT = 0;
g_nMastCurrHeight = 0;
SaveEncoderMT((u32)g_nEncoderMT); // 엔코더 멀티턴값 쓰기
SetBit(REG_IDX_7, 0x00, SHIFT_ENCODER_HW_RESET_CLEAR); // 엔코더 H/W Reset Clear Reset, Register7
}
}
// Bit 3 : 모터과전류 g_cOverCurrFlag
// Bit 2 : 높이값 표시용 엔코더 체크 g_cEncoderErrFlag
// Bit 1 : 마스트 구동 체크 0
// Bit 0 : 안테나마스트-임무통제기 통신 수신 g_cBitDetailHBErr
// BIT 상태 확인
static void CheckBitDetailInfo(void)
{
u8_t cData = 0u;
cData = 0x01u;
if(g_cBitDetailHBErr == 1u) // 안테나마스트-임무통제기 통신 수신, Bit: 0
{
g_cBitDetail |= cData;
}
else
{
cData = ~cData;
g_cBitDetail &= cData;
}
cData = 0x02;
if((g_cBitDetailHBErr == 1u) || (g_cEncoderErrFlag == 1u) || (g_cOverCurrFlag == 1u)) // 마스트 구동체크(통신 or 엔코더 or 과전류) 체크, Bit: 1 24.09.25 BIT 사양 재정의
{
g_cBitDetail |= cData;
}
else
{
cData = ~cData;
g_cBitDetail &= cData;
}
cData = 0x04;
if(g_cEncoderErrFlag == 1u) // 높이값 표시용 엔코더 체크, Bit: 2
{
g_cBitDetail |= cData;
}
else
{
cData = ~cData;
g_cBitDetail &= cData;
}
cData = 0x08;
if(g_cOverCurrFlag == 1u) // 모터과전류, Bit: 3
{
g_cBitDetail |= cData;
}
else
{
cData = ~cData;
g_cBitDetail &= cData;
}
}
// 현재높이값 확인
static void CheckCurrHeight(void)
{
u32_t nRetVal = 0, nVal, nData;
float32 fUpper, fLower, fData;
nRetVal = BLDC_mReadReg(BASE_ADDR, BLDC_S00_AXI_SLV_REG6_OFFSET); // Encoder값 가져오기
g_nEncoderMT = nRetVal;
/* Encoder값 계산 */
nData = nRetVal & SINGLE_CYCLE_MAST;
fLower = (float32)nData; // 단회전 값 결정(소수점 제외) 0 ~ 1023: 0 ~ 32.0mm(0.0 ~ 31.97)
fLower = fLower * (float32)SINGLE_BASE_SCALE;
nData = nRetVal & MULTI_CYCLE_MAST;
nData = nData >> 10u;
fUpper = (float32)(nData); // 다회전 값 결정
fData = fUpper * (float32)SINGLE_CYCLE_SCALE;
fData = fData + fLower;
nVal = (u32_t)fData;
/* MISRA C Dir 4.14 : 마스트 높이 최대값 초과 시 예외처리 */
if(nVal > ANT_MAST_HEIGHT_MAX)
{
g_nMastCurrHeight = ANT_MAST_HEIGHT_MAX;
}
else
{
g_nMastCurrHeight = nVal;
}
/* 최대/최소값 도달 시 멈춤 처리 */
if(g_cMastRcvCmd == (u8_t)CMD_MOTOR_CTN_UP) // 상승 중
{
if(g_nMastCurrHeight >= ANT_MAST_HEIGHT_MAX) // 최대값 도달
{
g_cMastRcvCmd = (u8_t)CMD_MOTOR_STOP; // 마스트 통신 커맨드 변경
SetMotor(g_cMastRcvCmd); // 마스트 Stop
}
}
if(g_cMastRcvCmd == (u8_t)CMD_MOTOR_CTN_DOWN) // 하강 중
{
if(g_nMastCurrHeight <= ANT_MAST_HEIGHT_MIN) // 최소값 도달
{
g_cMastRcvCmd = (u8_t)CMD_MOTOR_STOP; // 마스트 통신 커맨드 변경
SetMotor(g_cMastRcvCmd); // 마스트 Stop
}
}
if(g_cMastRcvCmd == (u8_t)CMD_MOTOR_USER_INPUT) // 유저 입력값 동작 중
{
if(g_cMastAction == (u8_t)DIR_MOTOR_UP) // 상승 중
{
if(g_nMastCurrHeight >= (g_nSetMastHeight - 30u)) // 마스트 속도 감안한 offset값
{
g_cMastRcvCmd = (u8_t)CMD_MOTOR_STOP; // 마스트 통신 커맨드 변경
SetMotor(g_cMastRcvCmd); // 마스트 Stop
}
}
if(g_cMastAction == (u8_t)DIR_MOTOR_DOWN) // 하강 중
{
if(g_nMastCurrHeight <= (g_nSetMastHeight + 30u))
{
g_cMastRcvCmd = (u8_t)CMD_MOTOR_STOP; // 마스트 통신 커맨드 변경
SetMotor(g_cMastRcvCmd); // 마스트 Stop
}
}
}
#if DEBUG_CTRL_MODULE
xil_printf("g_nMastCurrHeight:%d, g_nSetMastHeight:%d, nRetVal:%d, fLower:%d, fUpper:%d, g_cMastRcvCmd:%d, g_cMastAction:%d\r\n",
(u32_t)g_nMastCurrHeight, (u32_t)g_nSetMastHeight, (u32_t)nRetVal, (u32_t)fLower, (u32_t)fUpper, (u32_t)g_cMastRcvCmd, (u32_t)g_cMastAction);
#endif
}
// 마스트 구동 제어(Stop, Up, Down: 0x00, 0x01, 0x02)
// ControlItem(1) 0xC0: 사용자 입력, 0x80: 연속 상승, 0x40: 연속 하강, 0x00: 중지
// 상승/하강 중 역방향 동작 명령 수신 시 정지하는 사양 추가 24.04.07
// 정지 명령 제외하고 DevicePowerRequest값에 따라 동작 차단 조건 추가 24.05.10
void SetMotor(u8_t cCmd)
{
if(cCmd == (u8_t)CMD_MOTOR_STOP) // 01. 0x00 멈춤
{
if(g_cMastAction == DIR_MOTOR_UP) // 1-1 현재 상태 상승 중
{
g_cMastAction = (u8_t)DIR_MOTOR_STOP_FOR_UP; // 상승의 정지
}
else // 1-2 현재 상태 하강 중
{
g_cMastAction = (u8_t)DIR_MOTOR_STOP_FOR_DOWN; // 하강의 정지
}
g_nEcdeepromCnt = 0; // 저장 판정용 카운터 초기화
g_cEncoderSaveFlag = 1; // 엔코더 멀티턴값 eeprom 기록 판정
}
if((cCmd == (u8_t)CMD_MOTOR_CTN_UP) && (g_cCmdPowerOff == 0u)) // 02. 0x80 상승, DevicePowerRequest값 확인
{
if(g_cMastAction == (u8_t)DIR_MOTOR_DOWN) // 2-1 현재 상태 하강 중
{
g_cMastAction = (u8_t)DIR_MOTOR_STOP_FOR_DOWN; // 하강의 정지
g_nEcdeepromCnt = 0; // 저장 판정용 카운터 초기화
g_cEncoderSaveFlag = 1; // 엔코더 멀티턴값 eeprom 기록 판정
g_cMastRcvCmd = 0x00u; // 안테나마스트 대기 중
}
else // 2-2 그 외
{
g_cMastAction = (u8_t)DIR_MOTOR_UP; // 상승
}
}
if((cCmd == (u8_t)CMD_MOTOR_CTN_DOWN) && (g_cCmdPowerOff == 0u)) // 03. 0x40 하강, DevicePowerRequest값 확인
{
if(g_cMastAction == (u8_t)DIR_MOTOR_UP) // 3-1 현재 상태 상승 중
{
g_cMastAction = (u8_t)DIR_MOTOR_STOP_FOR_UP; // 상승의 정지
g_nEcdeepromCnt = 0; // 저장 판정용 카운터 초기화
g_cEncoderSaveFlag = 1; // 엔코더 멀티턴값 eeprom 기록 판정
g_cMastRcvCmd = 0x00u; // 안테나마스트 대기 중
}
else // 3-2 그 외
{
g_cMastAction = (u8_t)DIR_MOTOR_DOWN; // 하강
}
}
if((cCmd == (u8_t)CMD_MOTOR_USER_INPUT) && (g_cCmdPowerOff == 0u)) // 04. 0xC0 사용자 입력, DevicePowerRequest값 확인
{
if(g_nMastCurrHeight < g_nSetMastHeight) // 4-1 현재 높이가 목표 높이보다 낮으면 상승
{
if(g_cMastAction == (u8_t)DIR_MOTOR_DOWN) // 4-1-1 현재 상태 하강 중
{
g_cMastAction = (u8_t)DIR_MOTOR_STOP_FOR_DOWN; // 하강의 정지
g_nEcdeepromCnt = 0; // 저장 판정용 카운터 초기화
g_cEncoderSaveFlag = 1; // 엔코더 멀티턴값 eeprom 기록 판정
g_cMastRcvCmd = 0x00u; // 안테나마스트 대기 중
}
else // 4-1-2 그 외
{
g_cMastAction = (u8_t)DIR_MOTOR_UP; // 상승
}
}
else // 4-2 현재 높이가 목표 높이보다 높거나 같으면 하강
{
if(g_cMastAction == (u8_t)DIR_MOTOR_UP) // 4-2-1 현재 상태 상승 중
{
g_cMastAction = (u8_t)DIR_MOTOR_STOP_FOR_UP; // 상승의 정지
g_nEcdeepromCnt = 0; // 저장 판정용 카운터 초기화
g_cEncoderSaveFlag = 1; // 엔코더 멀티턴값 eeprom 기록 판정
g_cMastRcvCmd = 0x00u; // 안테나마스트 대기 중
}
else // 4-2-2 그 외
{
g_cMastAction = (u8_t)DIR_MOTOR_DOWN; // 하강
}
}
}
if((g_cMastAction == (u8_t)DIR_MOTOR_UP) || (g_cMastAction == (u8_t)DIR_MOTOR_STOP_FOR_UP)
|| (g_cMastAction == (u8_t)DIR_MOTOR_DOWN) || (g_cMastAction == (u8_t)DIR_MOTOR_STOP_FOR_DOWN)) // 유효한 명령만 수행
{
BLDC_mWriteReg(BASE_ADDR, BLDC_S00_AXI_SLV_REG2_OFFSET, (u32)g_cMastAction); // 마스트 동작 결정
}
#if DEBUG_CTRL_MODULE
xil_printf("SetMotor: cCmd:%d, g_cMastAction:%d\r\n", (u32_t)cCmd, (u32_t)g_cMastAction);
#endif
}
// LED 제어 (알람, 마스트 구동)
static void SetLEDControl(void)
{
u32_t cData = 0u, cMotor = 0u;
cData = GetByte(REG_IDX_7); // LED 제어 레지스터값 가져오기
if((g_cBitDetail & BIT_DETAIL_STATUS_OVER_CURR) == BIT_DETAIL_STATUS_OVER_CURR) // 과전류 알람, 250mSec 주기 동작으로 500mSec 마다 깜빡임 처리
{
switch (g_cMotorLedFlickerCnt)
{
case 0: cMotor = LED_MOTOR_ON; break;
case 1: cMotor = LED_MOTOR_OFF; break;
default: cMotor = LED_MOTOR_OFF; break;
}
if(g_cMotorLedFlickerCnt < 1u)
{
g_cMotorLedFlickerCnt++;
}
else
{
g_cMotorLedFlickerCnt = 0u;
}
}
else // 모터 구동
{
if((g_cMastAction == DIR_MOTOR_UP) || (g_cMastAction == DIR_MOTOR_DOWN))
{
cMotor = LED_MOTOR_ON;
}
else
{
cMotor = LED_MOTOR_OFF;
}
}
if(cMotor == 1u)
{
cData |= (1u << 0u); // 0: 자리수
}
else
{
cData &= ~(1u << 0u);
}
SetByte(REG_IDX_7, (u8_t)cData); // 두가지 상태 적용 후 LED 처리
}
// 마스트 엔코더 멀티턴값 세팅
static void SetEncoderMT(void)
{
BLDC_mWriteReg(BASE_ADDR, (BLDC_S00_AXI_SLV_REG0_OFFSET + (5u * 4u)), (u32)g_nEncoderMT);
SetBit(REG_IDX_5, 0x01, SHIFT_ENCODER_WRITE); // Encoder값 Register에 기록 Flag
}
// 제어부 모듈 초기 설정
void InitCtrlModule(void)
{
u32 cData;
g_cMastRcvCmd = (u8_t)CMD_MOTOR_STOP;
g_cMastAction = (u8_t)DIR_MOTOR_STOP_FOR_UP;
g_cCMProcessIdx = 0;
g_cCmdPreparePowerOff = 0;
g_cCmdPowerOff = 0;
g_cMotorLedFlickerCnt = 0; // 모터 LED 깜빡임 카운터
g_cBitDetailHBErr = 0; // Heart Beat 수신 Off 판정
g_cOverCurrFlag = 0; // 과전류 발생 여부
g_cEncoderHWResetFlag = 0;
SetEncoderMT(); // 마스트 엔코더 멀티턴값 세팅, eeprom에서 읽은값을 register에 기록
}
// 제어부 모듈 동작 처리
void CtrlModuleProcess(void)
{
if(g_nCnt2 > TIMER_MSEC250)
{
g_nCnt2 = 0;
CheckCurrHeight(); // 현재높이값 확인
switch(g_cCMProcessIdx) // 분산 처리
{
case 0: SetLEDControl(); break; // LED 제어 (알람, 마스트 구동)
case 1: CheckOverCurrent(); break; // 과전류 상태 확인
case 2: CheckEncoder(); break; // 엔코더 값 일치 확인
case 3: CheckBitDetailInfo(); break; // BIT 상태 확인
default: break;
}
g_cCMProcessIdx++;
if(g_cCMProcessIdx > 3u)
{
g_cCMProcessIdx = 0;
}
}
if(g_cEncoderSaveFlag == 0u) // eeprom 저장 조건이 아니면 카운터 초기화
{
g_nEcdeepromCnt = 0u;
}
else // eeprom 저장 조건 만족
{
if(g_nEcdeepromCnt > TIMER_SEC3)
{
g_cEncoderSaveFlag = 0u; // 재진입 방지
g_nEcdeepromCnt = 0u;
SaveEncoderMT((u32)g_nEncoderMT); // 엔코더 멀티턴값 쓰기
}
}
}

58
src/ctrl_module.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef CTRL_MODULE_H
#define CTRL_MODULE_H
#include "xil_io.h"
#include "define.h"
#include "main.h"
#include "tcp_client.h"
static u32_t g_cCMProcessIdx; // CtrlModuleProcess 순차 진행 처리용 인덱스
u32_t g_nMastCurrHeight; // 마스트 현재 높이(0 ~ 570cm)
u8_t g_cMastRcvCmd; // 모터 제어 수신 명령(Bit0:멈춤, Bit1:연속하강, Bit2:연속상승, Bit3:최대수축, Bit4: 최대확장, Bit5:사용자 입력)
static u8_t g_cMastAction; // FPGA에 사용할 마스트 현재 구동 상태(Stop, Up, Down: 0x00, 0x01, 0x02)
u8_t g_cBitDetail; // BIT Detail 정보
u32_t g_nSetMastHeight; // 마스트 목표 높이
static u8_t g_cRmtConn; // 리모컨 연결 여부
u8_t g_cMastPeriodSendCmd; // DeviceStart_Request 수신 커맨드, 이용처: AntMastStatus_Report(UDP), AntMastCBIT_Report, 정기 보고 활성/비활성
u8_t g_cDeviceErase; // DeviceErase 설정값
static u8_t g_cMastPowerCtrlRcvCmd; // DevicePower_Reqeust 수신 커맨드, 0x05:전원 Off 준비, 0x06: 전원 Off, 0x01: 전원 Off 취소, 0x07: 전원 On
u8_t g_cCmdPreparePowerOff; // DevicePower_Request 관련 변수, 1: Set, 0: Reset 0x05: 전원 Off 준비, 0x01: 전원 Off 취소
u8_t g_cCmdPowerOff; // DevicePower_Request 관련 변수, 1: Set, 0: Reset 0x06: 전원 Off, 0x07: 전원 On
u32_t g_nEncoderMT; // 엔코더 멀티턴값 X, 엔코더 전체값(24.09.10)
static u8_t g_cEncoderSaveFlag; // 엔코더 멀티턴값 기록 여부 판정 0: 대기, 1: 기록
u8_t g_cMotorLedFlickerCnt; // 모터 LED 깜빡임 카운터
u32_t g_nCnt2; // 제어부 모듈 동작 처리용 카운터
u32_t g_nEcdeepromCnt; // 엔코더 멀티턴 eeprom 기록용 카운터
u32_t g_nBitDetailHBCnt; // 임무처리에서 Heart Beat 수신되는지 판단하는 카운터(BIT Detail의 임무처리와의 통신 상태값 결정)
u8_t g_cBitDetailHBErr; // Heart Beat 수신 Off 판정
u8_t g_cOverCurrFlag; // 과전류 발생 여부
u8_t g_cEncoderErrFlag; // 엔코더 값 불일치 여부
u8_t g_cEncoderHWResetFlag; // 엔코더 영점 설정 여부(PBA 상 Set Origin)
static u8_t GetBit(u8_t nIdx, u8_t cMask, u8_t cShift); // 레지스터 BIT값 가져오기
static void SetBit(u8_t nIdx, u8_t cMask, u8_t cShift); // 레지스터 BIT값 설정하기
static u32_t GetByte(u8_t nIdx); // 레지스터 byte값 가져오기
static void SetByte(u8_t nIdx, u8_t cData); // 레지스터 byte값 설정하기
static void CheckOverCurrent(void); // 과전류 상태 확인
static void CheckEncoder(void); // 엔코더 값 일치 확인
static void CheckBitDetailInfo(void); // BIT Detail 상태 확인
static void CheckCurrHeight(void); // 현재높이값 확인
void SetMotor(u8_t cCmd); // 마스트 구동 제어(Stop, Up, Down: 0x00, 0x01, 0x02)
static void SetLEDControl(void); // LED 제어 (알람, 마스트 구동)
static void SetEncoderMT(void); // 마스트 엔코더 멀티턴값 세팅
void InitCtrlModule(void); // 제어부 모듈 초기 설정
void CtrlModuleProcess(void); // 제어부 모듈 동작 처리
#endif // CTRL_MODULE_H

230
src/define.h Normal file
View File

@ -0,0 +1,230 @@
#ifndef DEFINE_H
#define DEFINE_H
#define VER_VERSION 1u
#define VER_UPDATE 0u
#define VER_TEST 7u
#define VER_COMPILE 0u
#define TEST_LOG_ON 1u
#define TEST_LOG_ON_UDP 0u
#define DEBUG_CTRL_MODULE 0u
#define DEBUG_COVER 0u
typedef float float32;
//---------------------------------------------------------------------------------------------
//-----------------------------------------ctrl_module-----------------------------------------
#define BASE_ADDR 0x43C00000u
#define NUM_INDEX 13u // 0 ~ 8, 9 ~ 12(EEPROM 역할)
#define ERR_INDEX 0u
#define ARR_BUF_MARGIN 4u
#define TIMER_BASE 30000u
#define TIMER_MSEC250 27u
#define TIMER_MSEC333 35u
#define TIMER_MSEC500 53u
#define TIMER_SEC1 105u
#define TIMER_SEC2 210u
#define TIMER_SEC3 315u
#define TIMER_SEC5 525u
#define TIMER_SEC10 1050u
// Motor 명령
#define CMD_MOTOR_USER_INPUT 0xC0u
#define CMD_MOTOR_CTN_UP 0x80u
#define CMD_MOTOR_CTN_DOWN 0x40u
#define CMD_MOTOR_STOP 0x00u
// Motor 방향
#define DIR_MOTOR_STOP_FOR_UP 0x00u
#define DIR_MOTOR_UP 0x01u
#define DIR_MOTOR_DOWN 0x02u
#define DIR_MOTOR_STOP_FOR_DOWN 0x03u
//#define BIT_MOTOR_STOP 0x00
// Diagnostic 상태
#define NUM_DIAG_MEMBER 5u // Power On(7), Current Mon, Ethernet, Motor Init, Motor Pos(3)
#define BIT_MOTOR_POS 0x08u // Motor Position
#define BIT_MOTOR_INIT 0x10u // Motor Initialization
#define BIT_ETHERNET 0x20u
#define BIT_CURR_MON 0x40u
#define BIT_POWER_ON 0x80u
// Motor 상태
#define NUM_MOTOR_MEMBER 4u // Motor Up, Down, Min Height Arrive, Max Height Arrive
#define BIT_MOTOR_UP 0x01u // Register Index 3
#define BIT_MOTOR_DOWN 0x02u
#define BIT_MOTOR_MIN_ARRIVE 0x04u
#define BIT_MOTOR_MAX_ARRIVE 0x10u
// BIT DETAIL 상태
#define NUM_BIT_DETAIL_MEMBER 4u
#define BIT_DETAIL_STATUS_ENCODER 0x04u
#define BIT_DETAIL_STATUS_OVER_CURR 0x08u
// BIT 상태
#define REG_MASK_OVER_CURR 0x04u // REG_IDX_4
#define REG_MASK_ENCODER_ERR 0x40u
#define REG_MASK_ENCODER_HW_RESET 0x80u
// 제어
#define REG_MASK_ENCODER_HW_CLEAR 0x10u // REG_IDX_7
// 모터 높이
//#define SINGLE_CYCLE_SCALE 21u // 0 ~ 1023: 0 ~ 32mm
#define SINGLE_CYCLE_SCALE 21.476 // 0 ~ 1023: 0 ~ 21.51mm
#define SINGLE_BASE_SCALE 0.021
#define SINGLE_CYCLE_MAST 0x000003FFu // 유효bit: 10bit(0 ~ 1023)
#define MULTI_CYCLE_MAST 0x007FFC00u // 유효bit: 12bit(0 ~ 4095)
#define ANT_MAST_HEIGHT_MAX 5700u // 5700mm
#define ANT_MAST_HEIGHT_MIN 0u // 0mm
// 유선조정기, 전원제어, 소거제어
#define SHIFT_REMOCON_ON 00u // bit 이동
//#define SHIFT_POWER_CTRL 0x01u
#define SHIFT_DELETE_CTRL 02u
#define SHIFT_ENCODER_WRITE 24u // 24 번째 bit
#define BIT_REMOCON_ON 0x01u // bit 위치
//#define BIT_POWER_CTRL 0x02u
#define BIT_DELETE_CTRL 0x04u
// LED 상태 설정
//#define LED_ALARM_ON 0x04u
#define LED_MOTOR_ON 0x01u
#define LED_MOTOR_OFF 0x00u
#define LED_ALL_OFF 0x00u
// Mast 영점 설정
#define SHIFT_MAST_ORIGIN 0x02u
// 과전류 클리어
#define SHIFT_MAST_OVER_CURR 0x03u
// 과전류 알람
#define SHIFT_OVER_CURR 0x02u
// 엔코더 값 불일치 알람
#define SHIFT_ENCODER_ERR 0x06u
// 엔코더 H/W 리셋
#define SHIFT_ENCODER_HW_RESET 7u
// 엔코더 HW 리셋 클리어
#define SHIFT_ENCODER_HW_RESET_CLEAR 4u
// UDP 통신 커맨드
#define TCP_CMD_PERIOD_REPORT_STOP 0x00u
#define TCP_CMD_PERIOD_REPORT_START 0x40u
// TCP/IP 통신
// TCP MSG - TYPE
#define IDC_CMD_TYPE_DEVICE_PBIT 0x98u
#define IDC_CMD_TYPE_BIT_DETAIL 0x9Au
#define IDC_CMD_TYPE_MAST_CONTROL 0x9Bu
#define IDC_CMD_TYPE_DEVICE_ERASE 0x91u
#define IDC_CMD_TYPE_DEVICE_POWER 0x91u
// UDP MSG TYPE
#define IDC_CMD_TYPE_STATUS_REPORT 0x90u
#define IDC_CMD_TYPE_HEART_BEAT 0x92u
#define IDC_CMD_TYPE_CBIT_REPORT 0x99u
// ICD Sour/Dest Unit
#define ICD_CMD_UNIT_MP 0x61u
#define ICD_CMD_UNIT_MAST 0x40u
// ICD TM
#define ICD_CMD_TM_TCP 0x24u
#define IDC_CMD_TM_UDP 0x04u
// Simmulation Alarm
#define ICD_CMD_SIM_ALARM_RESET 0x00u // 알람 실제 모드
#define ICD_CMD_SIM_ALARM_SET 0x01u // 알람 가상 모드
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//----------------------------------------tcp/ip setting---------------------------------------
//main.c에 define된 DEFAULT_IP_ADDRESS, DEFAULT_IP_MASK, DEFAULT_GW_ADDRESS를 함께 변경
#define MY_IP_ADDR1 172u
#define MY_IP_ADDR2 16u
#define MY_IP_ADDR3 0u
#define MY_IP_ADDR4 50u
#define IPINFO_SIZE 6u
#define CHAR_SOUR 0x61u
//----------------------------------------TCP Server-------------------------------------------
#define NUM_TCP_CLIENT 2u
#define NUM_RECV_BUF 400u
#define MIN_TCP_SER_RCV_LEN 10u // 유효한 최소 패킷 사이즈
#define LEN_COMPARE 3u // 유효 패킷 검사 사이즈
#define LEN_ANT_MAST_START_REQ 10u // DeviceStart_Request Length
#define LEN_DEVICE_PBIT_REQ 10u // DevicePBIT_Request Length
#define LEN_DEVICE_BIT_DETAIL_REQ 11u // DeviceBITdetail_Request Length
#define LEN_ANT_MAST_CONTROL_REQ 11u // AntMastControl_Request Length, 가변, 8 ~ 12(코드에서 처리)
#define LEN_DEVICE_ERASE_REQ 11u // DeviceErase_Request Length
#define LEN_DEVICE_POWER_REQ 11u // DevicePower_Request Length
#define LEN_SIM_ALARM_SET_REQ 12u // SimAlarmSet_Request Length
#define LEN_MAST_ORIGIN_SET_REQ 10u // MastOrigin_Set_Request Length
//----------------------------------------TCP Client-------------------------------------------
#define TCP_CLIENT_MY_PORT 61501u // TCP Client 사용 24.06.27
#define TCP_MP_IP_ADDR1 172u // 임무통제기 내부 IP Address
#define TCP_MP_IP_ADDR2 16u
#define TCP_MP_IP_ADDR3 0u
#define TCP_MP_IP_ADDR4 20u
#define TCP_MP_PORT 61202U // 임무통제기 내부 Port
//----------------------------------------UDP Client-------------------------------------------
#define UDP_SERVER_IP_ADDRESS "172.16.0.20" // 172.16.x.x
#define UDP_SERVER_IP_ADDR1 172u
#define UDP_SERVER_IP_ADDR2 16u
#define UDP_SERVER_IP_ADDR3 0u
#define UDP_SERVER_IP_ADDR4 20u
#define UDP_SERVER_PORT 60202u // 변경 24.06.27
#define UDP_MY_PORT 61501u
#define LEN_ANT_MAST_STATUS_REPORT 15u
#define LEN_ANT_MAST_CBIT_REPORT 12u
#define LEN_HEART_BEAT_DATA 11u
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
// REGISTER INDEX
#define REG_IDX_0 0u
#define REG_IDX_1 1u
#define REG_IDX_2 2u
#define REG_IDX_3 3u
#define REG_IDX_4 4u
#define REG_IDX_5 5u
#define REG_IDX_6 6u
#define REG_IDX_7 7u
#define REG_IDX_8 8u
#define REG_IDX_9 9u
#define REG_IDX_10 10u
#define REG_IDX_11 11u
#define REG_IDX_12 12u
#define IIC_SCLK_RATE 100000u
#define TEST_BUFFER_SIZE 8u // EEPROM 읽기/쓰기 버퍼 사이즈
#define EEPROM_ADDR 0x50u // AT24C08C의 기본 I2C 주소, A2, A1, A0 모두 0일 경우
#endif // DEFINE_H

200
src/eeprom.c Normal file
View File

@ -0,0 +1,200 @@
#include "eeprom.h"
#include "ctrl_module.h"
#include "sleep.h"
u8 g_szIpInfo[IPINFO_SIZE] = { 0, }; // IP Address, Port
// EEPROM 초기화
void InitEeprom(void)
{
XIicPs_Config *ConfigPtr;
s32_t Status;
u32_t nData;
u32_t nRet;
u8 cEepromBuf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
xil_printf("InitEeprom Start\n");
ConfigPtr = XIicPs_LookupConfig(XPAR_XIICPS_0_DEVICE_ID);
if (NULL == ConfigPtr)
{
#if DEBUG_COVER
xil_printf("No config found for %d\n", XPAR_XIICPS_0_DEVICE_ID);
#endif
}
else
{
Status = XIicPs_CfgInitialize(&Iic, ConfigPtr, ConfigPtr->BaseAddress);
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
xil_printf("Initialization failed\n");
#endif
}
else
{
(void)XIicPs_SetSClk(&Iic, IIC_SCLK_RATE);
LoadEepromInfo(cEepromBuf); // Eeprom 정보 전체 읽기
if(cEepromBuf[1] == 0xFFu) // 공장초기화값이면 0 설정
{
g_cDeviceErase = 0u;
}
else // 정상값이면 0 또는 1
{
#if DEBUG_COVER
g_cDeviceErase = cEepromBuf[1];
#endif
}
xil_printf("Init Eeprom g_cDeviceErase:%d\n\n", (u32_t)g_cDeviceErase);
nData = cEepromBuf[2];
g_nEncoderMT = nData << 16;
nData = cEepromBuf[3];
g_nEncoderMT += nData << 8;
g_nEncoderMT += cEepromBuf[4];
xil_printf("Init Eeprom g_nEncoderMT:%06X\n", g_nEncoderMT);
xil_printf("InitEeprom End\n");
}
}
}
static s32 EepromWriteByte(XIicPs *IicInstance, u8 Address, u8 Data)
{
s32_t Status, nRet = XST_SUCCESS;
u8 Buffer[2];
Buffer[0] = Address; // 1바이트 주소 // 주소 및 데이터 버퍼 설정
Buffer[1] = Data; // 데이터
Status = XIicPs_MasterSendPolled(IicInstance, Buffer, 2, EEPROM_ADDR); // I2C를 통한 데이터 쓰기
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
nRet = Status;
#endif
}
else
{
while (XIicPs_BusIsBusy(IicInstance) == 1)
{
; // I2C 트랜잭션이 완료될 때까지 대기
}
(void)usleep(10000); // 쓰기 지연 대기 (최대 10ms, EEPROM 데이터 시트 참조)
}
return nRet;
}
static s32 EepromReadByte(XIicPs *IicInstance, u8 Address, u8 *Data)
{
s32_t Status, nRet = XST_SUCCESS;
Status = XIicPs_MasterSendPolled(IicInstance, &Address, 1, EEPROM_ADDR); // 주소 전송
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
nRet = Status;
#endif
}
else
{
while (XIicPs_BusIsBusy(IicInstance) == 1)
{
; // I2C 트랜잭션이 완료될 때까지 대기
}
Status = XIicPs_MasterRecvPolled(IicInstance, Data, 1, EEPROM_ADDR); // 데이터 읽기
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
nRet = Status;
#endif
}
}
return nRet;
}
// 엔코더 멀티턴값 쓰기
void SaveEncoderMT(u32 cVal)
{
s32 Status = 0;
u8 cAddr = 0x02;
Status = EepromWriteByte(&Iic, cAddr, (u8_t)(cVal >> 16)); // bit23 ~ 16 기록 // EEPROM에 데이터 쓰기
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
xil_printf("EEPROM write failed\n");
#endif
}
else
{
xil_printf("encoder multiturn 1st write succeded:%X\n", (u32_t)(cVal >> 16));
}
(void)usleep(10000);
Status = EepromWriteByte(&Iic, (u8_t)(cAddr + 1u), (u8_t)(cVal >> 8)); // bit15 ~ 8 기록 // EEPROM에 데이터 쓰기
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
xil_printf("EEPROM write failed\n");
#endif
}
else
{
xil_printf("encoder multiturn 2nd write succeded:%X\n", (u32_t)(cVal >> 8));
}
(void)usleep(10000);
Status = EepromWriteByte(&Iic, (u8_t)(cAddr + 2u), (u8_t)cVal); // bit7 ~ 0 기록
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
xil_printf("EEPROM write failed\n");
#endif
}
else
{
xil_printf("encoder multiturn 3rd write succeded:%X\n", (u32_t)cVal);
}
return Status;
}
// Eeprom 정보 전체 읽기
// Eeprom Read 시 Address 제어가 지정대로 동작되지 않는 경우
// 발생하여 일정 범위 읽어서 처리하도록 변경함
static void LoadEepromInfo(u8* cVal)
{
u8 i = 1u; // Start Address
s32_t Status;
u8 cData = 0u;
for(i = 0u; i < 5u; i++)
{
Status = EepromReadByte(&Iic, i, &cData);
if (Status != XST_SUCCESS)
{
#if DEBUG_COVER
xil_printf("EEPROM read failed\n");
#endif
}
else
{
xil_printf("read addr:%d, cData:%X\r\n", (u32_t)i, (u32_t)cData);
}
cVal[i] = cData; // 값 가져가기
}
}

19
src/eeprom.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef EEPROM_H
#define EEPROM_H
#include "xiicps.h"
#include "define.h"
extern u8 g_szIpInfo[IPINFO_SIZE]; // IP Address, Port
XIicPs Iic; // I2C 인스턴스
void InitEeprom(void); // EEPROM 초기화
static s32 EepromWriteByte(XIicPs *IicInstance, u8 Address, u8 Data);
static s32 EepromReadByte(XIicPs *IicInstance, u8 Address, u8 *Data);
void SaveEncoderMT(u32 cVal); // 엔코더 멀티턴값 쓰기
static void LoadEepromInfo(u8* cVal); // Eeprom 정보 전체 읽기
#endif

289
src/lscript.ld Normal file
View File

@ -0,0 +1,289 @@
/*******************************************************************/
/* */
/* This file is automatically generated by linker script generator.*/
/* */
/* Version: 2019.2 */
/* */
/* Copyright (c) 2010-2019 Xilinx, Inc. All rights reserved. */
/* */
/* Description : Cortex-A9 Linker Script */
/* */
/*******************************************************************/
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0xA000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0xA000;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
/* Define Memories in the system */
MEMORY
{
axi_bram_ctrl_0_Mem0 : ORIGIN = 0x40000000, LENGTH = 0x2000
ps7_ddr_0 : ORIGIN = 0x100000, LENGTH = 0x1FF00000
ps7_qspi_linear_0 : ORIGIN = 0xFC000000, LENGTH = 0x1000000
ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000
ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00
}
/* Specify the default entry point to the program */
ENTRY(_vector_table)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.text : {
KEEP (*(.vectors))
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > ps7_ddr_0
.init : {
KEEP (*(.init))
} > ps7_ddr_0
.fini : {
KEEP (*(.fini))
} > ps7_ddr_0
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > ps7_ddr_0
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > ps7_ddr_0
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > ps7_ddr_0
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > ps7_ddr_0
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > ps7_ddr_0
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > ps7_ddr_0
.got : {
*(.got)
} > ps7_ddr_0
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > ps7_ddr_0
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
___DTORS_END___ = .;
} > ps7_ddr_0
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > ps7_ddr_0
.eh_frame : {
*(.eh_frame)
} > ps7_ddr_0
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > ps7_ddr_0
.gcc_except_table : {
*(.gcc_except_table)
} > ps7_ddr_0
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > ps7_ddr_0
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > ps7_ddr_0
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > ps7_ddr_0
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > ps7_ddr_0
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > ps7_ddr_0
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > ps7_ddr_0
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > ps7_ddr_0
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > ps7_ddr_0
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > ps7_ddr_0
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > ps7_ddr_0
.bss (NOLOAD) : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
__bss_end = .;
} > ps7_ddr_0
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > ps7_ddr_0
.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
. = ALIGN(16);
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _IRQ_STACK_SIZE;
. = ALIGN(16);
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > ps7_ddr_0
_end = .;
}

277
src/main.c Normal file
View File

@ -0,0 +1,277 @@
#include "xparameters.h"
#include "netif/xadapter.h"
#include "platform.h"
#include "platform_config.h"
#include "lwipopts.h"
#include "xil_printf.h"
#include "sleep.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/init.h"
#include "lwip/inet.h"
#include "lwip/tcp.h"
#include "xil_cache.h"
#include "define.h"
#include "main.h"
#include "ctrl_module.h"
#include "tcpipcomm.h"
#include "tcp_client.h"
#include "udp_client.h"
#include "eeprom.h"
#if LWIP_IPV6==1
#include "lwip/ip6_addr.h"
#include "lwip/ip6.h"
#else
#if LWIP_DHCP==1
#include "lwip/dhcp.h"
extern volatile u32_t dhcp_timoutcntr;
#endif
#define DEFAULT_IP_ADDRESS "172.16.0.50"
#define DEFAULT_IP_MASK "255.255.255.0"
#define DEFAULT_GW_ADDRESS "172.16.0.1"
#endif /* LWIP_IPV6 */
extern volatile u32_t TcpFastTmrFlag;
extern volatile u32_t TcpSlowTmrFlag;
struct netif server_netif;
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || \
XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
u32_t ProgramSi5324(void);
u32_t ProgramSfpPhy(void);
#endif
#endif
#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
u32_t IicPhyReset(void);
#endif
#endif
#if LWIP_IPV6==1
static void print_ipv6(u32_t *msg, ip_addr_t *ip)
{
print(msg);
xil_printf(" %s\n\r", inet6_ntoa(*ip));
}
#else
static void print_ip(const char8 *msg, const ip_addr_t *ip)
{
print(msg);
xil_printf("%d.%d.%d.%d\r\n", (u32_t)ip4_addr1(ip), (u32_t)ip4_addr2(ip),
(u32_t)ip4_addr3(ip), (u32_t)ip4_addr4(ip));
}
static void print_ip_settings(const ip_addr_t *ip, const ip_addr_t *mask, const ip_addr_t *gw)
{
print_ip("Board IP: ", ip);
print_ip("Netmask : ", mask);
print_ip("Gateway : ", gw);
}
static void assign_default_ip(const ip_addr_t *ip, const ip_addr_t *mask, const ip_addr_t *gw)
{
u32_t err;
xil_printf("Configuring default IP %s \r\n", DEFAULT_IP_ADDRESS);
err = (u32_t)inet_aton(DEFAULT_IP_ADDRESS, ip);
if (err == 0u)
{
#if DEBUG_COVER
xil_printf("Invalid default IP address: %d\r\n", (u32_t)err);
#endif
}
err = (u32_t)inet_aton(DEFAULT_IP_MASK, mask);
if (err == 0u)
{
#if DEBUG_COVER
xil_printf("Invalid default IP MASK: %d\r\n", (u32_t)err);
#endif
}
err = (u32_t)inet_aton(DEFAULT_GW_ADDRESS, gw);
if (err == 0u)
{
#if DEBUG_COVER
xil_printf("Invalid default gateway address: %d\r\n", (u32_t)err);
#endif
}
}
#endif /* LWIP_IPV6 */
static void MakeTiming(void)
{
if(++g_nCnt1 > TIMER_BASE)
{
g_nCnt1 = 0;
g_nCnt2++; // ctrl_module.c CtrlModuleProcess()
g_nEcdeepromCnt++; // ctrl_module.c SetMotor()
g_nTcpCliConCnt++; // tcp_client.c ConnectToTcpServer()
g_nReportCnt++; // udp_client.c UdpCommPeriod()
if(g_stTcpClientMy.cConnected == TRUE) // client가 임무처리 S/W(Server)에 연결된 상태에서만 카운터
{
g_nBitDetailHBCnt++; // udp_client.c UdpCommProcess()
g_nTcpDisconnectCnt++; // udp_client.c
}
}
}
static void TcpipProcChk(struct netif* nif)
{
if (TcpFastTmrFlag != 0u) {
tcp_fasttmr();
TcpFastTmrFlag = 0u;
}
if (TcpSlowTmrFlag != 0u) {
tcp_slowtmr();
TcpSlowTmrFlag = 0u;
}
(void)xemacif_input(nif);
}
u32_t main(void)
{
struct netif *netif;
u8_t mac_ethernet_address[] = { 0x48, 0x21, 0x0B, 0x5A, 0x37, 0xA7 }; /* the mac address of the board. this should be unique per board */
u16_t nData = 0;
u32_t nData32 = 0;
netif = &server_netif;
static ip_addr_t ipaddr, netmask, gw;
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || \
XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
ProgramSi5324();
ProgramSfpPhy();
#endif
#endif
/* Define this board specific macro in order perform PHY reset
* on ZCU102
*/
#ifdef XPS_BOARD_ZCU102
IicPhyReset();
#endif
init_platform();
xil_printf("\r\n\r\n");
xil_printf("=====================================================\n\r");
xil_printf("-----\tAntMastPh2 Control Module V%d.%d.%d.%d\t-----\n\r", (u32_t)VER_VERSION, (u32_t)VER_UPDATE, (u32_t)VER_TEST, (u32_t)VER_COMPILE);
#if TEST_LOG_ON
xil_printf("-----\tCompiled by HKC\t[Debug]\t\t\t-----\n\r");
#else
xil_printf("-----\tCompiled by HKC\t[Release]\t\t-----\n\r");
#endif
xil_printf("=====================================================\n\r");
g_szIpInfo[0] = MY_IP_ADDR1;
g_szIpInfo[1] = MY_IP_ADDR2;
g_szIpInfo[2] = MY_IP_ADDR3;
g_szIpInfo[3] = MY_IP_ADDR4;
IP4_ADDR(&ipaddr, g_szIpInfo[0], g_szIpInfo[1], g_szIpInfo[2], g_szIpInfo[3]);
IP4_ADDR(&netmask, 255, 255, 255, 0); // 24.06.27 변경
IP4_ADDR(&gw, g_szIpInfo[0], g_szIpInfo[1], g_szIpInfo[2], 1); // 24.06.27 변경
lwip_init(); /* initialize lwIP */
//if (!xemac_add(netif, NULL, NULL, NULL, mac_ethernet_address,
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add((struct netif*)netif, (ip_addr_t*)&ipaddr, (ip_addr_t*)&netmask, (ip_addr_t*)&gw, (u8_t*)mac_ethernet_address, (u32_t)PLATFORM_EMAC_BASEADDR))
{
#if DEBUG_COVER
xil_printf("Error adding N/W interface\r\n");
#endif
}
else
{
#if LWIP_IPV6==1
netif->ip6_autoconfig_enabled = 1;
netif_create_ip6_linklocal_address(netif, 1);
netif_ip6_addr_set_state(netif, 0, IP6_ADDR_VALID);
print_ipv6("\n\rlink local IPv6 address is:", &netif->ip6_addr[0]);
#endif /* LWIP_IPV6 */
netif_set_default(netif);
/* now enable interrupts */
platform_enable_interrupts();
/* specify that the network if is up */
netif_set_up(netif);
#if (LWIP_IPV6==0)
#if (LWIP_DHCP==1)
/* Create a new DHCP client for this interface.
* Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
* the predefined regular intervals after starting the client.
*/
dhcp_start(netif);
dhcp_timoutcntr = 24;
while (((netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
xemacif_input(netif);
if (dhcp_timoutcntr <= 0) {
if ((netif->ip_addr.addr) == 0) {
xil_printf("ERROR: DHCP request timed out\r\n");
assign_default_ip(&(netif->ip_addr), &(netif->netmask), &(netif->gw));
}
}
/* print IP address, netmask and gateway */
#else
assign_default_ip((const ip_addr_t*)&(netif->ip_addr), (const ip_addr_t*)&(netif->netmask), (const ip_addr_t*)&(netif->gw));
#endif
print_ip_settings((const ip_addr_t*)&(netif->ip_addr), (const ip_addr_t*)&(netif->netmask), (const ip_addr_t*)&(netif->gw));
#endif /* LWIP_IPV6 */
g_cSn = 0; // 응답패킷 송신 카운터
InitEeprom(); // eeprom 초기화
InitCtrlModule(); // 제어부 모듈 초기 설정 //InitTcpServer(); // TCP 서버 초기화
InitTcpClient(); // TCP Client 초기화
InitUdpServer(); // UDP Server 초기화 //InitUdpClient(); // UDP Client 초기화
InitCompareMember(); // 문자열 비교 초기화
while (1)
{
if(g_cDeviceErase == 0u) // Device Erase가 설정되지 않으면 정상 동작, 적용하면 전체 오류발생 24.03.05
{
MakeTiming();
CtrlModuleProcess(); // 제어부 모듈 동작 처리 //TcpServCommProcess(); // 서버에 연결된 TCP 클라이언트 수신 및 송신 처리
TcpClientCommProceess(); // TCP Client 수신 및 송신 처리
ConnectToTcpServer(); // TCP 서버 반복 접속 관리
UdpCommProcess(); // UDP 통신 처리
TcpipProcChk(netif);
}
}
}
return 0;
}

17
src/main.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef MAIN_H
#define MAIN_H
#include "xtime_l.h"
#include "tcp_client.h"
static XTime g_nStartTime;
static XTime g_nCurTime;
static uint32_t g_nCnt1;
static void MakeTiming(void);
static void TcpipProcChk(struct netif* nif);
#endif // MAIN_H

179
src/platform.c Normal file
View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2009 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
#if __MICROBLAZE__
#include "arch/cc.h"
#include "platform.h"
#include "platform_config.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xintc.h"
#include "xil_exception.h"
#include "lwip/tcp.h"
#ifdef STDOUT_IS_16550
#include "xuartns550_l.h"
#endif
#include "lwip/tcp.h"
#if LWIP_DHCP==1
volatile int dhcp_timoutcntr = 24;
void dhcp_fine_tmr();
void dhcp_coarse_tmr();
#endif
volatile int TcpFastTmrFlag = 0;
volatile int TcpSlowTmrFlag = 0;
volatile u64_t tickcntr = 0;
void
timer_callback()
{
/* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified
* by lwIP.
* It is not important that the timing is absoluetly accurate.
*/
static int odd = 1;
#if LWIP_DHCP==1
static int dhcp_timer = 0;
#endif
tickcntr++;
if(tickcntr % 25 == 0){
TcpFastTmrFlag = 1;
odd = !odd;
if (odd) {
TcpSlowTmrFlag = 1;
#if LWIP_DHCP==1
dhcp_timer++;
dhcp_timoutcntr--;
dhcp_fine_tmr();
if (dhcp_timer >= 120) {
dhcp_coarse_tmr();
dhcp_timer = 0;
}
#endif
}
}
}
static XIntc intc;
void platform_setup_interrupts()
{
XIntc *intcp;
intcp = &intc;
XIntc_Initialize(intcp, XPAR_INTC_0_DEVICE_ID);
XIntc_Start(intcp, XIN_REAL_MODE);
/* Start the interrupt controller */
XIntc_MasterEnable(XPAR_INTC_0_BASEADDR);
#ifdef __MICROBLAZE__
microblaze_register_handler((XInterruptHandler)XIntc_InterruptHandler, intcp);
#endif
platform_setup_timer();
#ifdef XPAR_ETHERNET_MAC_IP2INTC_IRPT_MASK
/* Enable timer and EMAC interrupts in the interrupt controller */
XIntc_EnableIntr(XPAR_INTC_0_BASEADDR,
#ifdef __MICROBLAZE__
PLATFORM_TIMER_INTERRUPT_MASK |
#endif
XPAR_ETHERNET_MAC_IP2INTC_IRPT_MASK);
#endif
#ifdef XPAR_INTC_0_LLTEMAC_0_VEC_ID
#ifdef __MICROBLAZE__
XIntc_Enable(intcp, PLATFORM_TIMER_INTERRUPT_INTR);
#endif
XIntc_Enable(intcp, XPAR_INTC_0_LLTEMAC_0_VEC_ID);
#endif
#ifdef XPAR_INTC_0_AXIETHERNET_0_VEC_ID
XIntc_Enable(intcp, PLATFORM_TIMER_INTERRUPT_INTR);
XIntc_Enable(intcp, XPAR_INTC_0_AXIETHERNET_0_VEC_ID);
#endif
#ifdef XPAR_INTC_0_EMACLITE_0_VEC_ID
#ifdef __MICROBLAZE__
XIntc_Enable(intcp, PLATFORM_TIMER_INTERRUPT_INTR);
#endif
XIntc_Enable(intcp, XPAR_INTC_0_EMACLITE_0_VEC_ID);
#endif
}
void
enable_caches()
{
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
Xil_ICacheEnable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
Xil_DCacheEnable();
#endif
#endif
}
void
disable_caches()
{
Xil_DCacheDisable();
Xil_ICacheDisable();
}
void init_platform()
{
enable_caches();
#ifdef STDOUT_IS_16550
XUartNs550_SetBaud(STDOUT_BASEADDR, XPAR_XUARTNS550_CLOCK_HZ, 9600);
XUartNs550_SetLineControlReg(STDOUT_BASEADDR, XUN_LCR_8_DATA_BITS);
#endif
platform_setup_interrupts();
}
void cleanup_platform()
{
disable_caches();
}
u64_t get_time_ms()
{
return tickcntr * 10;
}
#endif

40
src/platform.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2009 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
#ifndef __PLATFORM_H_
#define __PLATFORM_H_
void init_platform();
void cleanup_platform();
#ifdef __MICROBLAZE__
void timer_callback();
#endif
void platform_setup_timer();
void platform_enable_interrupts();
u64_t get_time_ms();
#endif

10
src/platform_config.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __PLATFORM_CONFIG_H_
#define __PLATFORM_CONFIG_H_
#define PLATFORM_EMAC_BASEADDR XPAR_XEMACPS_0_BASEADDR
#define PLATFORM_ZYNQ
#endif

233
src/platform_zynq.c Normal file
View File

@ -0,0 +1,233 @@
/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
/*
* platform_zynq.c
*
* Zynq platform specific functions.
*
* 02/29/2012: UART initialization is removed. Timer initializations are
* removed. All unnecessary include files and hash defines are removed.
* 03/01/2013: Timer initialization is added back. Support for SI #692601 is
* added in the timer callback. The SI #692601 refers to the following issue.
*
* The EmacPs has a HW bug on the Rx path for heavy Rx traffic.
* Under heavy Rx traffic because of the HW bug there are times when the Rx path
* becomes unresponsive. The workaround for it is to check for the Rx path for
* traffic (by reading the stats registers regularly). If the stats register
* does not increment for sometime (proving no Rx traffic), the function resets
* the Rx data path.
*
* </pre>
*/
#ifdef __arm__
#include "platform_config.h"
#ifdef PLATFORM_ZYNQ
#include "xparameters.h"
#include "xparameters_ps.h" /* defines XPAR values */
#include "xil_cache.h"
#include "xscugic.h"
#include "lwip/tcp.h"
#include "xil_printf.h"
#include "netif/xadapter.h"
#include "xscutimer.h"
#include "xtime_l.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define TIMER_DEVICE_ID XPAR_SCUTIMER_DEVICE_ID
#define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR
#define RESET_RX_CNTR_LIMIT 400
void tcp_fasttmr(void);
void tcp_slowtmr(void);
static XScuTimer TimerInstance;
#ifndef USE_SOFTETH_ON_ZYNQ
static int ResetRxCntr = 0;
extern struct netif server_netif;
#endif
volatile int TcpFastTmrFlag = 0;
volatile int TcpSlowTmrFlag = 0;
#if LWIP_DHCP==1
volatile int dhcp_timoutcntr = 24;
void dhcp_fine_tmr();
void dhcp_coarse_tmr();
#endif
void
timer_callback(XScuTimer * TimerInstance)
{
/* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified
* by lwIP. It is not important that the timing is absoluetly accurate.
*/
static int odd = 1;
#if LWIP_DHCP==1
static int dhcp_timer = 0;
#endif
TcpFastTmrFlag = 1;
odd = !odd;
#ifndef USE_SOFTETH_ON_ZYNQ
ResetRxCntr++;
#endif
if (odd) {
TcpSlowTmrFlag = 1;
#if LWIP_DHCP==1
dhcp_timer++;
dhcp_timoutcntr--;
dhcp_fine_tmr();
if (dhcp_timer >= 120) {
dhcp_coarse_tmr();
dhcp_timer = 0;
}
#endif
}
/* For providing an SW alternative for the SI #692601. Under heavy
* Rx traffic if at some point the Rx path becomes unresponsive, the
* following API call will ensures a SW reset of the Rx path. The
* API xemacpsif_resetrx_on_no_rxdata is called every 100 milliseconds.
* This ensures that if the above HW bug is hit, in the worst case,
* the Rx path cannot become unresponsive for more than 100
* milliseconds.
*/
#ifndef USE_SOFTETH_ON_ZYNQ
if (ResetRxCntr >= RESET_RX_CNTR_LIMIT) {
xemacpsif_resetrx_on_no_rxdata(&server_netif);
ResetRxCntr = 0;
}
#endif
XScuTimer_ClearInterruptStatus(TimerInstance);
}
void platform_setup_timer(void)
{
int Status = XST_SUCCESS;
XScuTimer_Config *ConfigPtr;
int TimerLoadValue = 0;
ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
Status = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
xil_printf("In %s: Scutimer Cfg initialization failed...\r\n",
__func__);
return;
}
Status = XScuTimer_SelfTest(&TimerInstance);
if (Status != XST_SUCCESS) {
xil_printf("In %s: Scutimer Self test failed...\r\n",
__func__);
return;
}
XScuTimer_EnableAutoReload(&TimerInstance);
/*
* Set for 250 milli seconds timeout.
*/
TimerLoadValue = XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 8;
XScuTimer_LoadTimer(&TimerInstance, TimerLoadValue);
return;
}
void platform_setup_interrupts(void)
{
Xil_ExceptionInit();
XScuGic_DeviceInitialize(INTC_DEVICE_ID);
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler,
(void *)INTC_DEVICE_ID);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
XScuGic_RegisterHandler(INTC_BASE_ADDR, TIMER_IRPT_INTR,
(Xil_ExceptionHandler)timer_callback,
(void *)&TimerInstance);
/*
* Enable the interrupt for scu timer.
*/
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, TIMER_IRPT_INTR);
return;
}
void platform_enable_interrupts()
{
/*
* Enable non-critical exceptions.
*/
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
XScuTimer_EnableInterrupt(&TimerInstance);
XScuTimer_Start(&TimerInstance);
return;
}
void init_platform()
{
platform_setup_timer();
platform_setup_interrupts();
return;
}
void cleanup_platform()
{
Xil_ICacheDisable();
Xil_DCacheDisable();
return;
}
u64_t get_time_ms()
{
#define COUNTS_PER_MILLI_SECOND (COUNTS_PER_SECOND/1000)
XTime tCur = 0;
XTime_GetTime(&tCur);
return (tCur/COUNTS_PER_MILLI_SECOND);
}
#endif
#endif

288
src/tcp_client.c Normal file
View File

@ -0,0 +1,288 @@
#include "tcp_client.h"
// TCP Client 초기화
void InitTcpClient(void)
{
IP_ADDR4(&g_ipaddrMP, TCP_MP_IP_ADDR1, TCP_MP_IP_ADDR2, TCP_MP_IP_ADDR3, TCP_MP_IP_ADDR4); // 임무 IP
g_stTcpClientMy.cConnected = FALSE;
(void)memset((void *)g_stTcpClientMy.szRecvData, (s32_t)0, (s32_t)(NUM_RECV_BUF * sizeof(u8_t)));
g_stTcpClientMy.nRecvLen = 0;
g_stTcpClientMy.cRecvFlag = FALSE;
g_stTcpClientMy.cIsConnecting = FALSE;
m_nConnectCnt = 0;
g_nTcpDisconnectChk = 1u; // 접속 후 임무처리S/W의 Heart Beat 미 수신이 5초 이상 유지되면 접속해제
tcp_client_connect(); // TCP 서버 접속
}
// TCP 서버 접속
static void tcp_client_connect(void)
{
struct tcp_pcb *pcb;
err_t err = 0;
pcb = tcp_new();
if(pcb != NULL)
{
xil_printf("TCP Client: tcp_new() ok.\n");
ip_set_option(pcb, SOF_REUSEADDR); // sockoption ip, port 재사용 옵션 추가
err = tcp_bind(pcb, IP_ADDR_ANY, TCP_CLIENT_MY_PORT);
g_stTcpClientMy.cIsConnecting = TRUE;
if(err == (err_t)ERR_OK)
{
xil_printf("TCP Client: binding ok.\n");
xil_printf("connecting to Server..\n");
(void)tcp_connect(pcb, &g_ipaddrMP, TCP_MP_PORT, tcp_client_connected);
}
else
{
#if DEBUG_COVER
xil_printf("TCP Client: bind error.\n");
#endif
}
}
else
{
#if DEBUG_COVER
xil_printf("TCP Client: Error creating PCB.\n");
#endif
}
}
// TCP 서버 반복 접속 관리
void ConnectToTcpServer(void)
{
if(g_nTcpCliConCnt > TIMER_SEC1)
{
g_nTcpCliConCnt = 0u;
if(g_stTcpClientMy.cConnected == FALSE)
{
m_nConDelayCnt++;
if(m_nConDelayCnt > 5u) // 5초 경과 후 접속 시도
{
m_nConDelayCnt = 0u;
if(g_stTcpClientMy.cIsConnecting == TRUE)
{
m_nConnectCnt++;
xil_printf("\n\nConnect Count:%d\n\n", m_nConnectCnt);
xil_printf("TCP Client: Close Client Socket\n");
tcp_client_connection_close(g_stTcpClientMy.pcb);
g_stTcpClientMy.cIsConnecting = FALSE;
}
else
{
xil_printf("TCP Client: Start Connecting to Server\n");
tcp_client_connect(); // TCP 서버 접속
}
}
else
{
if(g_stTcpClientMy.cIsConnecting == TRUE)
{
xil_printf("TCP Client: Waiting Connection...%d\n", (u32_t)m_nConDelayCnt);
}
else
{
xil_printf("TCP Client: Stay...%d\n", (u32_t)m_nConDelayCnt);
}
}
}
}
}
// connect 콜백 함수
static err_t tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
u32_t i;
err_t ret_err = 0;
u32_t ipaddr;
void* Dummy;
struct tcp_pcb *pPcb = NULL;
Dummy = arg;
#if TEST_LOG_ON
xil_printf("tcp_client_connected()\n\r");
#endif
if(err == (err_t)ERR_OK)
{
if ((err != (err_t)ERR_OK) || (tpcb == NULL)) {
ret_err = ERR_VAL;
}
ipaddr = tpcb->remote_ip.addr;
xil_printf("accept() - %d.%d.%d.%d:%05d\r\n", (u32_t)(ipaddr & 0xFFu), (u32_t)((ipaddr >> 8) & 0xFFu), (u32_t)((ipaddr >> 16) & 0xFFu), (u32_t)((ipaddr >> 24) & 0xFFu), (u32_t)tpcb->remote_port);
tcp_setprio(tpcb, TCP_PRIO_MIN); // set priority
pPcb = (struct tcp_pcb*)mem_malloc(sizeof(struct tcp_pcb));
if(pPcb != NULL)
{
pPcb = tpcb;
tcp_arg((struct tcp_pcb*)tpcb, (void*)pPcb);
tcp_recv((struct tcp_pcb*)tpcb, tcp_client_recv);
tcp_sent((struct tcp_pcb*)tpcb, tcp_client_sent);
tcp_poll((struct tcp_pcb*)tpcb, tcp_client_poll, 1);
g_stTcpClientMy.cConnected = TRUE;
g_stTcpClientMy.pcb = pPcb;
g_stTcpClientMy.nRecvLen = 0;
g_stTcpClientMy.cRecvFlag = FALSE;
g_stTcpClientMy.cIsConnecting = FALSE; // 접속 시도 중 여부, 해제
g_nTcpDisconnectChk = 1; // 접속 후 임무처리S/W의 Heart Beat 미 수신이 5초 이상 유지되면 접속해제
ret_err = (err_t)ERR_OK;
}
else
{
tcp_client_connection_close(tpcb);
ret_err = ERR_MEM;
}
}
else
{
ret_err = (err_t)ERR_OK;
}
return ret_err;
}
// 수신 콜백 함수
static err_t tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
err_t ret_err;
u32_t ipaddr;
void* Dummy;
Dummy = arg;
if(p == NULL)
{
#if TEST_LOG_ON
xil_printf("tcp_client_recv() - p == NULL\r\n");
#endif
ipaddr = tpcb->remote_ip.addr;
xil_printf("tcp_client_recv() - p == NULL() - %d.%d.%d.%d:%05d\r\n", (u32_t)(ipaddr & 0xFFu), (u32_t)((ipaddr >> 8) & 0xFFu), (u32_t)((ipaddr >> 16) & 0xFFu), (u32_t)((ipaddr >> 24) & 0xFFu), (u32_t)tpcb->remote_port);
tcp_client_connection_close(tpcb);
ret_err = (err_t)ERR_OK;
}
else if(err != (err_t)ERR_OK)
{
#if TEST_LOG_ON
xil_printf("tcp_client_recv() - ERR\r\n");
#endif
if(p != NULL)
{
(void)pbuf_free(p);
}
ret_err = err;
}
else
{
g_stTcpClientMy.cRecvFlag = TRUE;
if(p->len < (u32_t)NUM_RECV_BUF)
{
(void)memcpy((void*)&g_stTcpClientMy.szRecvData[0], (const void*)p->payload, (size_t)p->len);
}
g_stTcpClientMy.nRecvLen = p->len;
ret_err = (err_t)ERR_OK;
}
return (err_t)ret_err;
}
// ACK 수신 콜백 함수
static err_t tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
u16_t nLenDummy = len;
u32_t ipaddr;
const struct tcp_pcb *pcbDummy = tpcb;
void *Dummy;
Dummy= arg;
ipaddr = tpcb->remote_ip.addr;
ipaddr += 1u;
return (err_t)ERR_OK;
}
// poll 콜백 함수
static err_t tcp_client_poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err = (err_t)ERR_OK;
u32_t ipaddr;
void *Dummy;
Dummy= arg;
ipaddr = tpcb->remote_ip.addr;
ipaddr += 1u;
LWIP_UNUSED_ARG(arg);
u8_t i = 0u;
struct tcp_pcb *pcbDummy = tpcb;
return (err_t)ret_err;
}
// client socket 종료 처리
void tcp_client_connection_close(struct tcp_pcb* tpcb)
{
err_t err;
u32_t ipaddr;
m_nConDelayCnt = 0u; // 재접속 판단 카운터 초기화
g_nBitDetailHBCnt = 0u;
g_nTcpDisconnectChk = 0u; // 접속 후 임무처리S/W의 Heart Beat 미 수신이 5초 이상 유지되면 접속해제
ipaddr = tpcb->remote_ip.addr;
xil_printf("tcp_client_connection_close() - %d.%d.%d.%d:%05d\r\n", (u32_t)(ipaddr & 0xFFu), (u32_t)((ipaddr >> 8) & 0xFFu), (u32_t)((ipaddr >> 16) & 0xFFu), (u32_t)((ipaddr >> 24) & 0xFFu), (u32_t)tpcb->remote_port);
g_stTcpClientMy.cConnected = FALSE;
(void)memset((void *)g_stTcpClientMy.szRecvData, (s32_t)0, (s32_t)(NUM_RECV_BUF * sizeof(u8_t)));
g_stTcpClientMy.nRecvLen = 0u;
g_stTcpClientMy.cRecvFlag = FALSE;
g_stTcpClientMy.cIsConnecting = FALSE;
tcp_arg(tpcb, NULL); // callback 해제
tcp_recv(tpcb, NULL);
tcp_sent(tpcb, NULL);
tcp_poll(tpcb, NULL, 0u);
err = tcp_close(tpcb);
if (err != (err_t)ERR_OK)
{
tcp_abort(tpcb); // Free memory with abort
}
}

45
src/tcp_client.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef TCP_CLIENT_H
#define TCP_CLIENT_H
#include "lwipopts.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/tcp.h"
#include "lwip/inet.h"
#include "xil_printf.h"
#include "eeprom.h"
#include "define.h"
#include "main.h"
#include "ctrl_module.h"
struct TcpCliConnectPcb
{
u8_t cConnected; // 접속 상태 확인, false일 때 재접속 시도
struct tcp_pcb *pcb; // tcp_pcb
u8_t szRecvData[NUM_RECV_BUF]; // 수신 버퍼
u32_t nRecvLen; // 수신 버퍼 사이즈
u8_t cRecvFlag; // 수신 플래그
u8_t cIsConnecting; // 접속 시도 중 여부
};
struct TcpCliConnectPcb g_stTcpClientMy; // 서버 접속용 클라이언트
static ip_addr_t g_ipaddrMP; // 임무처리기 TCP Server IP
static u8_t m_nConDelayCnt;
static u32_t m_nConnectCnt;
u32_t g_nTcpCliConCnt; // TCP Client가 서버에 미접속 상태일 때 접속 시도용 카운터
u32_t g_nTcpDisconnectCnt; // 접속 후 임무처리 S/W의 Heart Beat 미수신 5초 이상 발생 확인용 카운터
u32_t g_nTcpDisconnectChk; // 접속 후 임무처리S/W의 Heart Beat 미 수신이 5초 이상 유지되면 접속해제
void InitTcpClient(void); // TCP Client 초기화
static void tcp_client_connect(void); // TCP 서버 접속
void ConnectToTcpServer(void); // TCP 서버 반복 접속 관리
static err_t tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err); // connect 콜백 함수
static err_t tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); // 수신 콜백 함수
static err_t tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len); // ACK 수신 콜백 함수
static err_t tcp_client_poll(void *arg, struct tcp_pcb *tpcb); // poll 콜백 함수
void tcp_client_connection_close(struct tcp_pcb* tpcb); // client socket 종료 처리
#endif

290
src/tcpipcomm.c Normal file
View File

@ -0,0 +1,290 @@
#include "tcpipcomm.h"
#include "ctrl_module.h"
// 문자열 비교(strncmp에서 null 문자 시 종료되는 부분 비활성)
static u8_t strCompare(const u8_t *str1, const u8_t *str2, u8_t str2Len)
{
u8_t i, cVal = 1;
if(str2Len < 10u)
{
for(i = 0u ; i < str2Len ; i++)
{
if(str1[i] != str2[i])
{
cVal = 0; // 불일치 판정
}
}
}
return cVal; // 일치
}
// 문자열 비교 초기화 운용처리기 유효한 패킷 식별
void InitCompareMember(void)
{
szCase[0][0] = IDC_CMD_TYPE_DEVICE_PBIT; szCase[0][1] = 0x20u; szCase[0][2] = 0x40u; // DevicePBIT_Request PBIT 요청
szCase[1][0] = IDC_CMD_TYPE_BIT_DETAIL; szCase[1][1] = 0x20u; szCase[1][2] = 0x40u; // DeviceBITdetail_Request 장치별 세부 BIT 요청
szCase[2][0] = IDC_CMD_TYPE_MAST_CONTROL; szCase[2][1] = 0x23u; szCase[2][2] = 0x40u; // AntMastControl_Request 안테나마스트 설정 및 제어 요청
szCase[3][0] = IDC_CMD_TYPE_DEVICE_ERASE; szCase[3][1] = 0x20u; szCase[3][2] = 0x40u; // DeviceErase_Request 장치별 소거 요청
szCase[4][0] = IDC_CMD_TYPE_DEVICE_POWER; szCase[4][1] = 0x21u; szCase[4][2] = 0x40u; // DevicePower_Request 장치별 전원차단 요청
szCase[5][0] = 0xFFu; szCase[5][1] = 0xFEu; szCase[5][2] = 0x40u; // SimAlarm_Set 가상 알림 설정
szCase[6][0] = 0xFFu; szCase[6][1] = 0xFDu; szCase[6][2] = 0x40u; // MastOrigin_Set 가상 알림 설정
}
// TCP Client 수신 및 송신 처리
void TcpClientCommProceess(void)
{
u32_t j, nLen = 0;
if((g_stTcpClientMy.cConnected == TRUE) && (g_stTcpClientMy.cRecvFlag == TRUE)) // 접속된 pcb와 수신 패킷 존재 여부 확인
{
g_stTcpClientMy.cRecvFlag = FALSE; // 수신 플래그 해제
#if TEST_LOG_ON
xil_printf("rec msg:");
for(j = 0 ; j < g_stTcpClientMy.nRecvLen ; j++)
{
xil_printf("%02X", (u32_t)g_stTcpClientMy.szRecvData[j]);
}
xil_printf(" [%d]\r\n", g_stTcpClientMy.nRecvLen);
#endif
while(g_stTcpClientMy.nRecvLen >= (u32_t)MIN_TCP_SER_RCV_LEN) // 완성된 패킷 최소 사이즈보다 크거나 같을 경우 수신 처리
{
if(strCompare((const u8_t*)szCase[0], (const u8_t*)g_stTcpClientMy.szRecvData, (u8_t)LEN_COMPARE) == 1u) // 01. DevicePBIT_Request 장치별 PBIT 요청
{
nLen = LEN_DEVICE_PBIT_REQ;
g_cMastPeriodSendCmd = TCP_CMD_PERIOD_REPORT_START; // 1회 수신 시 전송 시작(전송 중지 없음)
FuncAntMastPBITRes((const u8_t *)g_stTcpClientMy.szRecvData); // 01. AntMastPBIT_Response 응답 처리
}
else if(strCompare((const u8_t*)szCase[1], (const u8_t*)g_stTcpClientMy.szRecvData, (u8_t)LEN_COMPARE) == 1u) // 02. DeviceBITdetail_Request 장치별 세부 BIT 요청
{
nLen = LEN_DEVICE_BIT_DETAIL_REQ;
if((g_stTcpClientMy.szRecvData[11] == 0x40u) && (g_stTcpClientMy.szRecvData[12] == 0x00u)) // 장치 확인 0x0040(B/E) → 0x4000(L/E) Device(2Byte) 0x0040(Bit6 High)
{
FuncAntMastBITdetailRes((const u8_t *)g_stTcpClientMy.szRecvData); // 02. AntMastBITdetail_Response 응답 처리
}
}
else if(strCompare((const u8_t*)szCase[2], (const u8_t*)g_stTcpClientMy.szRecvData, (u8_t)LEN_COMPARE) == 1u) // 03. AntMastControl_Request 안테나마스트 설정 및 제어 요청
{
nLen = LEN_ANT_MAST_CONTROL_REQ;
g_cOverCurrFlag = 0u;
g_cMastRcvCmd = g_stTcpClientMy.szRecvData[10]; // Control(1) 0x11: 사용자 입력, 0x10: 연속 상승, 0x01: 연속 하강, 0x00: 중지
if(g_cMastRcvCmd == (u8_t)CMD_MOTOR_USER_INPUT) // 유저 입력값이 있는 경우
{
nLen += (u32_t)4; // 수신길이 증가
g_nSetMastHeight = (u32_t)g_stTcpClientMy.szRecvData[14] << 24; // Little Endian 을 Big Endian로
g_nSetMastHeight += (u32_t)g_stTcpClientMy.szRecvData[13] << 16;
g_nSetMastHeight += (u32_t)g_stTcpClientMy.szRecvData[12] << 8;
g_nSetMastHeight += g_stTcpClientMy.szRecvData[11]; // 목표 높이값 적용
#if DEBUG_CTRL_MODULE
xil_printf("g_nSetMastHeight:%d\r\n", (u32_t)g_nSetMastHeight);
#endif
}
else
{
g_nSetMastHeight = 0;
}
SetMotor(g_cMastRcvCmd); // Motor Up/Down/Stop 구동 제어
FuncAntMastControlRes((const u8_t *)g_stTcpClientMy.szRecvData); // 03. AntMastControl_Response 응답 처리
}
else if(strCompare((const u8_t*)szCase[4], (const u8_t*)g_stTcpClientMy.szRecvData, (u8_t)LEN_COMPARE) == 1u) // 05. DevicePower_Request 장치별 전원차단 요청
{
nLen = LEN_DEVICE_POWER_REQ;
if(g_stTcpClientMy.szRecvData[11] == 0xA0u) // Unit 확인, 0xA0:안테나마스트
{
FuncAntMastPowerRes((const u8_t *)g_stTcpClientMy.szRecvData); // 05. AntMastPower_Response 응답 처리
}
}
else
{
g_stTcpClientMy.nRecvLen = 0; // while loop 빠져나가기 위한 처리
}
if(nLen > 0u)
{
g_stTcpClientMy.nRecvLen -= nLen; // 사용한 길이 제거
(void)memcpy((void*)&g_stTcpClientMy.szRecvData[0], (const void*)(&g_stTcpClientMy.szRecvData[nLen]), (size_t)g_stTcpClientMy.nRecvLen); // 사용한 패킷 제거
}
nLen = 0;
}
(void)memset((void *)g_stTcpClientMy.szRecvData, (s32_t)0, (s32_t)NUM_RECV_BUF); // 남은 패킷이 있다면 제거
g_stTcpClientMy.nRecvLen = 0;
}
}
// 01.AntMastPBIT_Response 응답 처리
static void FuncAntMastPBITRes(const uint8_t *pszData)
{
u32_t i = 0, j;
u8_t szBuf[LEN_DEVICE_PBIT_REQ + 2 + ARR_BUF_MARGIN];
u8_t cData = 0;
(void)memset((void *)szBuf, (s32_t)0, (s32_t)(sizeof(szBuf)));
szBuf[i++] = IDC_CMD_TYPE_DEVICE_PBIT; // Type
szBuf[i++] = 0x35u; // ID
szBuf[i++] = ICD_CMD_UNIT_MP; // Sour
szBuf[i++] = ICD_CMD_UNIT_MAST; // Dest
szBuf[i++] = (u8_t)g_cSn; // SN
g_cSn += (u8_t)1;
szBuf[i++] = ICD_CMD_TM_TCP; // TM
szBuf[i++] = 0x02u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
if(g_cEncoderErrFlag == 1u) // 엔코더 상태
{
szBuf[i++] = 0x0Au; // Function 안테나마스트 확장/수축 0x02, 운용참조 0x08 = 00001010b = 0x0A
szBuf[i++] = 0x05u; // Device 안테나마스트 Bit0: 1, 통신 Bit1: 0, 하부참조 Bit2: 1 = 0x05
}
else
{
szBuf[i++] = 0x00u;
szBuf[i++] = 0x00u;
}
struct pbuf *p = NULL;
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)i, PBUF_POOL);
if(p != NULL)
{
p->payload = szBuf;
p->len = (u16_t)i;
(void)tcp_write((struct tcp_pcb*)g_stTcpClientMy.pcb, (const void*)p->payload, (u16_t)p->len, (u8_t)1);
(void)pbuf_free(p);
}
szBuf[0] = pszData[0];
}
// 02.AntMastBITdetail_Response 응답 처리
static void FuncAntMastBITdetailRes(const uint8_t *pszData)
{
u32_t i = 0, j;
u8_t szBuf[LEN_DEVICE_BIT_DETAIL_REQ + 1 + ARR_BUF_MARGIN];
(void)memset((void *)szBuf, (s32_t)0, (s32_t)(sizeof(szBuf)));
szBuf[i++] = IDC_CMD_TYPE_BIT_DETAIL; // Type
szBuf[i++] = 0x35u; // ID
szBuf[i++] = ICD_CMD_UNIT_MP; // Sour
szBuf[i++] = ICD_CMD_UNIT_MAST; // Dest
szBuf[i++] = (u8_t)g_cSn; // SN
g_cSn += (u8_t)1;
szBuf[i++] = ICD_CMD_TM_TCP; // TM
szBuf[i++] = 0x02u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = pszData[10]; // 0x00(PBIT), 0x40(CBIT)
szBuf[i++] = g_cBitDetail; // BIT Detail Bit 3 : 모터과전류 Bit 2 : 높이값 표시용 엔코더 체크, Bit 1 : 마스트 구동 체크, Bit 0 : 안테나마스트-임무통제기 통신 수신 미발생(0)/발생(1)
struct pbuf *p = NULL;
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)i, PBUF_POOL);
if(p != NULL)
{
p->payload = szBuf;
p->len = (u16_t)i;
(void)tcp_write((struct tcp_pcb*)g_stTcpClientMy.pcb, (const void*)p->payload, (u16_t)p->len, (u8_t)1);
(void)pbuf_free(p);
}
szBuf[0] = pszData[0];
}
// 03.AntMastControl_Response 응답 처리
static void FuncAntMastControlRes(const uint8_t *pszData)
{
u32_t i = 0, j;
u8_t szBuf[LEN_ANT_MAST_CONTROL_REQ + 4 + ARR_BUF_MARGIN];
(void)memset((void *)szBuf, (s32_t)0, (s32_t)(sizeof(szBuf)));
szBuf[i++] = IDC_CMD_TYPE_MAST_CONTROL; // Type
szBuf[i++] = 0x33u; // ID
szBuf[i++] = ICD_CMD_UNIT_MP; // Sour
szBuf[i++] = ICD_CMD_UNIT_MAST; // Dest
szBuf[i++] = (u8_t)g_cSn; // SN
g_cSn += (u8_t)1;
szBuf[i++] = ICD_CMD_TM_TCP; // TM
if(g_cMastRcvCmd != (u8_t)CMD_MOTOR_USER_INPUT) // 유저 입력값이 없는 경우
{
szBuf[i++] = 0x01u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = g_cMastRcvCmd; // Control(1) 0xC0: 사용자 입력, 0x80: 연속 상승, 0x40: 연속 하강, 0x00: 중지
}
else
{
szBuf[i++] = 0x05u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = g_cMastRcvCmd; // Control(1) 0xC0: 사용자 입력, 0x80: 연속 상승, 0x40: 연속 하강, 0x00: 중지
szBuf[i++] = (u8_t)g_nSetMastHeight & 0xFFu; // Little Endian 처리, 설정 높이값 입력
szBuf[i++] = (u8_t)(g_nSetMastHeight >> 8) & 0xFFu;
szBuf[i++] = (u8_t)(g_nSetMastHeight >> 16) & 0xFFu;
szBuf[i++] = (u8_t)(g_nSetMastHeight >> 24) & 0xFFu;
}
struct pbuf *p = NULL;
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)i, PBUF_POOL);
/* MISRA C Dir 4.11 : 송신 버퍼 유효성 검사*/
if(p != NULL)
{
p->payload = szBuf;
p->len = (u16_t)i;
(void)tcp_write((struct tcp_pcb*)g_stTcpClientMy.pcb, (const void*)p->payload, (u16_t)p->len, (u8_t)1);
(void)pbuf_free(p);
}
szBuf[0] = pszData[0];
}
// 05. AntMastPower_Response 응답 처리
static void FuncAntMastPowerRes(const uint8_t *pszData)
{
u32_t i = 0, j;
u8_t szBuf[LEN_DEVICE_POWER_REQ + ARR_BUF_MARGIN];
(void)memset((void *)szBuf, (s32_t)0, (s32_t)(sizeof(szBuf)));
szBuf[i++] = IDC_CMD_TYPE_DEVICE_POWER; // Type
szBuf[i++] = 0x31u; // ID
szBuf[i++] = ICD_CMD_UNIT_MP; // Sour
szBuf[i++] = ICD_CMD_UNIT_MAST; // Dest
szBuf[i++] = (u8_t)g_cSn; // SN
g_cSn += (u8_t)1;
szBuf[i++] = ICD_CMD_TM_TCP; // TM
szBuf[i++] = 0x01u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = pszData[10]; // Control 1Byte
struct pbuf *p = NULL;
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)i, PBUF_POOL);
if(p != NULL)
{
p->payload = (void*)szBuf;
p->len = (u16_t)i;
(void)tcp_write((struct tcp_pcb*)g_stTcpClientMy.pcb, (const void*)p->payload, (u16_t)p->len, (u8_t)1u);
(void)pbuf_free(p);
}
szBuf[0] = pszData[0];
}

21
src/tcpipcomm.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef TCPIP_COMM_H
#define TCPIP_COMM_H
#include "define.h"
#include "tcp_client.h"
static u8_t g_cSn; // 응답패킷 송신 카운터
u8_t szCase[7][3]; // 문자열 비교 배열
static u8_t strCompare(const uint8_t *str1, const uint8_t *str2, uint8_t str2Len); // 문자열 비교(strncmp에서 null 문자 시 종료되는 부분 비활성)
void InitCompareMember(void); // 문자열 비교 초기화
void TcpClientCommProceess(void); // TCP Client 수신 및 송신 처리
// TCP 서버의 Client 응답
static void FuncAntMastPBITRes(const uint8_t *pszData); // 01. AntMastPBIT_Response 응답 처리
static void FuncAntMastBITdetailRes(const uint8_t *pszData); // 02. AntMastBITdetail_Response 응답 처리
static void FuncAntMastControlRes(const uint8_t *pszData); // 03. AntMastControl_Response 응답 처리
static void FuncAntMastPowerRes(const uint8_t *pszData); // 05. AntMastPower_Response 응답 처리
#endif // TCPIP_COMM_H

293
src/udp_client.c Normal file
View File

@ -0,0 +1,293 @@
#include "udp_client.h"
// UDP Server 초기화
void InitUdpServer(void)
{
s8_t err;
ip_addr_t addr;
InitUdpClientMember(); // UDP Client 구조체 초기화
/* Create Client PCB */
g_stUdpCliPcb.pcb = udp_new();
if(g_stUdpCliPcb.pcb != NULL)
{
err = udp_bind(g_stUdpCliPcb.pcb, IP_ADDR_ANY, UDP_MY_PORT);
if(err == (s8_t)ERR_OK)
{
xil_printf("udp server binding ok\n");
udp_recv(g_stUdpCliPcb.pcb, udp_server_receive_callback, NULL);
IP_ADDR4(&addr, UDP_SERVER_IP_ADDR1, UDP_SERVER_IP_ADDR2, UDP_SERVER_IP_ADDR3, UDP_SERVER_IP_ADDR4); // 임무 IP
g_stUdpCliPcb.pcb->remote_ip.addr = addr.addr; // 송신처 정보 확인
g_stUdpCliPcb.pcb->remote_port = 61202; // 51271
}
else
{
#if DEBUG_COVER
xil_printf("udp server binding error\n");
#endif
}
}
}
static void udp_server_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
uint8_t i;
u8_t szBuff[100];
void *Dummy;
struct udp_pcb* pDummyPcb;
ip_addr_t* pDummyAddr;
u16_t DummyPort;
Dummy = arg;
pDummyPcb = upcb;
pDummyAddr = addr;
DummyPort = port;
DummyPort++;
#if TEST_LOG_ON_UDP
xil_printf("udp recv:%s:%d\r\n", ip4addr_ntoa((const ip_addr_t *)addr), port);
#endif
if(p->len < 100u)
{
(void)memcpy((void*)szBuff, (const void*)(p->payload), (size_t)p->len);
if((szBuff[0] == 0x92u) && (szBuff[1] == 0x10u) && (szBuff[2] == 0x40u) && (szBuff[3] == 0x61u)) // 임무처리기 Heart Beat 수신 여부 검사
{
m_cRecvHBFromMP = 1;
g_nBitDetailHBCnt = 0; // 카운터 초기화
g_cBitDetailHBErr = 0; // Heart Beat 수신 On 판정(정상)
g_nTcpDisconnectCnt = 0; // 카운터 초기화, 접속 후 임무처리 S/W의 Heart Beat 미수신 5초 이상 발생 확인용 카운터
g_nTcpDisconnectChk = 1; // 접속 유지, 접속 후 임무처리S/W의 Heart Beat 미 수신이 5초 이상 유지되면 접속해제
}
}
(void)pbuf_free(p); /* Free the p buffer */
}
// UDP Client 구조체 초기화
static void InitUdpClientMember(void)
{
m_cRecvHBFromMP = 1;
g_cBitDetailHBErr = 0;
g_unUdpServerPort = UDP_SERVER_PORT;
g_stUdpCliPcb.nRecvLen = 0;
(void)memset((void*)g_stUdpCliPcb.szRecvData, (s32_t)0, (size_t)(NUM_RECV_BUF * sizeof(u8_t)));
g_stUdpCliPcb.cRecvFlag = FALSE;
}
// UDP 통신 처리
void UdpCommProcess(void)
{
UdpCommPeriod(); // UDP 주기적인 통신 처리
if(g_nBitDetailHBCnt > TIMER_SEC3)
{
g_nBitDetailHBCnt = 0; // 카운터 초기화
g_cBitDetailHBErr = 1; // Heart Beat 수신 오류 판정
}
if(g_nTcpDisconnectCnt > TIMER_SEC10)
{
g_nTcpDisconnectCnt = 0;
g_nTcpDisconnectChk = 0; // 접속 해제, 접속 후 임무처리S/W의 Heart Beat 미 수신이 5초 이상 유지되면 접속해제
if(g_stTcpClientMy.cConnected == TRUE)
{
tcp_client_connection_close(g_stTcpClientMy.pcb);
}
}
}
// UDP 주기적인 통신 처리
static void UdpCommPeriod(void)
{
if(g_nReportCnt > TIMER_MSEC333) // main() - makeTiming()
{
g_nReportCnt = 0u;
if(m_cReportIdx == 0u)
{
m_cReportIdx++;
if(m_cRecvHBFromMP == 1u) // 임무처리기 Heart Beat 수신되면 응답 시작
{
if(g_cMastPeriodSendCmd == TCP_CMD_PERIOD_REPORT_START)
{
FuncAntMastStatusReport(); // 안테나 마스트 상태 보고 송신
}
}
}
else if(m_cReportIdx == 1u)
{
m_cReportIdx++;
if(m_cRecvHBFromMP == 1u) // 임무처리기 Heart Beat 수신되면 응답 시작
{
if(g_cMastPeriodSendCmd == TCP_CMD_PERIOD_REPORT_START)
{
FuncAntMastCBitReport(); // 안테나 마스트 CBIT 보고 송신
}
}
}
else// if(m_cReportIdx == 2u) // 전원 공급 시 상시 전송
{
m_cReportIdx = 0u;
FuncHeartBeatData(); // LAN 연결성 확인 데이터
}
}
}
// 안테나 마스트 상태 보고 송신
static void FuncAntMastStatusReport(void)
{
u32_t i = 0;
u8_t szBuf[LEN_ANT_MAST_STATUS_REPORT + ARR_BUF_MARGIN];
struct pbuf *p = NULL;
(void)memset((void*)szBuf, (s32_t)0, (size_t)(sizeof(szBuf)));
szBuf[i++] = IDC_CMD_TYPE_STATUS_REPORT; // Type
szBuf[i++] = 0x04u; // ID
szBuf[i++] = ICD_CMD_UNIT_MP; // Sour
szBuf[i++] = ICD_CMD_UNIT_MAST; // Dest
szBuf[i++] = (u8_t)g_cSn; // SN
g_cSn += (u8_t)1;
szBuf[i++] = IDC_CMD_TM_UDP; // TM
szBuf[i++] = 0x05u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
if(g_cMastRcvCmd == 0x00u)
{
szBuf[i++] = 0x00u; // 안테나마스트 대기 중
}
else
{
szBuf[i++] = 0x40u; // 안테나마스트 동작 중
}
szBuf[i++] = (u8_t)g_nMastCurrHeight & 0xFFu; // 현재 높이값 입력
szBuf[i++] = (u8_t)(g_nMastCurrHeight >> 8) & 0xFFu; // 현재 높이값 입력
szBuf[i++] = (u8_t)(g_nMastCurrHeight >> 16) & 0xFFu; // 현재 높이값 입력
szBuf[i++] = (u8_t)(g_nMastCurrHeight >> 24) & 0xFFu; // 현재 높이값 입력
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)i, PBUF_POOL);
if(p != NULL)
{
(void)pbuf_take((struct pbuf*)p, (const void*)(u8_t*)szBuf, (u16_t)i);
(void)udp_sendto((struct udp_pcb*)g_stUdpCliPcb.pcb, (struct pbuf*)p, (const ip_addr_t*)&g_stUdpCliPcb.pcb->remote_ip, (u16_t)g_stUdpCliPcb.pcb->remote_port);
(void)pbuf_free(p);
}
else
{
#if DEBUG_COVER
xil_printf("error allocating pbuf to send\r\n");
#endif
}
}
// 안테나 마스트 CBIT 보고 송신
static void FuncAntMastCBitReport(void)
{
u32_t i = 0;
u8_t szBuf[LEN_ANT_MAST_CBIT_REPORT + ARR_BUF_MARGIN];
u8_t cData = 0;
struct pbuf *p = NULL;
(void)memset((void*)szBuf, (s32_t)0, (size_t)(sizeof(szBuf)));
szBuf[i++] = IDC_CMD_TYPE_CBIT_REPORT; // Type
szBuf[i++] = 0x05u; // ID
szBuf[i++] = ICD_CMD_UNIT_MP; // Sour
szBuf[i++] = ICD_CMD_UNIT_MAST; // Dest
szBuf[i++] = (u8_t)g_cSn; // SN
g_cSn += (u8_t)1;
szBuf[i++] = IDC_CMD_TM_UDP; // TM
szBuf[i++] = 0x02u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
if((g_cBitDetailHBErr == 1u) || (g_cEncoderErrFlag == 1u)) // 최우선 조건: 통신 에러 또는 엔코더 에러
{
szBuf[i++] = 0x0Au; // Function 안테나마스트 확장/수축 0x02, 운용참조 0x08 = 00001010b = 0x0A
if(g_cBitDetailHBErr == 1u) // 통신 에러
{
szBuf[i++] = 0x07u; // Device 안테나마스트 Bit0: 1, 통신 Bit1: 1, 하부참조 Bit2: 1 = 0x05
}
else
{
szBuf[i++] = 0x05u; // Device 안테나마스트 Bit0: 1, 통신 Bit1: 0, 하부참조 Bit2: 1 = 0x05
}
}
else if(g_cOverCurrFlag == 1u)
{
szBuf[i++] = 0x05u; // Function 안테나마스트 확장/수축 0x02, 운용참조 0x08 = 00001010b = 0x0A
szBuf[i++] = 0x05u; // Device 안테나마스트 Bit0: 1, 통신 Bit1: 0, 하부참조 Bit2: 1 = 0x05
}
else
{
szBuf[i++] = 0x00u;
szBuf[i++] = 0x00u;
}
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)i, PBUF_POOL);
if(p != NULL)
{
(void)pbuf_take((struct pbuf*)p, (const void*)(u8_t*)szBuf, (u16_t)i);
(void)udp_sendto((struct udp_pcb*)g_stUdpCliPcb.pcb, (struct pbuf*)p, (const ip_addr_t*)&g_stUdpCliPcb.pcb->remote_ip, (u16_t)g_stUdpCliPcb.pcb->remote_port);
(void)pbuf_free(p);
}
else
{
#if DEBUG_COVER
xil_printf("error allocating pbuf to send\r\n");
#endif
}
}
// LAN 연결성 확인 데이터
static void FuncHeartBeatData(void)
{
u32_t i = 0;
u8_t szBuf[LEN_HEART_BEAT_DATA + ARR_BUF_MARGIN];
struct pbuf *p = NULL;
(void)memset((void*)szBuf, (s32_t)0, (size_t)(sizeof(szBuf)));
szBuf[i++] = IDC_CMD_TYPE_HEART_BEAT; // Type
szBuf[i++] = 0x10u; // ID
szBuf[i++] = ICD_CMD_UNIT_MP; // Sour
szBuf[i++] = ICD_CMD_UNIT_MAST; // Dest
szBuf[i++] = (u8_t)g_cSn; // SN
g_cSn += (u8_t)1;
szBuf[i++] = IDC_CMD_TM_UDP; // TM
szBuf[i++] = 0x01u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Length
szBuf[i++] = 0x00u; // Reserved
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)i, PBUF_POOL);
if(p != NULL)
{
(void)pbuf_take((struct pbuf*)p, (const void*)(u8_t*)szBuf, (u16_t)i);
(void)udp_sendto((struct udp_pcb*)g_stUdpCliPcb.pcb, (struct pbuf*)p, (const ip_addr_t*)&g_stUdpCliPcb.pcb->remote_ip, (u16_t)g_stUdpCliPcb.pcb->remote_port);
(void)pbuf_free(p);
}
else
{
#if DEBUG_COVER
xil_printf("error allocating pbuf to send\r\n");
#endif
}
}

46
src/udp_client.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef UDP_CLIENT_H
#define UDP_CLIENT_H
#include "lwipopts.h"
#include "xlwipconfig.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/udp.h"
#include "lwip/inet.h"
#include "xil_printf.h"
#include "platform.h"
#include <sleep.h>
#include "ctrl_module.h"
#include "tcpipcomm.h"
#include "define.h"
struct ClientUdpPcb
{
struct udp_pcb *pcb; // udp_pcb
u8_t szRecvData[NUM_RECV_BUF]; // 수신 버퍼
u32_t nRecvLen; // 수신 버퍼 사이즈
u8_t cRecvFlag; // 수신 플래그
} ;
static struct ClientUdpPcb g_stUdpCliPcb; // UDP서버에 접속하는 클라이언트 처리
u32_t g_nReportCnt; // udp_client에서 사용, static 선언하면 안됨
static u16_t g_unUdpServerPort; // UDP Server Port
static u8_t m_cReportIdx = 0; // Report 2개 교차 송신용
static u8_t m_cRecvHBFromMP = 0; // 임무처리기로부터 Heart Beat 수신 여부
void InitUdpServer(void);
static void udp_server_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
static void InitUdpClientMember(void); // UDP Client 구조체 초기화
void UdpCommProcess(void); // UDP 통신 처리
static void UdpCommPeriod(void); // UDP 주기적인 통신 처리
static void FuncAntMastStatusReport(void); // 안테나 마스트 상태 보고 송신
static void FuncAntMastCBitReport(void); // 안테나 마스트 CBIT 보고 송신
static void FuncHeartBeatData(void); // LAN 연결성 확인 데이터
#endif // UDP_CLIENT_H