I am getting my first testing in with the new Kogna Board (this board is AWESOME - thanks!!!).
I can't find the Kogna's ADC and DAC values in the bulk status update. Am I missing something here?
I know I can read Kogna's ADC with a "ADCx" console query (with x being 8,9,10 or 11). Should this also be updated in CurrentStatus.ADC[x]?
I haven't figured out how to query the DAC setting through the .NET interface yet. What is the best way to continually query these from a .NET application.
Thanks - and I am really excited about this new board.
Kogna Analog Values
Moderators: TomKerekes, dynomotion
Re: Kogna Analog Values
After digging into this a bit deeper, I realized the Kogna ADC and DAC values are indeed uploaded with the "GetStatus" command, they are just not parsed and exposed through the MainStatus structure in the Kmotion_dotNET dll (unless I am missing something).
To workaround this I have:
- made a C# structure to replicate the MAIN_STATUS struct in PC-DSP.h
- periodically request "GetStatus" to upload the binary data in Hex string format
- convert the hex string into a continuous byte array
- marshal the byte array into the C# KognaMainStatus structure
This seems to be working well. I have played with setting various parameters in the Kmotion.exe GUI and seeing the changes being marshalled correctly in my C# data structure.
I am sure I have a few bugs to work out yet, but in case it is of interest...
The marshalling code:
My C# definition of the KognaMainStatus derived from PC-DSP.h
To workaround this I have:
- made a C# structure to replicate the MAIN_STATUS struct in PC-DSP.h
- periodically request "GetStatus" to upload the binary data in Hex string format
- convert the hex string into a continuous byte array
- marshal the byte array into the C# KognaMainStatus structure
This seems to be working well. I have played with setting various parameters in the Kmotion.exe GUI and seeing the changes being marshalled correctly in my C# data structure.
I am sure I have a few bugs to work out yet, but in case it is of interest...
The marshalling code:
Code: Select all
//above this point the main_status_byte_array was populated by parsing the string returned from KM.WriteLine("GetStatus")
// Pin the managed memory, marshal it into the structure, and the free it back up
GCHandle handle = GCHandle.Alloc(main_status_byte_array, GCHandleType.Pinned);
KognaMainStatus KogMainStat = (KognaMainStatus)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(KognaMainStatus));
handle.Free();
Code: Select all
public const int N_PC_COMM_PERSIST = 8;
public const int N_DACS = 8; // Kanalog
public const int N_ADCS = 8;
public const int N_PWMS = 8;
public const int N_ENCS = 8;
public const int N_ENCS_KOGNA = 20;
public const int N_DACS_KOGNA = 8; // referenced after Kanalog as 8-15
public const int N_ADCS_KOGNA = 4; // referenced after Kanalog as 8-11
public const int N_ADCS_SNAP= 8; // per snap amp
public const int N_PWMS_SNAP =4; // per snap amp
public const int N_ENCS_SNAP =4;
public const int N_CHANNELS_KOGNA = 16;
public const int N_IO_PWMS = 8;
public const int N_KOGNA_HRPWM = 4;
public struct KognaMainStatus
{
int VersionAndSize; //bits 16-23 = version, bits 0-15 = size in words
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_ADCS+2* N_ADCS_SNAP)] int[] ADC;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_DACS)] int[] DAC;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_PWMS + 2 * N_PWMS_SNAP)] int[] PWM;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_CHANNELS_KOGNA)] double[] Position;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_CHANNELS_KOGNA)] double[] Dest;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_CHANNELS_KOGNA)] byte[] OutputChan0;
int InputModes; // 4 bits for each axis (not sure why only using 16 of 32 bits)
int InputModes2; // 4 bits for each axis
int InputModes3; // 4 bits for each axis
int InputModes4; // 4 bits for each axis
int OutputModes; // 4 bits for each axis
int OutputModes2; // 4 bits for each axis
int OutputModes3; // 4 bits for each axis
int OutputModes4; // 4 bits for each axis
int Enables; // 1 bit for each axis
int AxisDone; // 1 bit for each axis
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] int[] BitsDirection; // KFLOP - 64 bits of I/O direction 1 = output
int BitsDirection200; // Kogna - 24 bits 200-223 of I/O direction 1 = output
int BitsDirection280; // Kogna - 10 bits 280-289 of I/O direction 1 = output
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] int[] BitsState; // KFLOP - 64 bits of state lsb=I/O bit0
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] int[] BitsState200; // Kogna - 90 bits 200-289 of state lsb=I/O bit200
int PinMuxModes; // Kogna - 10 Pin function modes 2 bits per pin 4 HRPWM + 6 SPI
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_ADCS_KOGNA)] short[] Kogna_ADC; // format 12 bits data (signed extended to 16 bits)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_DACS_KOGNA)] short[] Kogna_DAC; // format 12 bits data
byte Kogna_PWM_Prescale; // Prescale sets frequency of all 8 8-bit PWMs
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_IO_PWMS)] byte[] Kogna_PWM; // current pulse settings
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_IO_PWMS)] byte[] Kogna_PWM_Enables; // PWM Enables to control Pin?
UInt16 HRPWMPeriod01; // Kogna HRPWMs Periods
UInt16 HRPWMPeriod2;
UInt16 HRPWMPeriod3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_KOGNA_HRPWM)] UInt16[] HRPWM; // Kogna HRPWMs Pulse widths
int SnapBitsDirection0; // Snap - 32 bits of I/O direction 1=output 16-29 GPIO only, Card 0
int SnapBitsDirection1; // Snap - 32 bits of I/O direction 1=output 16-29 GPIO only, Card 1
int SnapBitsState0; // Snap - 32 bits of state 16-29 GPIO 0-7 Diff 8-15 OPTO, Card 0
int SnapBitsState1; // Snap - 32 bits of state 16-29 GPIO 0-7 Diff 8-15 OPTO, Card 1
int KanalogBitsStateInputs; // Kanalog - 16 bits 128-143
int KanalogBitsStateOutputs; // Kanalog - 24 bits 144-167
int RunOnStartUp; // word Bits 1-7 selects which threads to execute on startup
int ThreadActive; // one bit for each thread, 1=active, bit 0 - primary
int StopImmediateState; // Status of Stop Coordinated Motion Immediately
double TimeStamp; // Time in seconds (since KFlop boot) this status was aquired
[MarshalAs(UnmanagedType.ByValArray, SizeConst = N_PC_COMM_PERSIST)] int[] PC_comm;// 8 persist Variables constantly uploaded to send misc commands/data to PC
UInt32 VirtualBits; // Virtual I/O bits simulated in memory
UInt32 VirtualBitsEx0; // only upload 32 1024 Expanded Virtual Bits
}
Re: Kogna Analog Values
For completeness sake I am adding the code below that parses the "GetStatus" query into the managed KognaMainStatus structure.
Code: Select all
/* getBulkStatusUpload
* --------------------------------------------------------------------------------------------------------------------------------------------
* Commonly needed status information can be uploaded from the dynomotion board in bulk as a single binary image with a call to "GetStatus"
* The binary data is formatted /packed into a MAIN_STATUS structure that is defined in PC-DSP.h
*
* The data is tranmitted over several strings (each terminated with a CR).
* Each string contains (up to 16) continous 32-bit words in hexidecimal format. Each word is delimited by a space character.
* Below is an example of the upload data recieved from a Kogna Board (version 5.0.6).
* In Kogna ver5.0.6, the data is 174 words long, spread over 11 seperature strings
* Note that the first word (0x013500AE in this example), contains the version and size of the returned data. This will be used to check validity.
*
* 013500AE FFFFF800 FFFFF800 FFFFF800 FFFFF800 FFFFF800 FFFFF800 FFFFF800 FFFFF800 00000000 00000000 00000000 00000000 00000000 00000000 00000000
* 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
* 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
* 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
* 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 BFF00000 00000000 00000000
* 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
* 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
* 00000000 00000000 06040200 0E0C0A08 0E0E0E0E 0E0E0E0E 00001111 00001111 00001111 00001111 00000000 00000000 00000000 00000000 00000000 00000000
* 00000000 0000C000 00000000 00000000 00000000 FFFFC000 FE000000 000177F7 03600000 000A0000 00DD0000 0137044C 00000199 00000000 00000000 00000000
* 00000000 00000000 00000000 00000000 0FFF0000 10001000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
* 00000000 00000000 1CD43A38 40F24F2B 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000FFFF FFFFFFFF
*
-------------------------------------------------------------------------------------------------------------------------------------------------*/
/// <summary>
/// requests a bulk status upload from the Kogna/Kflop board, parses into binary data, and attempts to marshal the raw data into a KognaMainStatus
/// structure that mirrors the format of the structure defined in PC-DSP.h
/// If the call is successful, "true" will be returned and the main_status_to_populate object will be populated from the bulk status data.
/// If the call fails, "false" will be returned and main_status_to_populate object will remain untouched
/// </summary>
private bool getBulkStatusUpload(ref KognaMainStatus main_status_to_populate)
{
const int STAT_VERSION = 309; // the version of MAIN_STATUS from PC-DSP.h
const int num_words_expected = 174; // the number of words returned from the GetStatus call
int num_words_processed = 0; // var to keep track of the number of words we have parsed
UInt32[] status_words = new UInt32[num_words_expected]; // array to hold words parsed from bulk status upload
if (verifylKognaStructureSize(num_words_expected) == false) // verify size of our internal Kogna Structure, this could be commented out after prove-out
return false;
if (KM.WaitToken(100) != KMOTION_TOKEN.KMOTION_LOCKED) // get lock to prevent outside access to the board while we build / gather the status upload
return false;
try
{
KM.WriteLine("GetStatus"); // send command to query the bulk status:
while (num_words_processed < num_words_expected) // loop through the returned strings and parse out the binary data
{
string strline = ""; // string to hold the next line of the status update
bool read_ok = KM.ReadLineTimeout(ref strline, 5000); // get the next line of hexidecimal words from the GetStatus call
if (read_ok != true) // exit routine if there was a readline timeout
{
MessageBox.Show("Read Timeout in GetStatus");
KM.ReleaseToken();
return false;
}
string[] strWords = strline.Trim().Split(' '); // split the current line into an array of strings, each element being one hexidecimal word
for (int i = 0; i < strWords.Length; i++) // loop through each word in the array
{
UInt32 currentWord = Convert.ToUInt32(strWords[i], 16); // parse the value from the formatted string
status_words[num_words_processed] = currentWord; // add it to our array
num_words_processed++; // incriment the number of words processed counter
if (num_words_processed == 1) // check version and size info from the bulk upload if this is the first word
{
if (checkMainStatusVersionAndSize(STAT_VERSION, num_words_expected, currentWord) == false)
{
KM.ReleaseToken(); // release token
return false; // and exit routine if there is a version mismatch
}
}
}
}
KM.ReleaseToken(); // release the lock on the board
GCHandle handle = GCHandle.Alloc(status_words, GCHandleType.Pinned); // pin the managed array so it can be marshalled
main_status_to_populate = (KognaMainStatus)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(KognaMainStatus)); // marshal the data into the main_status_to_populate object
handle.Free(); // free the pinned object
return true; // return true, indicating success
}
catch (Exception)
{
return false; //todo, capture exception message and report
}
}
/// <summary>
/// checks the Version and Size word caputured during the GetStatus queruy against expected values
/// </summary>
private bool checkMainStatusVersionAndSize(int expectedVersion, int expectedWords, UInt32 VersionAndSizeWord)
{
uint num_words_from_upload = VersionAndSizeWord & 0xFFFF; // size (in words) is bits 0-15
uint version_from_upload = (VersionAndSizeWord & 0xFFFF0000)>>16; // version is bits 16-31
// check size, error if we don't get expected value
if (num_words_from_upload != expectedWords)
{
MessageBox.Show("Error in size check of GetStatus upload");
return false;
}
// check size, error if we don't get expected value
if (version_from_upload != expectedVersion)
{
MessageBox.Show("Error in version check of GetStatus upload");
return false;
}
return true;
}
/// <summary>
/// checks the size of our internal KognaMainStatus structure against the known from PC-DSP.h
/// </summary>
private bool verifylKognaStructureSize(int expectedWords)
{
// check the size of our MainStatus structure. For Kogna - Kmotion5.0.6 this will/should be 696 bytes
if (Marshal.SizeOf<KognaMainStatus>() != expectedWords * 4)
{
MessageBox.Show("Size of C# KognaMainStatus structure does not equal expected value");
return false;
}
return true;
}
- TomKerekes
- Posts: 2676
- Joined: Mon Dec 04, 2017 1:49 am
Re: Kogna Analog Values
Hi Jim,
Sorry for the late reply.
You are correct the new Kogna bulk status fields were not exposed to the .NET interface.
Your method seems more efficient than than the method we used. We will incorporate something similar in the next release.
Thanks!
Sorry for the late reply.
You are correct the new Kogna bulk status fields were not exposed to the .NET interface.
Your method seems more efficient than than the method we used. We will incorporate something similar in the next release.
Thanks!
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.