Absolute Encoder hexadecimal input - c++

Question: How do I receive input from a absolute encoder that makes it output in hexadecimal/grey code into a Arduino? do I use a digitalRead or analogRead command? I could not find example code/projects with a absolute encoder online.
Overall Objective: I want to use a absolute encoder as a knob for a project. The idea is that the encoder will output its position as a state to be used in a case statement. I.e:
case1: analogRead(absEncdr == 00)
arduino enters idle routine
case2: analogRead(absEncdr == 11)
arduino enters button routine
etc
details: Abs encoder type: 25LB22-G
encoder datasheet is here.
I'm using the hexidecimal/ grey code 4-Bit Binary Code Hexadecimal-16 Position encoder version
Basically, I'm not sure how to read in this abs encoder into my Arduino.

To read that you will need four digital pins. You can read the four pins and bit-shift those values into one byte that you can compare to the table in the data-sheet.
byte position = (digitalRead(pin8) << 3) | (digitalRead(pin4) << 2) | (digitalRead(pin2) << 1) | digitalRead(pin1);
Assuming that the pins are named as they are in that truth table in the datasheet.
We are using the OR operator | to put them together into the same byte.

Related

Using HidD_GetInputReport(..) to retrive XBOX ONEs button states

I am trying to talk to the XBOX ONE Controller via the Microsoft HID API without using XINPUT. I'm currently able to control all the rumble motors (including the force feedback triggers) by sending the packet using HidD_SetOutputReport(HANDLE, VOID*, ULONG). But I'm stuck reading the button values using HidD_GetInputReport(HANDLE, VOID*, ULONG) or ReadFile() / ReadFileEx() with and without the HANDLE being created with FILE_FLAG_OVERLAPPED and using OVERLAPPED and Windows Events.
I have already reverse engineered the USB URB protocol with the help of the following article https://github.com/quantus/xbox-one-controller-protocol. The main goal is to overcome the XINPUT overhead and writing a flexible framework so that I can integrate other gamepads as well.
That is what I accomplished:
I have connected the gamepad via USB with my computer (So that I can read all the USB Packages sent and received from the device)
I have found the controller’s path using SetupDiGetClassDevs(...), SetupDiEnumDeviceInfo(...), SetupDiEnumDeviceInterfaces(...) and SetupDiGetDeviceInterfaceDetail(...)
I have created a handle to the device using HANDLE gamePad = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL)
Using HidP_GetCaps(HANDLE, HIDP_CAPS*) doesn’t seem to return valid data since it reports a OutputReportByteLength of 0 but I am able to send Output reports of size 5 (Turn ON) and 9 (Set rumble motors)
All in and outcoming data (At least buttons and Rumble motors) seem to follow the following pattern
byte 0: Package type
byte 1: was always 0x00
byte 2: Package number (always incrementing every package)
byte 3: Size of following data
byte 4+: <Data>
With that information i was able to let the motors and triggers rumble as I desire
For example: Two of my output rumble packets look like this (Using the pulse length to dirty turn on and off the motors):
This turns on and of all motors with the rumble motors speed at 0xFF and the triggers at speed 0xF0. This is how I did it:
struct RumbleContinous{
BYTE mode;
BYTE mask; // Motor Mask 0b 0 0 0 0 LT RT L R
BYTE lTForce;
BYTE rTForce;
BYTE lForce;
BYTE rForce;
BYTE pulseLength;
BYTE offTime;
BYTE terminator; // Terminator / Dummy / ?? (XINPUT sends that as 0xEB!) / Changing seems to not make any changes
};
RumbleContinous rc = {0x00, 0x0F, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF 0x00, 0xEB};
HidD_SetOutputReport(gamePad, (PVOID)&rc, sizeof(RumbleContinous ));
Now to my problem
Looking at the input packages from the controller it looks like you need to create a buffer of size 0x0E = 14, ZeroMemory it (or just write the first byte to 0 like MSDN is suggesting) and just call HidD_GetInputReport(HANDLE, buffer, 14)
So what I did was calling HidD_FlushQueue() to make sure the next package is the input package. Then I insert a little delay so that I am able to change some controller values. After that I tried reading into a BYTE array with HidD_GetInputReport(HANDLE, cmd_in, 14) but the function always failed with GetLastError() == 0x00000057 // ERROR_INVALID_PARAMETER
Since HID is able to filter packages it may be required to allocate a buffer one byte larger than expected and pass the required report id to the buffer at location 0. This is what I did:
BYTE cmd_in[15];
ZeroMemory(cmd_in, 15);
cmd_in[0] = 0x20;
HidD_GetInputReport(gamePad, cmd_in, 15);
Still no success. Since the HidP_GetCaps(...) function reported an input report of 16 (But I don't trust this since it already fooled me with output report size of 0) I tried sweeping over many buffer sizes:
BYTE cmd_in[30];
for (UINT bs = 0; bs < 30; bs++) {
ZeroMemory(cmd_in, 30);
HidD_FlushQueue(gamePad); // Flushing works
Sleep(500);
if (HidD_GetInputReport(gamePad, cmd_in, bs)) {
// Output result (ommited)
}
else {
// Print error (ommited)
}
}
and
BYTE cmd_in[30];
for (UINT bs = 0; bs < 30; bs++) {
ZeroMemory(cmd_in, 30);
cmd_in[0] = 0x20;
HidD_FlushQueue(gamePad); // Flushing works
Sleep(500);
if (HidD_GetInputReport(gamePad, cmd_in, bs)) {
// Output result (ommited)
}
else {
// Print error (ommited)
}
}
Still no success. According to the special required output format and the wrong HidP_GetCaps(...) readings i suspect that the XBOX ONE Gamepad Driver requires a special header already beeing in the input buffer (As far as I know HidD_GetInputReport(...) just calls the User / Kernel Mode Driver call back; So the driver is free to perform checks and reject all data being send to it)
Maybe anyone out there does know how to call HidD_GetInputReport(...) for the XBOX One controller
I know that it is possible to retrieve that input data since the SimpleHIDWrite is able to see the button states. Even through the format is totally different (The two triggers for example are combined in one byte. In the USB Packed each trigger has its own byte):
I should also mention that the HIDWrite sees the data without the press of any button! Looking at the log from the SimpleHIDWrite it looked like it is reading RD from 00 15 bytes of data, having a 16-byte array and element 0 at 00 (Didn't work in my application). Or does it just dump all data coming in. If yes how is this possible? That would be an option for me too!
I looked at what XINPUT is doing when executing the following code:
XINPUT_STATE s;
XInputGetState(0, &s);
It turned out that XINPUT is doing the same stuff I did until it comes to reading the data from the controler. Insteal of HidD_GetInputReport(...) XINPUT is calling DeviceIoControl(...). So what I did was a fast google serch "DeviceIoControl xbox" and tada here it is without the need to to figure out the memory layout on my own: Getting xbox controller input without xinput
Edit: Using DeviceIoControl(...) works even if the gamepad is connected via bluetooth while HidD_SetOutputReport(...) does not work when the gamepad is connected via bluetooth. I rember reading something that DeviceIoControl(...) via bluetooth requires an addition parameter to be present in the output buffer. But I'm currently trying to figure out a way to controle the rumble motors via DeviceIoControl(...). If you have any sugestions feel free to comment! The article in the link above only activates the two rumble motors but not the triggers!
Edit 2: I tried sweeping over DeviceIoControl(HANDLE, j, CHAR*, i, NULL, 0, DWORD*, NULL) from j 0x0 to 0xFFFFFFFF and i 0x1 to 0x3F. Well it worked... at first... but after a few values of j I got a Blue-Screen: WDF_Violation (At least I know how to crash a computer ;) )

Shift Register 74HC595 Output Current

I'm testing/debugging a C++ program that uses the 74HC595 shift register (Arduino Teensy3.2 # 3.3V).
I want to connect the 8 outputs of the SR back to 8 input pins on the Arduino board.
My question is: would I need resistors between the output of the shift register and the Arduino input? How to know the current flowing from the SR output?
I did have a look at the datasheet but that just confused me more:
https://www.taydaelectronics.com/datasheets/A-251.pdf
CODE TO SET THE REGISTERS:
void ShiftRegisterOut(uint8_t bitOrder, uint8_t val)
{
for (uint8_t i = 0; i < 8; i++)
{
if (bitOrder == LSBFIRST)
digitalWrite(pinData, !!(val & (1 << i)));
else
digitalWrite(pinData, !!(val & (1 << (7 - i))));
digitalWrite(pinClock, HIGH);
digitalWrite(pinClock, LOW);
}
}
According to the datasheet you linked and the datasheet for uC on the Teensy you should not need resistors between the uC to limit current:
74HC595 maximum output current +/-20mA # 6V
MK20DX256VLH7 maximum input current +/- 25mA
But if you supply the 74HC595 with > 6V you might exceed the maximum input voltage of 5.5V of the MK20DX256VLH7.
We need to differentiate between "µC port is input" and "µC port is output", and how the supply voltages differ.
TL;DR: You should strive to use the same supply voltage on both, and to make sure that the µC never sets the connected port pins as output. This is the first case described, and you will need no resistor.
µC port is input
Supply voltage of 74HC595 is lower than or equal to that of the µC
In this case the input impedance of the µC port is so high that no significant DC current flows.
You don't need any resistor, it will only make the edges slower.
Supply voltage of 74HC595 is higher than that of the µC
If the voltage output by the pins of the 74HC595 makes the clamp diodes of the µC conduct, the resulting current can be too high, depending on too many electrical characteristics to mention here. The data sheet of the 74HC595 states that each output can deliver at least 35mA because this is the allowed maximum output current. This is clearly more then the allowed 25mA of the µC.
There is another limit: the 74HC595 must not provide more than 70mA in total.
So you need a resistor per line. For optimum speed of the edges make it as low as possible.
In example, if you have 6V supply at the 74HC595, you will need at least (6V - 3.3V) / (70mA / 8) = 308Ohm. To be safe I'd use 620Ohm.
µC port is output
In this case the output could drive against each other. You need a resistor for each line. The higher of both supply voltages needs to be taken into account.
The µC has the limit for the sum of all outputs, too: it must not provide more than 100mA in total. But this is higher than that of the 74HC595 so we need to take that.
Supply voltage of 74HC595 is lower than or equal to that of the µC
The critical case is "low" on the 74HC595 and "high" on the µC.
You will need at least 3.3V / (70mA / 8) = 377Ohm. To be safe I'd use 750Ohm.
Supply voltage of 74HC595 is higher than that of the µC
The critical case is "high" on the 74HC595 and "low" on the µC, and it depends on the supply voltage of the 74HC595.
In example, if you have 6V supply at the 74HC595, you will need at least 6V / (70mA / 8) = 686Ohm. To be safe I'd use 1.5kOhm.

Media Foundation video re-encoding producing audio stream sync offset

I'm attempting to write a simple windows media foundation command line tool to use IMFSourceReader and IMFSyncWriter to load in a video, read the video and audio as uncompressed streams and re-encode them to H.246/AAC with some specific hard-coded settings.
The simple program Gist is here
sample video 1
sample video 2
sample video 3
(Note: the video's i've been testing with are all stereo, 48000k sample rate)
The program works, however in some cases when comparing the newly outputted video to the original in an editing program, I see that the copied video streams match, but the audio stream of the copy is pre-fixed with some amount of silence and the audio is offset, which is unacceptable in my situation.
audio samples:
original - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc
copy - |[silence] [silence] [silence] [audio1] [audio2] [audio3] ... etc
In cases like this the first video frames coming in have a non zero timestamp but the first audio frames do have a 0 timestamp.
I would like to be able to produce a copied video who's first frame from the video and audio streams is 0, so I first attempted to subtract that initial timestamp (videoOffset) from all subsequent video frames which produced the video i wanted, but resulted in this situation with the audio:
original - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc
copy - |[audio4] [audio5] [audio6] [audio7] [audio8] ... etc
The audio track is shifted now in the other direction by a small amount and still doesn't align. This can also happen sometimes when a video stream does have a starting timestamp of 0 yet WMF still cuts off some audio samples at the beginning anyway (see sample video 3)!
I've been able to fix this sync alignment and offset the video stream to start at 0 with the following code inserted at the point of passing the audio sample data to the IMFSinkWriter:
//inside read sample while loop
...
// LONGLONG llDuration has the currently read sample duration
// DWORD audioOffset has the global audio offset, starts as 0
// LONGLONG audioFrameTimestamp has the currently read sample timestamp
//add some random amount of silence in intervals of 1024 samples
static bool runOnce{ false };
if (!runOnce)
{
size_t numberOfSilenceBlocks = 1; //how to derive how many I need!? It's aribrary
size_t samples = 1024 * numberOfSilenceBlocks;
audioOffset = samples * 10000000 / audioSamplesPerSecond;
std::vector<uint8_t> silence(samples * audioChannels * bytesPerSample, 0);
WriteAudioBuffer(silence.data(), silence.size(), audioFrameTimeStamp, audioOffset);
runOnce= true;
}
LONGLONG audioTime = audioFrameTimeStamp + audioOffset;
WriteAudioBuffer(dataPtr, dataSize, audioTime, llDuration);
Oddly, this creates an output video file that matches the original.
original - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc
copy - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc
The solution was to insert extra silence in block sizes of 1024 at the beginning of the audio stream. It doesn't matter what the audio chunk sizes provided by IMFSourceReader are, the padding is in multiples of 1024.
My problem is that there seems to be no detectable reason for the the silence offset. Why do i need it? How do i know how much i need? I stumbled across the 1024 sample silence block solution after days of fighting this problem.
Some videos seem to only need 1 padding block, some need 2 or more, and some need no extra padding at all!
My question here are:
Does anyone know why this is happening?
Am I using Media Foundation incorrectly in this situation to cause this?
If I am correct, How can I use the video metadata to determine if i need to pad an audio stream and how many 1024 blocks of silence need to be in the pad?
EDIT:
For the sample videos above:
sample video 1 : the video stream starts at 0 and needs no extra blocks, passthrough of original data works fine.
sample video 2 : video stream starts at 834166 (hns) and needs 1 1024 block of silence to sync
sample video 3 : video stream starts at 0 and needs 2 1024 blocks of silence to sync.
UPDATE:
Other things I have tried:
Increasing the duration of the first video frame to account for the offset: Produces no effect.
I wrote another version of your program to handle NV12 format correctly (yours was not working) :
EncodeWithSourceReaderSinkWriter
I use Blender as video editing tools. Here is my results with Tuning_against_a_window.mov :
from the bottom to the top :
Original file
Encoded file
I changed the original file by settings "elst" atoms with the value of 0 for number entries (I used Visual Studio hexa editor)
Like Roman R. said, MediaFoundation mp4 source doesn't use the "edts/elst" atoms. But Blender and your video editing tools do. Also the "tmcd" track is ignored by mp4 source.
"edts/elst" :
Edits Atom ( 'edts' )
Edit lists can be used for hint tracks...
MPEG-4 File Source
The MPEG-4 file source silently ignores hint tracks.
So in fact, the encoding is good. I think there is no audio stream sync offset, comparing to the real audio/video data. For example, you can add "edts/elst" to the encoded file, to get the same result.
PS: on the encoded file, i added "edts/elst" for both audio/video tracks. I also increased size for trak atoms and moov atom. I confirm, Blender shows same wave form for both original and encoded file.
EDIT
I tried to understand relation between mvhd/tkhd/mdhd/elst atoms, in the 3 video samples. (Yes I know, i should read the spec. But i'm lazy...)
You can use a mp4 explorer tool to get atom's values, or use the mp4 parser from my H264Dxva2Decoder project :
H264Dxva2Decoder
Tuning_against_a_window.mov
elst (media time) from tkhd video : 20689
elst (media time) from tkhd audio : 1483
GREEN_SCREEN_ANIMALS__ALPACA.mp4
elst (media time) from tkhd video : 2002
elst (media time) from tkhd audio : 1024
GOPR6239_1.mov
elst (media time) from tkhd video : 0
elst (media time) from tkhd audio : 0
As you can see, with GOPR6239_1.mov, media time from elst is 0. That's why there is no video/audio sync problem with this file.
For Tuning_against_a_window.mov and GREEN_SCREEN_ANIMALS__ALPACA.mp4, i tried to calculate the video/audio offset.
I modified my project to take this into account :
EncodeWithSourceReaderSinkWriter
For now, i didn't find a generic calculation for all files.
I just find the video/audio offset needed to encode correctly both files.
For Tuning_against_a_window.mov, i begin encoding after (movie time - video/audio mdhd time).
For GREEN_SCREEN_ANIMALS__ALPACA.mp4, i begin encoding after video/audio elst media time.
It's OK, but I need to find the right unique calculation for all files.
So you have 2 options :
encode the file and add elst atom
encode the file using right offset calculation
it depends on your needs :
The first option permits you to keep the original file.But you have to add the elst atom
With the second option you have to read atom from the file before encoding, and the encoded file will loose few original frames
If you choose the first option, i will explain how I add the elst atom.
PS : i'm intersting by this question, because in my H264Dxva2Decoder project, the edts/elst atom is in my todo list.
I parse it, but i don't use it...
PS2 : this link sounds interesting :
Audio Priming - Handling Encoder Delay in AAC

Raspberry Pi with PmodDA2 digital analog conversion

As a part of a project in university, i have to send Data from the Raspberry Pi 2 to the Digilent PmodDA2 using C/C++. For that, i tried to use the bcm2835 library, which can only send 8 bit at a time. The PmodDA2 is a 12 bit device (integer values form 0 to 4095), so how can I transfer alle the bits? In the DACSPI2 Library Reference Manual (functions for Arduino) it even says "this function writes the 12 bits value to the DA converter, by writing 16 bits to SPI..." - so do I have to send 16bits? What do the missing 4 Bits look like then?
What's more, I need information about the clock polarity, the clock phase and if the chip is active at HIGH or at LOW.
Thank's a lot!
PS: For the bit-problem I tried:
char spiOut[3]; char spiIn[3];
if(!bcm2835_init())return 1;
bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
bcm2835_spi_setDataMode(BCM2835_SPI_MODE3);
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_256);
bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);
while (k<10) {
spiOut[0]=Data[k] >> 4;//Data[k] contains the Integer values from 0 to 4095
spiOut[1]=((Data[k]&0x00F)<<4)|(Data[k+1]>>8);
spiOut[2]=Data[k+1]&0x0FF;
bcm2835_spi_transfernb(spiOut, spiIn, sizeof(spiOut));

Synchronizing input pins in directshow

I am creating a directshow filter which's purpose is to take 3 input pins and create a video which shows alternately vidoe from the first source, the second source and the third source, in a fixed time internal.
So if i have three webcam connected to my filter, i want the final video for example to show 5 seconds of the first cam, five seconds of the second cam, and so on...
I have tried two approaches:
Approach one
I use a class TimeManager. This class has a function isItPinsTurn(pinname). This functions returns true or false regarding if the pin is supposed to send sample to the output. To do this the TimeManager creates a new thread which sleeps every x seconds.
After it slept it changes to the current active inputpin to the next.
The result is that every x seconds the isItPinSTurn(pinname) function returns another pin. This way every pin only seconds output to the outputpin when it is its turn, hence i get the desired videos with x intervalls between the input cam.
The problem with this approach
Sleep doesn't seem to work in directshow filters. I get a runtime error:
abort() has been called
Approach two
I use the samples GetMediaTime method and a buffer which keeps track of how much video samples in terms of its mediatime, has already been sent to the output pin. This is best illustrated with code:
void MyFilter::acceptFilterInput(LPCWSTR pinname, IMediaSample* sample)
{
mylogger->LogDebug("In acceptFIlterInput", L"D:\\TEMP\\yc.log");
if (wcscmp(pinname, this->currentInputPin) == 0)
{
outpin->Deliver(sample);
LONGLONG timestart;
LONGLONG timeend;
sample->GetTime(&timestart, &timeend);
*mediaTimeBuffer += timeend - timestart;
if (*mediaTimeBuffer > this->MEDIATIME)
{
this->SetNextPinActive(pinname);
*mediaTimeBuffer = 0;
}
}
}
When the filter starts the currentInputPin is set to pin0 (the first). Calls to acceptFilterInput (which is called by the the input pins receie function) adjust the mediaTimeBUffer with the size of the MediaSample-MediaTime. If this buffer is higher than MEDIATIME (which can for example be 5 (seconds)), the buffer is set back to zero and the next pin is set active.
Problems with this approach
I am not even sure if CMediaSample->GetMediaTime returns the data i need, as it seems to return negative numbers, which doesn't seem to make much sense. I didn't find useful information about the return value of GetMediaTime on the web.
You are expected to block execution (incoming calls to IPin::Receive) on input streams so that other streams could catch up on their own streaming threads. You typically achieve this by either using wait/synchronization APIs and functions, or by holding references on media samples so that input peer would block on empty allocator waiting for a media sample (buffer) to get available.
Yes Sleep works well, although polling is the worst of possible options.
Approach two does not make sense for me because I don't see any real synchronization there: there is no execution blocking, and there is no making pin active. You cannot force data on the input pin, you only can wait to get called with new media sample. So you should block accepting data on one input stream/pin until you get data on another.
Some useful relevant information on multiplexing:
How to make a DirectShow Muxer Filter - Part 1
How to make a DirectShow Muxer Filter - Part 2
GDCL MPEG-4 Multiplexer - available in source, and can multiplex data from 2+ streams