(一)PC系统信息
edda@EDDA-SH-Linux-01:~$ uname -a
Linux EDDA-SH-Linux-01 5.4.19-rt10 #1 SMP PREEMPT_RT Tue Aug 23 13:57:00 CST 2022 x86_64 x86_64 x86_64 GNU/Linux
edda@EDDA-SH-Linux-01:~$ gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
(二)preempt实时包
参考:机械臂官方教程
https://frankaemika.github.io/docs/installation_linux.html#setting-up-the-real-time-kernel
(三)代码
can.cpp
can.hpp
#include <iostream>
#include <thread>
#include "can.hpp"
#include <iso646.h>
extern "C"
{
#include <ECI113.h>
#include <EciDemoCommon.h>
#include <EciCanDemo113.h>
#include <config_usbToCan_ixxat.h>
#include <ctrl_config.h>
#include <OsEci.h>
#include <ECI_pshpack1.h>
#include <string.h>
#include <limits.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
}
// gripPara
ECI_CTRL_HDL dwCtrlHandle = ECI_INVALID_HANDLE;
ECI_RESULT hResult = ECI_OK;
DWORD dwHwIndex = 0;
DWORD dwCtrlIndex = 0;
can_TxPDO gripCmd;
can_RxPDO gripState; // gripState
// int gripState = 0;//gripStatue
bool gripStop = false;
#if 0
int main(int argc, char **argv) //主函数 流程切换控制
{
#if 0
if (argc != 1)
{
std::cout << "Usage: " << argv[0] << " <robot-hostname>" << std::endl;
return -1;
}
std::thread thrd_Grip(ThreadGrip);
thrd_Grip.detach();
#endif
// gripCmd.control_word=6;
ThreadGrip();
return 0;
}
#endif
void *ThreadGrip(void *data);
int main(int argc, char *argv[])
{
struct sched_param param;
pthread_attr_t attr;
pthread_t thread;
int ret;
// 获取核数
int CPU = 0;
int CPU_NUM = sysconf(_SC_NPROCESSORS_CONF);
printf("System has %i processor(s). \n", CPU_NUM);
cpu_set_t mask; // CPU核的集合
CPU_ZERO(&mask);
// set CPU MASK
CPU_SET(CPU, &mask);
/* Lock memory */
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
{
printf("mlockall failed: %m\n");
exit(-2);
}
/* Initialize pthread attributes (default values) */
ret = pthread_attr_init(&attr);
if (ret)
{
printf("init pthread attributes failed\n");
goto out;
}
/* Set a specific stack size */
printf("PTHREAD_STACK_MIN=%d\n", PTHREAD_STACK_MIN); // 16384
ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
if (ret)
{
printf("pthread setstacksize failed\n");
goto out;
}
/* Set scheduler policy and priority of pthread */
ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
if (ret)
{
printf("pthread setschedpolicy failed\n");
goto out;
}
param.sched_priority = 99;
ret = pthread_attr_setschedparam(&attr, ¶m);
if (ret)
{
printf("pthread setschedparam failed\n");
goto out;
}
/* Use scheduling parameters of attr */
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if (ret)
{
printf("pthread setinheritsched failed\n");
goto out;
}
/* Create a pthread with specified attributes */
ret = pthread_create(&thread, &attr, ThreadGrip, NULL);
if (ret)
{
printf("create pthread failed\n");
goto out;
}
#if 1
//设置当前进程的CPU Affinity
if (pthread_setaffinity_np(thread, sizeof(mask), &mask) != 0)
{
printf("warning: could not set CPU affinity, continuing...\n");
}
#endif
/* Join the thread and wait until it is done */
ret = pthread_join(thread, NULL);
if (ret)
{
printf("join pthread failed: %m\n");
}
out:
return ret;
}
void *ThreadGrip(void *data) // 器械控制程序
{
hResult = init_driver_eci(&dwHwIndex, &dwCtrlIndex, &dwCtrlHandle); // init can
if (ECI_OK != hResult)
{
printf("[ERROR] init_driver ERROR!\n");
}
else
{
printf("[Note] init_driver Success!\n");
}
hResult = NMTControl(dwCtrlHandle, NMT_Start_Node, 1); // start node
if (ECI_OK != hResult)
{
printf("[ERROR] NMTControl ERROR!\n");
}
else
{
printf("[Note] NMTControl Success!\n");
}
sleep(1);
/*==========================================================================*/
can_RxPDO can_RxPDO_info;
can_RxPDO_info.state_word = 200; //任意数值
can_RxPDO_info.act_pos = 200;
can_RxPDO_info.act_vec = 200;
can_RxPDO_info.act_torque = 200;
can_RxPDO_info.act_current = 200;
can_RxPDO_info.log_input = 200;
can_RxPDO_info.phy_input = 200;
can_RxPDO_info.state = 200;
int cmdState = 0;
int idx = 0;
int flag = 0;
struct timespec ts_1;
struct timespec ts_2;
struct timespec ts_3;
struct timespec ts_4;
long delta34 = 0;
clock_gettime(CLOCK_MONOTONIC, &ts_1);
clock_gettime(CLOCK_MONOTONIC, &ts_2);
clock_gettime(CLOCK_MONOTONIC, &ts_3);
clock_gettime(CLOCK_MONOTONIC, &ts_4);
// printf("CLOCK_REALTIME 1: %d, %d\n", ts_1.tv_sec, ts_1.tv_nsec);
// printf("CLOCK_REALTIME 2: %d, %d\n", ts_2.tv_sec, ts_2.tv_nsec);
while (!gripStop)
{
// printf("idx=%d\n", idx);
idx++;
int a = receivePDO(dwCtrlHandle, &can_RxPDO_info); //接受PDO
switch (cmdState)
{
case SwitchOnDisabled: // switch on disabled 初始化完成,可以进行CAN通讯(WP)
{
// printf("[SwitchOnDisabled] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
if ((can_RxPDO_info.state_word & 0x0040) == 0x0040) // 0040对应的状态字是0100 0000,SwitchOnDisabled (WP)
{
gripCmd.control_word = 0x0006; // 06对应的含义是从初始化这一步进到下面ReadyToSwitchOn状态的控制字(WP)
cmdState = ReadyToSwitchOn;
}
break;
}
case ReadyToSwitchOn: //该状态等待进入SwitchOn状态,此时电机没有被励磁(WP)
{
// printf("[ReadyToSwitchOn] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[ReadyToSwitchOn] act_pos=%d\n", can_RxPDO_info.act_pos);
gripCmd.mode = 06; //选择运行模式为归零模式(WP)
gripCmd.home_position = 0;
gripCmd.homing_method = 37; //-3 37
gripCmd.current_threshold_of_homing = 100; // max current threshold
gripCmd.homing_speed_for_search = 100;
if ((can_RxPDO_info.state_word & 0x0021) == 0x0021) // 0021对应的状态字是0010 0001,就是ReadyToSwitchOn (WP)
{
gripCmd.control_word = 0x0007; // 07对应的含义是由等待SwitchOn状态进入到StwitchedOn状态的控制字(WP)
cmdState = SwitchedOn;
}
break;
}
case SwitchedOn: //该状态主电已上,输入励磁信号并开始控制电机(WP)
{
// printf("[SwitchedOn] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[SwitchedOn] act_pos=%d\n", can_RxPDO_info.act_pos);
// printf("[SwitchedOn] mode_display=0x%x\n", can_RxPDO_info.mode_display);
if ((can_RxPDO_info.state_word & 0x0023) == 0x0023) // 0023对应的状态字是0010 0011,就是SwitchedOn状态(WP)
{
gripCmd.control_word = 0x000F; //主电上成功后,接下来进入使能状态的控制字就是0F(也就是15)(WP)
cmdState = OperationEnabled;
}
break;
}
case OperationEnabled:
{
// printf("[OperationEnabled] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[OpeartionEnabled] act_pos=%d\n", can_RxPDO_info.act_pos);
if ((can_RxPDO_info.state_word & 0x0027) == 0x0027) // 0027对应的状态字是0010 0111,就是OperationEnabled状态(WP)
{
cmdState = ServoSetHoming;
}
break;
}
case ServoSetHoming:
{
// printf("[ServoSetHoming] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[ServoSetHoming] act_pos=%d\n", can_RxPDO_info.act_pos);
// gripCmd.mode = 06; //选择运行模式为归零模式(WP)
// gripCmd.home_position = 0;
// gripCmd.homing_method = -3; //-3 37
// gripCmd.current_threshold_of_homing = 120;
// gripCmd.homing_speed_for_search = 100;
if (can_RxPDO_info.mode_display == 06)
{
gripCmd.control_word = 0x001F; //控制字运行归零模式 0001 1111 (WP)
cmdState = WaitingHoming;
}
}
case WaitingHoming:
{
// printf("[WaitingHoming] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[WaitingHoming] act_pos=%d\n", can_RxPDO_info.act_pos);
if ((can_RxPDO_info.state_word & 0x9000) == 0x9000) // 00x9000
{
printf(" ********** Arrive Home **********\n");
//usleep(10000);
// cmdState = 10;
cmdState = ServoModeHomingEnable;
}
break;
}
case ServoModeHomingEnable:
{
// printf("[ServoModeHomingEnable] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[ServoModeHomingEnable] act_pos=%d\n", can_RxPDO_info.act_pos);
// if ((can_RxPDO_info.state_word & 0x0014) == 0x0014) // 0024对应的状态字是0001 0100,operation enabled and voltage enabled (WP)
// {
gripCmd.target_pos = can_RxPDO_info.act_pos;
gripCmd.mode = 8; // set csp
gripCmd.interpolation_time = 2; // ms 插补时间
cmdState = ServoModeCycPosition;
idx = 0;
break;
}
case ServoModeCycPosition:
{
// printf("[ServoModeCycPosition] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[INFO START]flag=%d act_vec=%d\n", flag, can_RxPDO_info.act_vec);
printf("[ServoModeCycPosition]can_RxPDO_info.act_pos=%d \n", can_RxPDO_info.act_pos);
printf("[ServoModeCycPosition]gripCmd.target_pos====%d \n", 300*flag);
printf("[ServoModeCycPosition]delta==============%d \n", 300*flag-can_RxPDO_info.act_pos);
// gripCmd.target_vec = 1000;
// printf("[INFO START]flag=%d act_pos=%d\n", flag, can_RxPDO_info.act_pos);
#if 1
if (flag < 1000)
{
gripCmd.target_pos +=300;
}
// else if (flag >= 4000 && flag < 8000)
// {
// gripCmd.target_pos -= 100;
//}
else
{
cmdState = 10;
}
#endif
// printf("[INFO END]flag=%d act_vec=%d\n", flag, can_RxPDO_info.act_vec);
// printf("[INFO END]flag=%d act_pos=%d\n", flag, can_RxPDO_info.act_pos);
flag = flag + 1;
break;
}
case 10:
{
// printf("[10] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[10] act_pos=%d\n", can_RxPDO_info.act_pos);
gripStop = 1;
break;
}
case 20:
{
// printf("[20] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[20] act_pos=%d\n", can_RxPDO_info.act_pos);
cmdState = 30;
}
case 30:
{
// printf("[30] can_RxPDO_info.state_word=0x%x\n", can_RxPDO_info.state_word);
// printf("[30] act_pos=%d\n", can_RxPDO_info.act_pos);
gripStop = 1;
break;
}
default:
break;
} // switch
hResult = sendPDO(dwCtrlHandle, gripCmd, &ts_1, &ts_2, &ts_3, &ts_4, &delta34); //发送PDO
// usleep(2000);
} // for-----while
sleep(1);
hResult = release_driver_eci(&dwHwIndex, &dwCtrlIndex, &dwCtrlHandle); // stop can
can.hpp
// Copyright (c) 2017 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE
#pragma once
#include <array>
#include <iostream>
extern "C"
{
#include <ECI113.h>
#include <EciDemoCommon.h>
#include <EciCanDemo113.h>
#include <config_usbToCan_ixxat.h>
#include <ctrl_config.h>
#include <OsEci.h>
#include <ECI_pshpack1.h>
#include <string.h>
}
#define USEC_PER_SEC 1000000
#define NSEC_PER_SEC 1000000000
namespace
{
// can
#define SwitchOnDisabled 0x00
#define ReadyToSwitchOn 0x06
#define SwitchedOn 0x07
#define OperationEnabled 0x0F
#define ServoCmdDisable 0x09 // 0x07
#define ServoSetHoming 0x16 //回零模式
#define ServoModeHomingEnable 0x26
#define ServoModeHoming 0x06 //回零模式
#define ServoModeCycPosition 0x08 // 周期位置模式
#define ServoModeCycTorque 0x0A //周期力矩模式
#define WaitingHoming 0x1000 //等待模式
#define omegaL_gripDeg_close -0.012
#define omegaL_gripDeg_open -28.4518
#define omegaR_gripDeg_close 0.012
#define omegaR_gripDeg_open 28.4518
#define HomingModeNegative -3 //正向回零
#define HomingModeNegativeToPositive -1 //正向回零再反转
#define HomingModePositive -4 //反向回零
#define HomingModePositiveToNegative -2 //负向回零再正转
#define NMT_Start_Node 0x01
#define NMT_Stop_Node 0x02
#define NMT_Enter_PreOperational 0x80
#define NMT_Reset_Node 0x81
#define NMT_Reset_Comunication 0x82
typedef struct CAN_TxPDO
{
uint16_t control_word;
int32_t target_pos;
int32_t target_vec;
int32_t home_position;
int16_t target_torque;
int8_t homing_method;
int8_t mode;
int8_t state;
int16_t current_threshold_of_homing;
int32_t homing_speed_for_search;
uint8_t interpolation_time;
} can_TxPDO;
typedef struct CAN_RxPDO
{
uint16_t state_word;
int8_t mode_display;
int32_t act_pos;
int32_t act_vec;
int16_t act_torque;
int16_t act_current;
uint8_t log_input;
uint8_t phy_input;
int8_t state;
} can_RxPDO;
// can
static long cycs = 0;
static inline void tsnorm(struct timespec *ts)
{
while (ts->tv_nsec >= NSEC_PER_SEC)
{
ts->tv_nsec -= NSEC_PER_SEC;
ts->tv_sec++;
}
}
ECI_RESULT NMTControl(ECI_CTRL_HDL dwCtrlHandle, BYTE NMT_CMD, BYTE Node_Id)
{
ECI_RESULT hResult = ECI_OK;
ECI_CTRL_MESSAGE stcCtrlMsg = {0};
//*** Prepare CAN Message to send
stcCtrlMsg.wCtrlClass = ECI_CTRL_CAN;
stcCtrlMsg.u.sCanMessage.dwVer = ECI_STRUCT_VERSION_V0;
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x000;
stcCtrlMsg.u.sCanMessage.u.V0.uMsgInfo.Bits.dlc = 2;
stcCtrlMsg.u.sCanMessage.u.V0.abData[0] = NMT_CMD;
stcCtrlMsg.u.sCanMessage.u.V0.abData[1] = Node_Id;
OS_Sleep(1);
//*** Send one message
hResult = ECI113_CtrlSend(dwCtrlHandle, &stcCtrlMsg, ECIDEMO_TX_TIMEOUT);
OS_Sleep(10);
/***************************************************/
if (ECI_OK != hResult)
{
OS_Printf("Error while sending CAN Messages\n");
ECIDEMO_CHECKERROR(ECI113_CtrlSend);
}
return hResult;
}
int receivePDO(ECI_CTRL_HDL dwCtrlHandle, can_RxPDO *can_RxPDO_info)
{
// printf("file=%s func=%s line=%d\n", __FILE__, __FUNCTION__, __LINE__);
#if 0
can_RxPDO_info->state_word = 0;
can_RxPDO_info->act_pos = 0;
can_RxPDO_info->act_vec = 0;
can_RxPDO_info->act_torque = 0;
can_RxPDO_info->act_current = 0;
can_RxPDO_info->log_input = 0;
can_RxPDO_info->phy_input = 0;
can_RxPDO_info->state = 0;
#endif
ECI_CTRL_MESSAGE astcCtrlMsg[20] = {{0}};
DWORD dwCount = _countof(astcCtrlMsg);
DWORD dwMsgIndex = 0;
ECI_RESULT hResult = ECI_OK;
//*** Try to read some message
hResult = ECI113_CtrlReceive(dwCtrlHandle, &dwCount, astcCtrlMsg, ECIDEMO_RX_TIMEOUT);
if (ECI_OK != hResult)
{
printf("[reseive_PDO_ERROR]\n");
ECIDEMO_CHECKERROR(ECI113_CtrlReceive);
printf("\n");
can_RxPDO_info->state = 1;
return 0;
}
while ((ECI_OK == hResult) && (dwCount > dwMsgIndex))
{
ECI_CTRL_MESSAGE *pstcCtrlMsg = &astcCtrlMsg[dwMsgIndex];
DWORD b1 = pstcCtrlMsg->u.sCanMessage.u.V0.dwMsgId;
uint8_t *abData = pstcCtrlMsg->u.sCanMessage.u.V0.abData;
// printf("[INFO]dwMsgIndex=%d COBID=0x%x\n",dwMsgIndex, b1);
// EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
// OS_Printf("\n");
// EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
// OS_Printf("\n");
int nodeID = 0x01;
if (b1 == 0x180 + nodeID)
{
memcpy(&can_RxPDO_info->state_word, &abData[0], 2);
memcpy(&can_RxPDO_info->mode_display, &abData[2], 4);
// EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
// OS_Printf("\n");
}
else if (b1 == 0x280 + nodeID)
{
memcpy(&can_RxPDO_info->state_word, &abData[0], 2);
memcpy(&can_RxPDO_info->act_pos, &abData[2], 4);
// EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
// OS_Printf("\n");
// printf("act_pos=%d\n",can_RxPDO_info->act_pos);
}
else if (b1 == 0x380 + nodeID)
{
memcpy(&can_RxPDO_info->state_word, &abData[0], 2);
memcpy(&can_RxPDO_info->act_vec, &abData[2], 4);
// EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
// OS_Printf("\n");
}
else if (b1 == 0x480 + nodeID)
{
memcpy(&can_RxPDO_info->state_word, &abData[0], 2);
memcpy(&can_RxPDO_info->act_torque, &abData[2], 2);
memcpy(&can_RxPDO_info->act_current, &abData[4], 2); //
// EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
// OS_Printf("\n");
// printf("state_word=%d act_torque=%d act_current=%d \n",can_RxPDO_info->state_word,can_RxPDO_info->act_torque,can_RxPDO_info->act_current);
}
else if ((b1 != 0x180 + nodeID) && (b1 != 0x280 + nodeID) && (b1 != 0x380 + nodeID) && (b1 != 0x480 + nodeID))
{
printf("[reseive_PDO_ERROR]: receiveMessage failed!");
EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
OS_Printf("\n");
can_RxPDO_info->state = 2;
}
//*** Proceed with next message
dwMsgIndex++;
} // end while
//*** Reset Error code and proceed with transmission
hResult = ECI_OK;
return 0;
} //主函数
HRESULT sendPDO(ECI_CTRL_HDL dwCtrlHandle, can_TxPDO canTxPDO, struct timespec *ts_1, struct timespec *ts_2, struct timespec *ts_3, struct timespec *ts_4, long *delta34)
{
// printf("file=%s func=%s line=%d\n", __FILE__, __FUNCTION__, __LINE__);
ECI_RESULT hResult = ECI_OK;
/***********************************************************************/
//*** Send some CAN Messages
ECI_CTRL_MESSAGE stcCtrlMsg = {0};
DWORD dwTxMsgCount = 5; // ECIDEMO_TX_MSGCOUNT_CAN;
DWORD dwIndex = 0;
//*** Send Loop
for (dwIndex = 0; dwIndex < dwTxMsgCount; dwIndex++)
{
//*** Prepare CAN Message to send
stcCtrlMsg.wCtrlClass = ECI_CTRL_CAN;
stcCtrlMsg.u.sCanMessage.dwVer = ECI_STRUCT_VERSION_V0;
stcCtrlMsg.u.sCanMessage.u.V0.uMsgInfo.Bits.dlc = 8;
uint8_t *abData = stcCtrlMsg.u.sCanMessage.u.V0.abData;
// OS_Sleep(200);
int nodeID = 0x01;
if (dwIndex == 0)
{
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x200 + nodeID;
memcpy(&abData[0], &(canTxPDO.control_word), 2);
memcpy(&abData[2], &(canTxPDO.mode), 1);
memcpy(&abData[3], &(canTxPDO.homing_method), 1);
// mempcp(&abData[4],&(canTxPDO.home_position),4);
}
if (dwIndex == 1)
{
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x300 + nodeID;
memcpy(&(abData[0]), &(canTxPDO.control_word), 2);
memcpy(&(abData[2]), &(canTxPDO.target_pos), 4);
memcpy(&(abData[6]), &(canTxPDO.current_threshold_of_homing), 2);
}
if (dwIndex == 2)
{
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x400 + nodeID;
memcpy(&(abData[0]), &(canTxPDO.control_word), 2);
memcpy(&(abData[2]), &(canTxPDO.target_vec), 4);
memcpy(&(abData[6]), &(canTxPDO.interpolation_time), 1);
}
if (dwIndex == 3)
{
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x500 + nodeID;
memcpy(&(abData[0]), &(canTxPDO.control_word), 2);
memcpy(&(abData[2]), &(canTxPDO.target_torque), 2);
memcpy(&(abData[4]), &(canTxPDO.homing_speed_for_search), 4);
}
if (dwIndex == 4)
{
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x080;
stcCtrlMsg.u.sCanMessage.u.V0.uMsgInfo.Bits.dlc = 0;
//plan A
#if 1
long time = 2000000; // 5000000ns=5ms
long delta_nsec, delta_sec;
long remain_ns = 0;
/* Get current time */
clock_gettime(CLOCK_MONOTONIC, ts_2);
delta_sec = ts_2->tv_sec - ts_1->tv_sec;
delta_nsec = delta_sec * 1000000000 + ts_2->tv_nsec - ts_1->tv_nsec; //+ *delta34;
remain_ns = time - delta_nsec > 10000 ? time - delta_nsec : 10000;
//printf("used_ns=%lu remain_ns=%lu\n", delta_nsec, remain_ns);
ts_2->tv_nsec += remain_ns;
tsnorm(ts_2);
ts_1->tv_sec = ts_2->tv_sec;
ts_1->tv_nsec = ts_2->tv_nsec;
int ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts_2, NULL);
hResult = ECI113_CtrlSend(dwCtrlHandle, &stcCtrlMsg, ECIDEMO_TX_TIMEOUT);
#endif
//plan B
#if 0
ts_2->tv_nsec += 1950000;
tsnorm(ts_2);
int ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts_2, NULL);
hResult = ECI113_CtrlSend(dwCtrlHandle, &stcCtrlMsg, ECIDEMO_TX_TIMEOUT);
#endif
break;
} // if (dwIndex == 4)
//*** Wait some time to ensure bus idle
// OS_Sleep(1);
//*** Send one message
hResult = ECI113_CtrlSend(dwCtrlHandle, &stcCtrlMsg, ECIDEMO_TX_TIMEOUT);
if (ECI_OK != hResult)
{
printf("[PDOSendERROR]: /n");
ECIDEMO_CHECKERROR(ECI113_CtrlSend);
printf("/n");
}
} // end for for (dwIndex = 0; dwIndex < dwTxMsgCount; dwIndex++)
return hResult;
}
DWORD ReadSDO(ECI_CTRL_HDL dwCtrlHandle, WORD index, BYTE Subindex, BYTE dCount)
{
ECI_RESULT hResult = ECI_OK;
ECI_CTRL_MESSAGE stcCtrlMsg = {0};
DWORD SDO_info;
stcCtrlMsg.wCtrlClass = ECI_CTRL_CAN;
stcCtrlMsg.u.sCanMessage.dwVer = ECI_STRUCT_VERSION_V0;
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x601;
stcCtrlMsg.u.sCanMessage.u.V0.uMsgInfo.Bits.dlc = 8;
uint8_t *abData = stcCtrlMsg.u.sCanMessage.u.V0.abData;
abData[0] = 0x40;
memcpy(&abData[1], &(index), 2);
memcpy(&abData[3], &(Subindex), 1);
abData[4] = 0;
abData[5] = 0;
abData[6] = 0;
abData[7] = 0;
hResult = ECI113_CtrlSend(dwCtrlHandle, &stcCtrlMsg, ECIDEMO_TX_TIMEOUT);
if (ECI_OK != hResult)
{
printf("[PDOSendERROR]: \n");
ECIDEMO_CHECKERROR(ECI113_CtrlSend);
printf("/n");
return 0;
}
OS_Sleep(5);
ECI_CTRL_MESSAGE astcCtrlMsg[20] = {{0}};
DWORD dwCount = _countof(astcCtrlMsg);
hResult = ECI113_CtrlReceive(dwCtrlHandle, &dwCount, astcCtrlMsg, ECIDEMO_RX_TIMEOUT);
if (ECI_OK != hResult)
{
printf("[PDOSendERROR]: \n");
ECIDEMO_CHECKERROR(ECI113_CtrlReceive);
printf("/n");
return 0;
}
else
{
ECI_CTRL_MESSAGE *pstcCtrlMsg = &astcCtrlMsg[0];
DWORD cobID = pstcCtrlMsg->u.sCanMessage.u.V0.dwMsgId;
uint8_t *SDOData = pstcCtrlMsg->u.sCanMessage.u.V0.abData;
// EciPrintCtrlMessage(&astcCtrlMsg[dwMsgIndex]);
// OS_Printf("\n");
if (cobID == 0x581)
{
memcpy(&SDO_info, &abData[4], 4);
return SDO_info;
}
}
return SDO_info;
}
ECI_RESULT WriteSDO(ECI_CTRL_HDL dwCtrlHandle, BYTE index, BYTE Subindex, BYTE length, DWORD data)
{
ECI_RESULT hResult = ECI_OK;
ECI_CTRL_MESSAGE stcCtrlMsg = {0};
stcCtrlMsg.wCtrlClass = ECI_CTRL_CAN;
stcCtrlMsg.u.sCanMessage.dwVer = ECI_STRUCT_VERSION_V0;
stcCtrlMsg.u.sCanMessage.u.V0.dwMsgId = 0x601;
stcCtrlMsg.u.sCanMessage.u.V0.uMsgInfo.Bits.dlc = 8;
uint8_t *abData = stcCtrlMsg.u.sCanMessage.u.V0.abData;
abData[0] = length;
memcpy(&abData[1], &(index), 2);
memcpy(&abData[3], &(Subindex), 1);
if (length == 0x2F)
{
memcpy(&abData[4], &(data), 1);
}
if (length == 0x2B)
{
memcpy(&abData[4], &(data), 2);
}
if (length == 0x27)
{
memcpy(&abData[4], &(data), 3);
}
if (length == 0x23)
{
memcpy(&abData[4], &(data), 4);
}
hResult = ECI113_CtrlSend(dwCtrlHandle, &stcCtrlMsg, ECIDEMO_TX_TIMEOUT);
if (ECI_OK != hResult)
{
printf("[PDOSendERROR]:\n");
ECIDEMO_CHECKERROR(ECI113_CtrlSend);
printf("/n");
return 0;
}
return 0;
}
} // namespace name