|
|
//@doc
/******************************************************
** ** @module DPACK.CPP | DataPackager implementation file ** ** Description: ** ** History: ** Created 1/05/98 Matthew L. Coill (mlc) ** ** (c) 1986-1998 Microsoft Corporation. All Rights Reserved. ******************************************************/
#include "DPack.h"
#include "FFDevice.h"
#include "Midi_Obj.hpp"
#include "joyregst.hpp"
#include "SW_Error.hpp"
#include "Hau_midi.hpp"
#include "CritSec.h"
DataPackager* g_pDataPackager = NULL; extern CJoltMidi* g_pJoltMidi;
//
// --- MIDI Command codes 200
//
#define PLAYSOLO_OP_200 0x00
#define DESTROY_OP_200 0x01
#define PLAYSUPER_OP_200 0x02
#define STOP_OP_200 0x03
#define STATUS_OP_200 0x04
#define FORCEX_OP_200 0x06
#define FORCEY_OP_200 0x07
//#define MODIFY_CMD_200 0xF1 -- In Header
//#define EFFECT_CMD_200 0xF2 -- In Header
#define DEVICE_CMD_200 0xF3
#define SHUTDOWN_OP_200 0x01
#define ENABLE_OP_200 0x02
#define DISABLE_OP_200 0x03
#define PAUSE_OP_200 0x04
#define CONTINUE_OP_200 0x05
#define STOPALL_OP_200 0x06
#define KILLMIDI_OP_200 0x07
#define GAIN_SCALE_200 78.74
#define PERCENT_SHIFT 10000
#define PERCENT_TO_DEVICE 158
/************** DataPacket class ******************/ DataPacket::DataPacket() : m_BytesOfData(0), m_AckNackMethod(0), m_AckNackDelay(0), m_AckNackTimeout(0), m_NumberOfRetries(0) { m_pData = m_pFixedData; }
DataPacket::~DataPacket() { if (m_pData != m_pFixedData) { delete[] m_pData; } m_pData = NULL; m_BytesOfData = 0; }
BOOL DataPacket::AllocateBytes(DWORD numBytes) { if (m_pData != m_pFixedData) { delete[] m_pData; } if (numBytes <= 32) { m_pData = m_pFixedData; } else { m_pData = new BYTE[numBytes]; } m_BytesOfData = numBytes; m_AckNackMethod = ACKNACK_NOTHING; m_AckNackDelay = 0; m_AckNackTimeout = 0; m_NumberOfRetries = 0;
return (m_pData != NULL); }
/************** DataPackeger class ******************/ DataPackager::DataPackager() : m_NumDataPackets(0), m_DirectInputVersion(0) { m_pDataPackets = m_pStaticPackets; }
DataPackager::~DataPackager() { if (m_pDataPackets != m_pStaticPackets) { delete[] m_pDataPackets; } m_NumDataPackets = 0; m_pDataPackets = NULL; }
HRESULT DataPackager::Escape(DWORD effectID, LPDIEFFESCAPE pEscape) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::SetGain(DWORD gain) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::SendForceFeedbackCommand(DWORD state) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::GetForceFeedbackState(DIDEVICESTATE* pDeviceState) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::CreateEffect(const InternalEffect& effect, DWORD diFlags) { if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
DataPacket* commandPacket = GetPacket(0); HRESULT hr = effect.FillCreatePacket(*commandPacket); if (FAILED(hr)) { ClearPackets(); } return hr; }
HRESULT DataPackager::ModifyEffect(InternalEffect& currentEffect, InternalEffect& newEffect, DWORD modFlags) { return currentEffect.Modify(newEffect, modFlags); }
HRESULT DataPackager::DestroyEffect(DWORD downloadID) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::StartEffect(DWORD downloadID, DWORD mode, DWORD count) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::StopEffect(DWORD downloadID) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::GetEffectStatus(DWORD downloadID) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::SetMidiChannel(BYTE channel) { ClearPackets(); return SUCCESS; }
HRESULT DataPackager::ForceOut(LONG lForceData, ULONG ulAxisMask) { ClearPackets(); return SUCCESS; }
DataPacket* DataPackager::GetPacket(USHORT packet) const { if ((packet >= 0) && (packet < m_NumDataPackets)) { return (m_pDataPackets + packet); } return NULL; }
BOOL DataPackager::AllocateDataPackets(USHORT numPackets) { // Out with the old
if (m_pDataPackets != m_pStaticPackets) { // Allocated, need to deallocate
delete[] m_pDataPackets; } else { // Static, need to uninitialize
for (int i = 0; i < m_NumDataPackets; i++) { m_pStaticPackets[i].AllocateBytes(0); } }
// In with the new
if (numPackets <= 3) { m_pDataPackets = m_pStaticPackets; } else { m_pDataPackets = new DataPacket[numPackets]; } m_NumDataPackets = numPackets;
return (m_pDataPackets != NULL); }
void DataPackager::ClearPackets() { if (m_pDataPackets != m_pStaticPackets) { // Were allocated (deallocate)
delete[] m_pDataPackets; m_pDataPackets = m_pStaticPackets; } else { // Static, need to uninitialize
for (int i = 0; i < m_NumDataPackets; i++) { m_pStaticPackets[i].AllocateBytes(0); } } m_NumDataPackets = 0; }
/************** DataPackeger100 class ******************/
HRESULT DataPackager100::SetGain(DWORD gain) { if (!AllocateDataPackets(2)) { return SFERR_DRIVER_ERROR; }
// Packet to set index15 (gain) of System Effect
DataPacket* setIndexPacket = GetPacket(0); if (!setIndexPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } setIndexPacket->m_pData[0] = EFFECT_CMD | DEFAULT_MIDI_CHANNEL; setIndexPacket->m_pData[1] = SET_INDEX | (BYTE) (INDEX15 << 2); setIndexPacket->m_pData[2] = SYSTEM_EFFECT_ID; setIndexPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_SETINDEX); setIndexPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
// Packet to set modify data[index] of current effect
DataPacket* modifyParamPacket = GetPacket(1); if (!modifyParamPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; }
modifyParamPacket->m_pData[0] = MODIFY_CMD | DEFAULT_MIDI_CHANNEL; gain /= SCALE_GAIN; gain *= DWORD(MAX_SCALE); modifyParamPacket->m_pData[1] = BYTE(gain & 0x7f); modifyParamPacket->m_pData[2] = (BYTE) ((gain >> 7) & 0x7f); modifyParamPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_MODIFYPARAM); modifyParamPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
return SUCCESS; }
HRESULT DataPackager100::SendForceFeedbackCommand(DWORD state) { if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet to set index15 (gain) of System Effect
DataPacket* commandPacket = GetPacket(0); if (!commandPacket->AllocateBytes(2)) { ClearPackets(); return SFERR_DRIVER_ERROR; } commandPacket->m_pData[0] = SYSTEM_CMD | DEFAULT_MIDI_CHANNEL; switch (state) { case DISFFC_SETACTUATORSON: commandPacket->m_pData[1] = SWDEV_FORCE_ON; break; case DISFFC_SETACTUATORSOFF: commandPacket->m_pData[1] = SWDEV_FORCE_OFF; break; case DISFFC_PAUSE: commandPacket->m_pData[1] = SWDEV_PAUSE; break; case DISFFC_CONTINUE: commandPacket->m_pData[1] = SWDEV_CONTINUE; break; case DISFFC_STOPALL: commandPacket->m_pData[1] = SWDEV_STOP_ALL; break; case DISFFC_RESET: commandPacket->m_pData[1] = SWDEV_SHUTDOWN; break; default: { ClearPackets(); return SFERR_INVALID_PARAM; } } commandPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_SETDEVICESTATE); if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR); commandPacket->m_AckNackDelay = g_pJoltMidi->DelayParamsPtrOf()->dwHWResetDelay; commandPacket->m_AckNackTimeout = ACKNACK_TIMEOUT;
return SUCCESS; }
HRESULT DataPackager100::GetForceFeedbackState(LPDIDEVICESTATE pDeviceState) { return DataPackager::GetForceFeedbackState(pDeviceState); }
HRESULT DataPackager100::DestroyEffect(DWORD downloadID) { ClearPackets();
// Note: Cannot allow actually destroying the SYSTEM Effects - Control panel might call this
if ((downloadID == SYSTEM_FRICTIONCANCEL_ID) || (downloadID == SYSTEM_EFFECT_ID) || (downloadID == SYSTEM_RTCSPRING_ALIAS_ID) || (downloadID == SYSTEM_RTCSPRING_ID)) { ASSUME_NOT_REACHED(); return S_FALSE; // User should have no acces to these
}
{ // Check for valid Effect and destroy it
InternalEffect* pEffect = g_ForceFeedbackDevice.RemoveEffect(downloadID); if (pEffect == NULL) { ASSUME_NOT_REACHED(); return SFERR_INVALID_OBJECT; } delete pEffect; }
// Allocate DestroyEffect packet
if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for destroy effect
DataPacket* destroyPacket = GetPacket(0); if (!destroyPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } destroyPacket->m_pData[0] = EFFECT_CMD | DEFAULT_MIDI_CHANNEL; destroyPacket->m_pData[1] = DESTROY_EFFECT; destroyPacket->m_pData[2] = BYTE(downloadID); destroyPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_DESTROYEFFECT); if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR); destroyPacket->m_AckNackDelay = g_pJoltMidi->DelayParamsPtrOf()->dwDestroyEffectDelay; destroyPacket->m_AckNackTimeout = SHORT_MSG_TIMEOUT;
return SUCCESS; }
HRESULT DataPackager100::StartEffect(DWORD downloadID, DWORD mode, DWORD count) { if (downloadID == SYSTEM_EFFECT_ID) { // start has no meaning for raw force
ClearPackets(); return S_FALSE; }
if (count != 1) { // Don't support PLAY_LOOP for this version
ClearPackets(); return SFERR_NO_SUPPORT; }
if (downloadID == SYSTEM_RTCSPRING_ALIAS_ID) { // Remap RTC Spring ID Alias
downloadID = SYSTEM_RTCSPRING_ID; }
ASSUME(BYTE(downloadID) < MAX_EFFECT_IDS); // Small sanity check
if (g_ForceFeedbackDevice.GetEffect(downloadID) == NULL) { // Check for valid Effect
ClearPackets(); ASSUME_NOT_REACHED(); return SFERR_INVALID_OBJECT; }
if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for play effect
DataPacket* playPacket = GetPacket(0); if (!playPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } playPacket->m_pData[0] = EFFECT_CMD | DEFAULT_MIDI_CHANNEL; playPacket->m_pData[2] = BYTE(downloadID); playPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_PLAYEFFECT); playPacket->m_AckNackTimeout = LONG_MSG_TIMEOUT;
if (mode & DIES_SOLO) { // Is it PLAY_SOLO?
playPacket->m_pData[1] = PLAY_EFFECT_SOLO; // pMidiEffect->SetPlayMode(PLAY_SOLO); // Update the playback mode for this Effect
} else { playPacket->m_pData[1] = PLAY_EFFECT_SUPERIMPOSE; // pMidiEffect->SetPlayMode(PLAY_SUPERIMPOSE); // Update the playback mode for this Effect
}
return SUCCESS; }
HRESULT DataPackager100::StopEffect(DWORD downloadID) { // Special case for putrawforce (Cannot stop - this is up for discussion)
if (downloadID == SYSTEM_EFFECT_ID) { ClearPackets(); return S_FALSE; }
// Remap alias ID properly
if (downloadID == SYSTEM_RTCSPRING_ALIAS_ID) { downloadID = SYSTEM_RTCSPRING_ID; // Jolt returned ID0 for RTC Spring so return send alias ID
}
if (g_ForceFeedbackDevice.GetEffect(downloadID) == NULL) { // Check for valid Effect
ASSUME_NOT_REACHED(); ClearPackets(); return SFERR_INVALID_OBJECT; }
if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for stop effect
DataPacket* stopPacket = GetPacket(0); if (!stopPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } stopPacket->m_pData[0] = EFFECT_CMD | DEFAULT_MIDI_CHANNEL; stopPacket->m_pData[1] = STOP_EFFECT; stopPacket->m_pData[2] = BYTE(downloadID); stopPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_STOPEFFECT); stopPacket->m_AckNackTimeout = SHORT_MSG_TIMEOUT;
return SUCCESS; }
HRESULT DataPackager100::GetEffectStatus(DWORD downloadID) { // Special case RTC Spring ID
if (downloadID == SYSTEM_RTCSPRING_ALIAS_ID) { downloadID = SYSTEM_RTCSPRING_ID; // Jolt returned ID0 for RTC Spring so return send alias ID
}
if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for stop effect
DataPacket* packet = GetPacket(0); if (!packet->AllocateBytes(2)) { ClearPackets(); return SFERR_DRIVER_ERROR; } packet->m_pData[0] = STATUS_CMD | DEFAULT_MIDI_CHANNEL; packet->m_pData[1] = BYTE(downloadID); packet->m_AckNackMethod = ACKNACK_NOTHING; if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR); packet->m_AckNackDelay = g_pJoltMidi->DelayParamsPtrOf()->dwGetEffectStatusDelay;
return SUCCESS; }
HRESULT DataPackager100::SetMidiChannel(BYTE channel) { if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for channel set
DataPacket* packet = GetPacket(0); if (!packet->AllocateBytes(9)) { ClearPackets(); return SFERR_DRIVER_ERROR; }
// SysEx Header
packet->m_pData[0] = SYS_EX_CMD; // SysEX CMD
packet->m_pData[1] = 0; // Escape to Manufacturer ID
packet->m_pData[2] = MS_MANUFACTURER_ID & 0x7f; // Manufacturer High Byte
packet->m_pData[3] = (MS_MANUFACTURER_ID >> 8) & 0x7f; // Manufacturer Low Byte (note shifted 8!)
packet->m_pData[4] = JOLT_PRODUCT_ID; // Product ID
// Midi Assign specific
packet->m_pData[5] = MIDI_ASSIGN; // Opcode, midi assign
packet->m_pData[6] = channel & 0x7F; // 7 bit channel ID
// Midi Footer
packet->m_pData[7] = InternalEffect::ComputeChecksum(*packet, 7); // Checksum
packet->m_pData[8] = MIDI_EOX; // End of SysEX command
packet->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_DEVICEINIT); packet->m_AckNackTimeout = ACKNACK_TIMEOUT;
return SUCCESS; }
HRESULT DataPackager100::ForceOut(LONG forceData, ULONG axisMask) { if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet to set index15 (gain) of System Effect
DataPacket* pPacket = GetPacket(0); if (!pPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } pPacket->m_pData[0] = EFFECT_CMD | DEFAULT_MIDI_CHANNEL; pPacket->m_pData[1] = BYTE(int(forceData) << 2) & 0x7c; switch (axisMask) { case X_AXIS: { pPacket->m_pData[1] |= PUT_FORCE_X; break; } case Y_AXIS: { pPacket->m_pData[1] |= PUT_FORCE_Y; break; } // case X_AXIS | Y_AXIS: { // Never Sent!!!
// pPacket->m_pData[1] |= PUT_FORCE_XY; break;
// }
default: { ClearPackets(); return SFERR_INVALID_PARAM; } } pPacket->m_pData[2] = BYTE(int(forceData) >> 5) & 0x7f;
pPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_SETINDEX); pPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
return SUCCESS; }
/************** DataPackeger200 class ******************/
BYTE DataPackager200::EffectCommandParity(const DataPacket& packet) const { BYTE w = packet.m_pData[0] ^ (packet.m_pData[1] & 0xF0) ^ packet.m_pData[2]; return (w >> 4) ^ (w & 0x0F); }
BYTE DataPackager200::DeviceCommandParity(const DataPacket& packet) const { BYTE w = packet.m_pData[0] ^ (packet.m_pData[1] & 0xF0); return (w >> 4) ^ (w & 0x0F); }
// Gain is parameter 0 from effect 0
HRESULT DataPackager200::SetGain(DWORD gain) { if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
DataPacket* modifyPacket = GetPacket(0); if ((modifyPacket == NULL) || (!modifyPacket->AllocateBytes(6))) { ClearPackets(); return SFERR_DRIVER_ERROR; }
DWORD value = DWORD(double(gain)/GAIN_SCALE_200); modifyPacket->m_pData[0] = MODIFY_CMD_200; modifyPacket->m_pData[1] = 0; // Temporary for checksum calc.
modifyPacket->m_pData[2] = 0; modifyPacket->m_pData[3] = 0; modifyPacket->m_pData[4] = BYTE(value & 0x7F); modifyPacket->m_pData[5] = 0; // Gain is only 0 to 127
// New checksum method just to be annoying
BYTE checksum = modifyPacket->m_pData[0] + modifyPacket->m_pData[4]; checksum = 0 - checksum; checksum &= 0xFF; modifyPacket->m_pData[1] = BYTE(checksum & 0x7F); modifyPacket->m_pData[2] |= BYTE(checksum >> 1) & 0x40;
modifyPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_MODIFYPARAM); modifyPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
return SUCCESS; }
HRESULT DataPackager200::SendForceFeedbackCommand(DWORD state) { if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet to set requested System Command
DataPacket* commandPacket = GetPacket(0); if (!commandPacket->AllocateBytes(2)) { ClearPackets(); return SFERR_DRIVER_ERROR; } commandPacket->m_pData[0] = DEVICE_CMD_200; switch (state) { case DISFFC_SETACTUATORSON: commandPacket->m_pData[1] = ENABLE_OP_200; break; case DISFFC_SETACTUATORSOFF: commandPacket->m_pData[1] = DISABLE_OP_200; break; case DISFFC_PAUSE: commandPacket->m_pData[1] = PAUSE_OP_200; break; case DISFFC_CONTINUE: commandPacket->m_pData[1] = CONTINUE_OP_200; break; case DISFFC_STOPALL: commandPacket->m_pData[1] = STOPALL_OP_200; break; case DISFFC_RESET: commandPacket->m_pData[1] = SHUTDOWN_OP_200; break; default: { ClearPackets(); return SFERR_INVALID_PARAM; } } commandPacket->m_pData[1] = BYTE(commandPacket->m_pData[1] << 4); commandPacket->m_pData[1] |= DeviceCommandParity(*commandPacket) & 0x0F;
commandPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_SETDEVICESTATE); commandPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR); commandPacket->m_AckNackDelay = g_pJoltMidi->DelayParamsPtrOf()->dwHWResetDelay; commandPacket->m_AckNackTimeout = ACKNACK_TIMEOUT;
return SUCCESS; }
HRESULT DataPackager200::GetForceFeedbackState(DIDEVICESTATE* pDeviceState) { return DataPackager::GetForceFeedbackState(pDeviceState); }
HRESULT DataPackager200::CreateEffect(const InternalEffect& effect, DWORD diFlags) { // Figure out the number of packets nessacary
UINT totPackets = effect.GetModifyOnlyNeeded() + 1;
if (!AllocateDataPackets((USHORT)totPackets)) { return SFERR_DRIVER_ERROR; }
DataPacket* createPacket = GetPacket(0); HRESULT hr = effect.FillCreatePacket(*createPacket); if (hr != SUCCESS) { ClearPackets(); return hr; } createPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_DOWNLOADEFFECT); createPacket->m_AckNackDelay = 0; createPacket->m_AckNackTimeout = SHORT_MSG_TIMEOUT; createPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
hr = effect.FillModifyOnlyParms(); // Add the params that can only be modified
if (hr != SUCCESS) { ClearPackets(); }
return hr; }
HRESULT DataPackager200::DestroyEffect(DWORD downloadID) { ClearPackets();
// Note: Cannot allow actually destroying the SYSTEM Effects - Control panel might call this
if ((downloadID == SYSTEM_FRICTIONCANCEL_ID) || (downloadID == SYSTEM_EFFECT_ID) || (downloadID == SYSTEM_RTCSPRING_ALIAS_ID) || (downloadID == ID_RTCSPRING_200)) { ASSUME_NOT_REACHED(); return S_FALSE; // User should have no acces to these
}
{ // Check for valid Effect and destroy it
InternalEffect* pEffect = g_ForceFeedbackDevice.RemoveEffect(downloadID); if (pEffect == NULL) { ASSUME_NOT_REACHED(); return SFERR_INVALID_OBJECT; } delete pEffect; }
// Allocate DestroyEffect packet
if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for destroy effect
DataPacket* destroyPacket = GetPacket(0); if (!destroyPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
destroyPacket->m_pData[0] = EFFECT_CMD_200; destroyPacket->m_pData[1] = BYTE(DESTROY_OP_200 << 4); destroyPacket->m_pData[2] = BYTE(downloadID); destroyPacket->m_pData[1] |= EffectCommandParity(*destroyPacket) & 0x0F; destroyPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_DESTROYEFFECT); destroyPacket->m_AckNackDelay = g_pJoltMidi->DelayParamsPtrOf()->dwDestroyEffectDelay; destroyPacket->m_AckNackTimeout = SHORT_MSG_TIMEOUT; destroyPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
return SUCCESS; }
HRESULT DataPackager200::StartEffect(DWORD downloadID, DWORD mode, DWORD count) { if ((downloadID == SYSTEM_EFFECT_ID) || (downloadID == RAW_FORCE_ALIAS)) { // start has no meaning for raw force
ClearPackets(); return S_FALSE; }
#ifdef _DEBUG
if (downloadID != SYSTEM_RTCSPRING_ALIAS_ID) { // Remap RTC Spring ID Alias
ASSUME(BYTE(downloadID) < MAX_EFFECT_IDS); // Small sanity check
} #endif _DEBUG
InternalEffect* pEffect = g_ForceFeedbackDevice.GetEffect(downloadID); if (pEffect == NULL) { // Check for valid Effect
ClearPackets(); ASSUME_NOT_REACHED(); return SFERR_INVALID_OBJECT; }
if (count == 0) { // I can do this easily
ClearPackets(); return S_OK; }
BOOL truncate = FALSE; if (count == INFINITE) { // Device expects zero for infinite
count = 0; } else if (count > 127) { // Device MAX
count = 127; truncate = TRUE; }
int allocCount = 1; if ((mode & DIES_SOLO) && count != 1) { allocCount = 2; // Need to stopall for SOLO with count
} if (!AllocateDataPackets((USHORT)allocCount)) { return SFERR_DRIVER_ERROR; }
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
if (count != 1) { // Special case, done via modify
BYTE nextPacket = 0; if (mode & DIES_SOLO) { // need to stop all first
DataPacket* stopAllPacket = GetPacket(0); if (!stopAllPacket->AllocateBytes(2)) { ClearPackets(); return SFERR_DRIVER_ERROR; } stopAllPacket->m_pData[0] = DEVICE_CMD_200; stopAllPacket->m_pData[1] = STOPALL_OP_200 << 4; stopAllPacket->m_pData[1] |= DeviceCommandParity(*stopAllPacket) & 0x0F; stopAllPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_SETDEVICESTATE); stopAllPacket->m_AckNackDelay = g_pJoltMidi->DelayParamsPtrOf()->dwHWResetDelay; stopAllPacket->m_AckNackTimeout = ACKNACK_TIMEOUT; stopAllPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
nextPacket = 1; } HRESULT hr = pEffect->FillModifyPacket200(nextPacket, pEffect->GetRepeatIndex(), count); if ((hr == S_OK) && (truncate == TRUE)) { return DI_TRUNCATED; } return hr; }
// Packet for play effect
DataPacket* playPacket = GetPacket(0); if (!playPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } playPacket->m_pData[0] = EFFECT_CMD_200; playPacket->m_pData[2] = BYTE(pEffect->GetDeviceID()); playPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_PLAYEFFECT); playPacket->m_AckNackTimeout = LONG_MSG_TIMEOUT; playPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
if (mode & DIES_SOLO) { // Is it PLAY_SOLO?
playPacket->m_pData[1] = PLAYSOLO_OP_200; } else { playPacket->m_pData[1] = PLAYSUPER_OP_200; } playPacket->m_pData[1] = BYTE(playPacket->m_pData[1] << 4); playPacket->m_pData[1] |= EffectCommandParity(*playPacket) & 0x0F;
return SUCCESS; }
HRESULT DataPackager200::StopEffect(DWORD downloadID) { // Special case for putrawforce (Cannot stop - this is up for discussion)
if ((downloadID == SYSTEM_EFFECT_ID) || (downloadID == RAW_FORCE_ALIAS)) { ClearPackets(); return S_FALSE; }
// Remap alias ID properly
if (downloadID == SYSTEM_RTCSPRING_ALIAS_ID) { downloadID = ID_RTCSPRING_200; // Jolt returned ID0 for RTC Spring so return send alias ID
}
if (g_ForceFeedbackDevice.GetEffect(downloadID) == NULL) { // Check for valid Effect
ASSUME_NOT_REACHED(); ClearPackets(); return SFERR_INVALID_OBJECT; }
if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for stop effect
DataPacket* stopPacket = GetPacket(0); if (!stopPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } stopPacket->m_pData[0] = EFFECT_CMD_200; stopPacket->m_pData[1] = BYTE(STOP_OP_200 << 4); stopPacket->m_pData[2] = BYTE(downloadID); stopPacket->m_pData[1] |= EffectCommandParity(*stopPacket) & 0x0F; stopPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_STOPEFFECT); stopPacket->m_AckNackTimeout = SHORT_MSG_TIMEOUT; stopPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
return SUCCESS; }
HRESULT DataPackager200::GetEffectStatus(DWORD downloadID) { // Special case RTC Spring ID
if (downloadID == SYSTEM_RTCSPRING_ALIAS_ID) { downloadID = ID_RTCSPRING_200; // Jolt returned ID0 for RTC Spring so return send alias ID
}
if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet for status effect command
DataPacket* packet = GetPacket(0); if (!packet->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
packet->m_pData[0] = EFFECT_CMD_200; packet->m_pData[1] = BYTE(STATUS_OP_200 << 4); packet->m_pData[2] = BYTE(downloadID); packet->m_pData[1] |= EffectCommandParity(*packet) & 0x0F; packet->m_AckNackMethod = ACKNACK_BUTTONSTATUS; packet->m_AckNackDelay = g_pJoltMidi->DelayParamsPtrOf()->dwGetEffectStatusDelay; packet->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
return SUCCESS;
}
HRESULT DataPackager200::ForceOut(LONG forceData, ULONG axisMask) { if (!AllocateDataPackets(1)) { return SFERR_DRIVER_ERROR; }
// Packet to set index15 (gain) of System Effect
DataPacket* pPacket = GetPacket(0); if (!pPacket->AllocateBytes(3)) { ClearPackets(); return SFERR_DRIVER_ERROR; } pPacket->m_pData[0] = EFFECT_CMD_200; switch (axisMask) { case X_AXIS: { pPacket->m_pData[1] = BYTE(FORCEX_OP_200 << 4); break; } case Y_AXIS: { pPacket->m_pData[1] = BYTE(FORCEY_OP_200 << 4); break; } default: { ClearPackets(); return SFERR_INVALID_PARAM; } } BYTE calc = BYTE((PERCENT_SHIFT - forceData)/PERCENT_TO_DEVICE); pPacket->m_pData[2] = BYTE(calc & 0x7f); pPacket->m_pData[1] |= EffectCommandParity(*pPacket) & 0x0F;
pPacket->m_AckNackMethod = g_ForceFeedbackDevice.GetAckNackMethod(REGBITS_SETINDEX); pPacket->m_NumberOfRetries = MAX_RETRY_COUNT; // Probably differentiate this
return SUCCESS; }
|