blob: 3f1c9310b80b2f85a263e9439f9ef341d7425f9c [file] [log] [blame]
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Kinect.h"
#include "DriverStation.h"
#include "NetworkCommunication/FRCComm.h"
#include "NetworkCommunication/UsageReporting.h"
#include "Skeleton.h"
#include "Synchronized.h"
#include "WPIErrors.h"
#define kHeaderBundleID kFRC_NetworkCommunication_DynamicType_Kinect_Header
#define kSkeletonExtraBundleID kFRC_NetworkCommunication_DynamicType_Kinect_Extra1
#define kSkeletonBundleID kFRC_NetworkCommunication_DynamicType_Kinect_Vertices1
Kinect *Kinect::_instance = NULL;
Kinect::Kinect() :
m_recentPacketNumber(0),
m_numberOfPlayers(0)
{
AddToSingletonList();
m_dataLock = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);
nUsageReporting::report(nUsageReporting::kResourceType_Kinect, 0);
}
Kinect::~Kinect()
{
semTake(m_dataLock, WAIT_FOREVER);
semDelete(m_dataLock);
}
/**
* Get the one and only Kinect object
* @returns pointer to a Kinect
*/
Kinect *Kinect::GetInstance()
{
if (_instance == NULL)
_instance = new Kinect();
return _instance;
}
/**
* Get the number of tracked players on the Kinect
* @return the number of players being actively tracked
*/
int Kinect::GetNumberOfPlayers()
{
UpdateData();
return m_numberOfPlayers;
}
/**
* Get the floor clip plane as defined in the Kinect SDK
* @return The floor clip plane
*/
Kinect::Point4 Kinect::GetFloorClipPlane()
{
UpdateData();
return m_floorClipPlane;
}
/**
* Get the gravity normal from the kinect as defined in the Kinect SDK
* @return The gravity normal (w is ignored)
*/
Kinect::Point4 Kinect::GetGravityNormal()
{
UpdateData();
return m_gravityNormal;
}
/**
* Get the skeleton data
* Returns the detected skeleton data from the kinect as defined in the Kinect SDK
* @param skeletonIndex Which of (potentially 2) skeletons to return. This is ignored in this implementation and
* only a single skeleton is supported for the FRC release default gesture interpretation.
* @return The current version of the skeleton object.
*/
Skeleton Kinect::GetSkeleton(int skeletonIndex)
{
if (skeletonIndex <= 0 || skeletonIndex > kNumSkeletons)
{
wpi_setWPIErrorWithContext(ParameterOutOfRange, "Skeleton index must be 1");
return Skeleton();
}
UpdateData();
return m_skeletons[skeletonIndex-1];
}
/**
* Get the current position of the skeleton
* @param skeletonIndex the skeleton to read from
* @return the current position as defined in the Kinect SDK (w is ignored)
*/
Kinect::Point4 Kinect::GetPosition(int skeletonIndex)
{
if (skeletonIndex <= 0 || skeletonIndex > kNumSkeletons)
{
wpi_setWPIErrorWithContext(ParameterOutOfRange, "Skeleton index must be 1");
return Point4();
}
UpdateData();
return m_position[skeletonIndex-1];
}
/**
* Get the quality of the skeleton.
* Quality masks are defined in the SkeletonQuality enum
* @param skeletonIndex the skeleton to read from
* @return the quality value as defined in the Kinect SDK
*/
UINT32 Kinect::GetQuality(int skeletonIndex)
{
if (skeletonIndex <= 0 || skeletonIndex > kNumSkeletons)
{
wpi_setWPIErrorWithContext(ParameterOutOfRange, "Skeleton index must be 1");
return kClippedRight | kClippedLeft | kClippedTop | kClippedBottom;
}
UpdateData();
return m_quality[skeletonIndex-1];
}
/**
* Get the TrackingState of the skeleton.
* Tracking states are defined in the SkeletonTrackingState enum
* @param skeletonIndex the skeleton to read from
* @return the tracking state value as defined in the Kinect SDK
*/
Kinect::SkeletonTrackingState Kinect::GetTrackingState(int skeletonIndex)
{
if (skeletonIndex <= 0 || skeletonIndex > kNumSkeletons)
{
wpi_setWPIErrorWithContext(ParameterOutOfRange, "Skeleton index must be 1");
return kNotTracked;
}
UpdateData();
return m_trackingState[skeletonIndex-1];
}
/**
* Check for an update of new data from the Driver Station
* This will read the new values and update the data structures in this class.
*/
void Kinect::UpdateData()
{
Synchronized sync(m_dataLock);
UINT32 packetNumber = DriverStation::GetInstance()->GetPacketNumber();
if (m_recentPacketNumber != packetNumber)
{
m_recentPacketNumber = packetNumber;
int retVal = getDynamicControlData(kHeaderBundleID, m_rawHeader, sizeof(m_rawHeader), 5);
if(retVal == 0)
{
m_numberOfPlayers = (int)m_rawHeader[13];
memcpy(&m_floorClipPlane.x, &m_rawHeader[18], 4);
memcpy(&m_floorClipPlane.y, &m_rawHeader[22], 4);
memcpy(&m_floorClipPlane.z, &m_rawHeader[26], 4);
memcpy(&m_floorClipPlane.w, &m_rawHeader[30], 4);
memcpy(&m_gravityNormal.x, &m_rawHeader[34], 4);
memcpy(&m_gravityNormal.y, &m_rawHeader[38], 4);
memcpy(&m_gravityNormal.z, &m_rawHeader[42], 4);
}
retVal = getDynamicControlData(kSkeletonExtraBundleID, m_rawSkeletonExtra, sizeof(m_rawSkeletonExtra), 5);
if(retVal == 0)
{
memcpy(&m_position[0].x, &m_rawSkeletonExtra[22], 4);
memcpy(&m_position[0].y, &m_rawSkeletonExtra[26], 4);
memcpy(&m_position[0].z, &m_rawSkeletonExtra[30], 4);
memcpy(&m_quality[0], &m_rawSkeletonExtra[34], 4);
memcpy(&m_trackingState[0], &m_rawSkeletonExtra[38], 4);
}
retVal = getDynamicControlData(kSkeletonBundleID, m_rawSkeleton, sizeof(m_rawSkeleton), 5);
if(retVal == 0)
{
for(int i=0; i < Skeleton::JointCount; i++)
{
memcpy(&m_skeletons[0].m_joints[i].x, &m_rawSkeleton[i*12+2], 4);
memcpy(&m_skeletons[0].m_joints[i].y, &m_rawSkeleton[i*12+6], 4);
memcpy(&m_skeletons[0].m_joints[i].z, &m_rawSkeleton[i*12+10], 4);
m_skeletons[0].m_joints[i].trackingState = (Skeleton::JointTrackingState)m_rawSkeletonExtra[i+2];
}
}
// TODO: Read skeleton #2
}
}