Files
allwpilib/hal/lib/Athena/ctre/CtreCanNode.cpp
Omar Zrien cd5765559a Last feature addition for CANTalon java/C++ user-facing API.
- CANJaguar also touched up to report it can't do the new control mode (just like with follower).
- New third optional param for talon c'tor to speed up enable control frame.
- The pulse width routines have been moved to where the script generator puts them.  No actual changes there but should help Peter integrate the latest code generator.

Last feature additions for TalonSRX HAL for FRC2015-FRC-2016 season.

-HAL driver uses control_5 frame if firmware supports it.  This allows teams to see/confirm control settings taking effect before enabling the robot.
  For example selecting the sensor type and going to web-dash to check sensor values now works without having to enable the robot.
-Motion profile HAL routines added.  Tested on Single-Speed Double reduction (with slave Talon too).
-Start moving ctre frame defs into a new common header (better then shoving a bunch of struct defs at top of module).
-New child class in CANTalonSRX for buffering motion profile points.  Not sure it would be best to leave it as is or make another module.  It's trivial now so I thought that was acceptable, (in future it will likely possess compression strategies => no longer trivial).

Change-Id: I803680c1a6669ca3f5157d7875942def6f75b540
2015-12-16 00:02:01 -08:00

165 lines
5.6 KiB
C++

#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include "ctre/CtreCanNode.h"
#include "FRC_NetworkCommunication/CANSessionMux.h"
#include <string.h> // memset
#include <unistd.h> // usleep
static const UINT32 kFullMessageIDMask = 0x1fffffff;
CtreCanNode::CtreCanNode(UINT8 deviceNumber)
{
_deviceNumber = deviceNumber;
}
CtreCanNode::~CtreCanNode()
{
}
void CtreCanNode::RegisterRx(uint32_t arbId)
{
/* no need to do anything, we just use new API to poll last received message */
}
/**
* Schedule a CAN Frame for periodic transmit.
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
* @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
* @param dlc Number of bytes to transmit (0 to 8).
* @param initialFrame Ptr to the frame data to schedule for transmitting. Passing null will result
* in defaulting to zero data value.
*/
void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs, uint32_t dlc, const uint8_t * initialFrame)
{
int32_t status = 0;
if(dlc > 8)
dlc = 8;
txJob_t job = {0};
job.arbId = arbId;
job.periodMs = periodMs;
job.dlc = dlc;
if(initialFrame){
/* caller wants to specify original data */
memcpy(job.toSend, initialFrame, dlc);
}
_txJobs[arbId] = job;
FRC_NetworkCommunication_CANSessionMux_sendMessage( job.arbId,
job.toSend,
job.dlc,
job.periodMs,
&status);
}
/**
* Schedule a CAN Frame for periodic transmit. Assume eight byte DLC and zero value for initial transmission.
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
* @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
*/
void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs)
{
RegisterTx(arbId,periodMs, 8, 0);
}
/**
* Remove a CAN frame Arbid to stop transmission.
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
*/
void CtreCanNode::UnregisterTx(uint32_t arbId)
{
/* set period to zero */
ChangeTxPeriod(arbId, 0);
/* look and remove */
txJobs_t::iterator iter = _txJobs.find(arbId);
if(iter != _txJobs.end()) {
_txJobs.erase(iter);
}
}
timespec diff(const timespec & start, const timespec & end)
{
timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return temp;
}
CTR_Code CtreCanNode::GetRx(uint32_t arbId,uint8_t * dataBytes, uint32_t timeoutMs)
{
CTR_Code retval = CTR_OKAY;
int32_t status = 0;
uint8_t len = 0;
uint32_t timeStamp;
/* cap timeout at 999ms */
if(timeoutMs > 999)
timeoutMs = 999;
FRC_NetworkCommunication_CANSessionMux_receiveMessage(&arbId,kFullMessageIDMask,dataBytes,&len,&timeStamp,&status);
if(status == 0){
/* fresh update */
rxEvent_t & r = _rxRxEvents[arbId]; /* lookup entry or make a default new one with all zeroes */
clock_gettime(2,&r.time); /* fill in time */
memcpy(r.bytes, dataBytes, 8); /* fill in databytes */
}else{
/* did not get the message */
rxRxEvents_t::iterator i = _rxRxEvents.find(arbId);
if(i == _rxRxEvents.end()){
/* we've never gotten this mesage */
retval = CTR_RxTimeout;
/* fill caller's buffer with zeros */
memset(dataBytes,0,8);
}else{
/* we've gotten this message before but not recently */
memcpy(dataBytes,i->second.bytes,8);
/* get the time now */
struct timespec temp;
clock_gettime(2,&temp); /* get now */
/* how long has it been? */
temp = diff(i->second.time,temp); /* temp = now - last */
if(temp.tv_sec > 0){
retval = CTR_RxTimeout;
}else if(temp.tv_nsec > ((int32_t)timeoutMs*1000*1000)){
retval = CTR_RxTimeout;
}else {
/* our last update was recent enough */
}
}
}
return retval;
}
void CtreCanNode::FlushTx(uint32_t arbId)
{
int32_t status = 0;
txJobs_t::iterator iter = _txJobs.find(arbId);
if(iter != _txJobs.end())
FRC_NetworkCommunication_CANSessionMux_sendMessage( iter->second.arbId,
iter->second.toSend,
iter->second.dlc,
iter->second.periodMs,
&status);
}
/**
* Change the transmit period of an already scheduled CAN frame.
* This keeps the frame payload contents the same without caller having to perform
* a read-modify-write.
* @param arbId CAN Frame Arbitration ID. Set BIT31 for 11bit ids, otherwise we use 29bit ids.
* @param periodMs Period to transmit CAN frame. Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
* @return true if scheduled job was found and updated, false if there was no preceding job for the specified arbID.
*/
bool CtreCanNode::ChangeTxPeriod(uint32_t arbId, uint32_t periodMs)
{
int32_t status = 0;
/* lookup the data bytes and period for this message */
txJobs_t::iterator iter = _txJobs.find(arbId);
if(iter != _txJobs.end()) {
/* modify th periodMs */
iter->second.periodMs = periodMs;
/* reinsert into scheduler with the same data bytes, only the period changed. */
FRC_NetworkCommunication_CANSessionMux_sendMessage( iter->second.arbId,
iter->second.toSend,
iter->second.dlc,
iter->second.periodMs,
&status);
return true;
}
return false;
}