Even though I have found so many Libraries that allows programmers to use the Artnet/ArtnetDMX protocol I haven't found the correct structure to send out Artnet in code (To a socket).
The structure is given but, I just can't figure out in what order bytes should be send.
Do i send a byte to a universe One by One, or do I need to send a Byte array with all the values?
Doesn anyone have experience in sending Artnet over UDP?
This the structure given on wikipedia: http://i.stack.imgur.com/wUjzd.png
I use the following struct for Art-Net v2
typedef struct {
char ID[8]; //"Art-Net"
UInt16 OpCode; // See Doc. Table 1 - OpCodes eg. 0x5000 OpOutput / OpDmx
UInt16 version; // 0x0e00 (aka 14)
UInt8 seq; // monotonic counter
UInt8 physical; // 0x00
UInt8 subUni; // low universe (0-255)
UInt8 net; // high universe (not used)
UInt16 length; // data length (2 - 512)
uint8_t data[512]; // universe data
} ArtnetDmx;
If you want to write an Art-Net application you should really read the documentation located on Artistic Licence.
I would follow the version 2 (14) specification as that version 3 is quite rare in the wild.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Artnet
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string id;
public short opCode;
public byte protocolHi;
public byte protocolLo;
public byte sequence;
public byte physical;
public short universe;
public short length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] data;
}
Related
I have a native struct, (which is quite large so I have to use new key word to instantiate, below is just to make a MCVE I cant change the struct as it is provided as external dependencies),
struct NativeStruct
{
char BrokerID[11];
char InvestorID[13];
char InstrumentID[31];
char OrderRef[13];
char UserID[16];
char OrderPriceType;
char Direction;
double LimitPrice;
}
I want to convert NativeStruct to managed object, so I defined a ref struct to mirror it, this also used two enums as below,
public enum struct EnumOrderPriceTypeType
{
AnyPrice = (Byte)'1',
LimitPrice = (Byte)'2',
BestPrice = (Byte)'3',
LastPrice = (Byte)'4',
LastPricePlusOneTicks = (Byte)'5',
LastPricePlusTwoTicks = (Byte)'6',
LastPricePlusThreeTicks = (Byte)'7',
AskPrice1 = (Byte)'8',
AskPrice1PlusOneTicks = (Byte)'9',
AskPrice1PlusTwoTicks = (Byte)'A',
AskPrice1PlusThreeTicks = (Byte)'B',
BidPrice1 = (Byte)'C',
BidPrice1PlusOneTicks = (Byte)'D',
BidPrice1PlusTwoTicks = (Byte)'E',
BidPrice1PlusThreeTicks = (Byte)'F'
};
public enum struct EnumDirectionType
{
Buy = (Byte)'0',
Sell = (Byte)'1'
};
[StructLayout(LayoutKind::Sequential)]
public ref struct ManagedStruct
{
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 11)]
String^ BrokerID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
String^ InvestorID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 31)]
String^ InstrumentID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
String^ OrderRef;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 16)]
String^ UserID;
EnumOrderPriceTypeType OrderPriceType;
EnumDirectionType Direction;
double LimitPrice;
};
Then I use StructureToPtr to copy the native object to managed object, and use WriteLine to test if the copy is successful,
NativeStruct *native = new NativeStruct();
ManagedStruct^ managed = gcnew ManagedStruct();
managed->LimitPrice = 95.5;
managed->BrokerID = "666666";
Marshal::StructureToPtr(managed, IntPtr(native), false);
int i;
for (i = 0; i < 11; i++)
Console::Write(native->BrokerID[i]);
Console::WriteLine();
Console::WriteLine(native->LimitPrice);
Console::WriteLine(L"Hello ");
Console::ReadLine();
My question is why LimitPrice is not copied successfuly? I have been battling this for a week, any help will be welcomed. Thanks a lot.
Marshal::StructureToPtr() can only work correctly when the managed and the native struct are an exact match. By far the simplest way to verify this is to check the sizes of the structures, they must be identical. So add this code to your program:
auto nlen = sizeof(NativeStruct);
auto mlen = Marshal::SizeOf(ManagedStruct::typeid);
System::Diagnostics::Debug::Assert(nlen == mlen);
Kaboom. The native struct takes 96 bytes and the managed one takes 104. Consequences are dire, you corrupt memory and that has a lot more unpleasant side effects than the LimitPrice member value getting copied to the wrong offset.
Two basic ways to trouble-shoot this. You can simply populate all of the managed struct members with unique values and check the first member of the native struct that has the wrong value. The member before it is wrong. Keep going until the you no longer get the kaboom. Or you can write code that uses offsetof() on the native struct members and compare them with Marshal::OffsetOf().
Just to save you the trouble, the problem are the enum declarations. Their size in the native struct is 1 byte but the managed versions take 4 bytes. Fix:
public enum struct EnumOrderPriceTypeType : Byte
and
public enum struct EnumDirectionType : Byte
Note the added : Byte to force the enum to take 1 byte of storage. It should be noted that copying the members one-by-one instead of using Marshal::StructureToPtr() is quicker and would have saved you a week of trouble.
My C structure format is this:
typedef struct pt_data {
int Length; ///< Length of the Data field in bytes
uchar Data[1]; ///< The data itself, variable length
} PT_DATA;
My C function is this:
PT_STATUS PTSetFingerData (
IN PT_CONNECTION hConnection,
IN PT_LONG lSlotNr,
IN PT_DATA *pFingerData
)
Now I want to put a wrapper for this function in C#.
How can I do this? In particular, how can I do this for passing the C# PT_DATA struct to PT_DATA C struct?
You need to marshal the data manually. A variable length struct cannot be marshalled by the p/invoke marshaller.
In your case the obvious way to do this would be to declare the PTDATA* argument as byte[] in your p/invoke. Then you just need to populated the byte array before calling the function. The first 4 bytes are the length of the subsequent data.
static byte[] GetPTData(byte[] arr)
{
byte[] len = BitConverter.GetBytes(arr.Length);
byte[] data = new byte[sizeof(int) + arr.Length];
Array.Copy(len, data, sizeof(int));
Array.Copy(arr, 0, data, sizeof(int), arr.Length);
return data;
}
I'm trying to serialize a data struct, send it over the network and deserialize it on the other side. Works perfectly fine if both sides are consistently compiled as x64 or x86 but it won't work between the two, even if I only serialize a single boolean.
Serialization code:
Myclass myc;
std::stringstream ss;
boost::archive::text_oarchive oa(ss);
oa << myc;
// get stringstream's length
ss.seekg(0, ios::end);
int len = ss.tellg();
ss.seekg(0, ios::beg);
// allocate CORBA type and copy the stringstream buffer over
const std::string copy = ss.str(); // copy since str() only generates a temporary object
const char* buffer = copy.c_str();
// ByteSequence is a sequence of octets which again is defined as a raw, platform-independent byte type by the CORBA standard
IDL::ByteSequence_var byteSeq(new IDL::ByteSequence());
byteSeq->length(len);
memcpy(byteSeq->get_buffer(), buffer, len);
return byteSeq._retn();
Deserialization code:
IDL::ByteSequence_var byteSeq;
byteSeq = _remoteObject->getMyClass();
// copy CORBA input sequence to local char buffer
int seqLen = byteSeq->length();
std::unique_ptr<char[]> buffer(new char[seqLen]);
memcpy(buffer.get(), byteSeq->get_buffer(), seqLen);
// put buffer into a stringstream
std::stringstream ss;
std::stringbuf* ssbuf = ss.rdbuf();
ssbuf->sputn(buffer.get(), seqLen);
// deserialize from stringstream
// throws exception 'Unsupported version' between x86 and x64
boost::archive::text_iarchive ia(ss);
MyClass result;
ia >> result;
As far as I can tell without testing this is caused by different boost versions on the various architectures, see also Boost serialization: archive "unsupported version" exception
I'm having run time error in addStu function when trying to read data from input file to binary tree, is there anything wrong with the format or pointer usage?
This is my code for reading file:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "BST_ADT.h"
// Structure
typedef struct
{
char* name;
char* market;
char* initial;
float stock;
}STUDENT;
// Prototype Delarations
void addStu (BST_TREE* list);
//void deleteStu (BST_TREE* list);
//void findStu (BST_TREE* list);
//void printList (BST_TREE* list);
//int compareStu (void* stu1, void* stu2);
//void processStu (void* dataPtr);
int main (void)
{
// Local Definitions
BST_TREE* list;
// Statements
list = BST_Create(compareStu);
addStu(list);
deleteStu(list);
findStu (list);
printList(list);
return 0;
}
/*===================== addStu =========================*/
void addStu (BST_TREE* list)
{
// Local Declarations
STUDENT* stuPtr;
FILE* fp;
char fileName[25];
char buffer [100];
// Statements
stuPtr = (STUDENT*)malloc (sizeof (STUDENT));
printf("Enter the file name: ");
gets(fileName);
fp = fopen(fileName, "r");
if(fp == NULL)
{
printf("Error cannot open the file!\n");
exit(101);
}
while(fgets(buffer, 100, fp) != NULL)
{
if (!stuPtr)
printf("MEmory overflow!\n"), exit(101);
sscanf(buffer, "%s %s %s %f", stuPtr->name, stuPtr->market, stuPtr->initial, &(stuPtr->stock));;
} // end while
BST_Insert(list, stuPtr);
} //addStu
this is my input:
Microsoft Corporation; NASDAQ MSFT 259.94B
Yahoo! Inc.; NASDAQ YHOO 37.67B
Baidu.com, Inc. (ADR); NASDAQ BIDU 8.64B
CNET Networks, Inc.; NASDAQ CNET 1.13B
QuickLogic Corporation; NASDAQ QUIK 88.62M
Answers Corporation; NASDAQ ANSW 53.49M
Apple Inc.; NASDAQ AAPL 114.17B
EarthLink, Inc.; NASDAQ ELNK 890.68M
Amazon.com, Inc.; NASDAQ AMZN 28.28B
IAC/InterActiveCorp; NASDAQ IACI 6.09B
Time Warner Inc.; NYSE TWX 57.29B
You havent initialize the strings in your structure. Bear in mind that char* name is a POINTER to a string, NOT the string itself. Same with the other strings. In a 32 bit app, the size of char* is actually 4 bytes. That means your entire structure is 16 bytes (3 * 4 byte pointers + 1 4 byte float).
You will need to allocate space for your strings and assign them to your structure before you can try populating them from the file data. Otherwise your structure will be pointing to whatever garbage was on the heap at the pointer name* as the address of your string.
EDIT:
Try allocating some space for your strings:
stuPtr->name = (char*) malloc(128 * sizeof(char));
This will create a string large enough to hold 127 chars. Do the same for your other strings.
A very, very long time since I've used used C, but the fact that you are not allocating space for STUDENT elements shouts out.
When you declare
// Structure
typedef struct
{
char* name;
char* market;
char* initial;
float stock;
}STUDENT;
You are declaring space for 16 bytes (assuming 4 byte pointers and floats).
Now each of the pointers name, market and initial have undefined values when created as a STUDENT. They point to random space - if you VERY lucky they are initialised to nulls.
A better definition for STUDENT would be
typedef struct
{
char name[MAX_NAME_SIZE];
char market[MAX_MARKET_SIZE];
char initial[MAX_INITIAL_SIZE];
float stock;
}STUDENT;
Where the MAXs are defines to be added earlier.
The other alternative would be to assign space just after creation
stuPtr = (STUDENT*)malloc (sizeof (STUDENT));
stuPtr->name = (char *)malloc(MAX_NAME_SIZE);
stuPtr->market = (char *)malloc(MAX_MARKET_SIZE);
stuPtr->initial = (char *)malloc(MAX_INITIAL_SIZE);
Array names are pointers to the first element of an array, so name and &name[0] are the same.
Hope this helps.
Andrew
Need help with union struct. I'm receiving byte stream that consists of various packets, so I'm putting the byte data into union struct and accessing needed data via struct members. The problem is with uint32_t type member - the read skips its two bytes and shows wrong value when accessing via its member. Here's full demo code:
PacketUtils.h
#include <stdint.h>
typedef struct {
uint8_t startSymbol;
uint8_t packetType;
uint32_t deviceId;
uint16_t packetCRC;
} PacketData;
typedef union {
uint8_t *bytes; // stores raw bytes
PacketData *packet;
} Packet;
// Puts bytes into predefined struct
void getPacketFromBytes(void *bytes, Packet *packetRef);
PacketUtils.c
#include <stdio.h>
#include "UnionStruct.h"
void getPacketFromBytes(void *bytes, Packet *packetRef)
{
uint8_t *rawBytes = (uint8_t *)bytes;
packetRef->bytes = rawBytes;
}
Calling code:
// sample byte data
uint8_t packetBytes[] = {0x11, 0x02, 0x01, 0x01, 0x01, 0x03, 0xbb, 0xbd};
Packet packetRef;
getPacketFromBytes(packetBytes, &packetRef);
printf("%x\n", packetRef.packet->startSymbol); // good - prints 0x11
printf("%x\n", packetRef.packet->packetType); // good - prints 0x02
printf("%x\n", packetRef.packet->deviceId); // bad - prints bd bb 03 01
printf("%x\n", packetRef.packet->packetCRC); // bad - prints 36 80 (some next values in memory)
Everything is OK when PacketData struct consist of uint8_t or uint16_t type members then the print shows correct values. However, printing deviceId of type uint32_t skips two bytes (0x01 0x01) and grabs last 4 bytes. Printing packetCRC prints the values out of given byte array - some two values in memory, like packetBytes[12] and packetBytes[13]. I can't figure out why it skips two bytes...
The problem is due to the fields being padded out to default alignment on your platform. On most modern architectures 32-bit values are most efficient when read/written to a 32-bit word aligned address.
In gcc you can avoid this by using a special attribute to indicate that the structure is "packed". See here:
http://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/Type-Attributes.html
So struct definition would look something like this:
typedef struct {
uint8_t startSymbol;
uint8_t packetType;
uint32_t deviceId;
uint16_t packetCRC;
} PacketData __attribute__((packed));
The 32-bit number will be aligned on a 4-byte boundary only. If you move it to the start of your struct, it may just work as you want.
Processors usually are optimised to fetch data on multiples of the datum size - 4 bytes for 32-bit, 8 bytes for 64-bit... - and the compiler knows this and adds gaps into the data structures to make sure that the processor can fetch the data efficiently.
If you don't want to deal with the padding and can't move the data structure around, you could define
typedef struct {
uint8_t startSymbol;
uint8_t packetType;
uint16_t deviceIdLow;
uint16_t deviceIdHigh;
uint16_t packetCRC;
} PacketData;
and then just write
uint32_t deviceID = packetRef.packet->deviceIdLow | (packetRef.packet->deviceIdLow << 16);