I am quite interested in using .NET features to access hardware via Mathematica. I have sorted out how access NI USB-6009 (via NetAssembly), DrDAQ (via 32-bit DLL) and Arduino (via .NET SerialIO) boards but I am still not comfortable with the way I am using .NET calls.

UDP NTP Access

As an example, here is a self-contained piece of code that accesses NTP servers using the .NET UDP class. Most of the code is concerned with interpreting the 48-Byte NTP package and it is essentially my test code. The code is "clean" in the sense that if you run the last lines following the Grid command everything closes down perfectly, which is important as long as you play with the code.

Install .NET:

Needs["NETLink`"];

InstallNET[];

Prepare the NTP UDP request package (which consists of 48 bytes):

ntpServer ="192.53.103.108"; (* PTB server Braunschweig Germany *)
(* or *)
ntpServer = "64.90.182.55"; (* NIST server, NY, USA *)

packetLength = 48;
packet = Table[0, {packetLength}];
packet[[1 ;; 4]] = {2^^11100011, 10^^0, 10^^6, 16^^EC};
packet[[13 ;; 16]] = {10^^49, 16^^4E, 10^^49, 10^^52};

sendPacket = NETNew["System.Byte[]", packetLength];
sendPacket = packet;
receivePacket = NETNew["System.Byte[]", packetLength];

udp = NETNew["System.Net.Sockets.UdpClient"];
endPoint = NETNew["System.Net.IPEndPoint", 1, 1];

udp@Connect[ntpServer, 123];

Define interpretations of values returned via the NTP protocol:

leapIndicatorList = {"No warning", "Last minute of day has 61 sec", 
   "Last minute of day has 59 sec", "Alarm"};
modeList = {"Unknown", "Symmetric Active", "Symmetric Passive", "Client", 
   "Server", "Broadcast" , "NTP control message"};
stratumList = {"Unspecified", "Primary Server", "Secondary Server", 
   "Unsynchronized", "Reserved"};

Testing and gathering some information:

In[22]:= err = udp@Send[sendPacket, packetLength]

Out[22]= 48

In[23]:= available = udp@Available[]

Out[23]= 0

In[24]:= broadcatsQ = udp@EnableBroadcast[];

In[25]:= ttlNumber = udp@Ttl[];

In[26]:= receivePacket = udp@Receive[endPoint];

In[27]:= endPoint@Address@ToString[]

Out[27]= "64.90.182.55"

In[28]:= endPoint@ToString[]

Out[28]= "64.90.182.55:123"

In[29]:= NETObjectToExpression[endPoint@ToString[]]

Out[29]= "64.90.182.55:123"

In[30]:= dataPacket = NETObjectToExpression[receivePacket]

Out[30]= {36, 1, 6, 227, 0, 0, 0, 0, 0, 0, 0, 0, 65, 67, 84, 83, 210, 237, 24, 58, 14, \
17, 190, 191, 0, 0, 0, 0, 0, 0, 0, 0, 210, 237, 24, 65, 38, 226, 85, 160, \
210, 237, 24, 65, 38, 227, 17, 28}

In[31]:= leapIndicator = BitShiftRight[BitAnd[dataPacket[[1]], 2^^11000000], 6]

Out[31]= 0

In[32]:= versionNumber = BitShiftRight[BitAnd[dataPacket[[1]], 2^^00111000], 3]

Out[32]= 4

In[33]:= mode = BitAnd[dataPacket[[1]], 2^^00000111]

Out[33]= 4

In[34]:= stratum = dataPacket[[2]]

Out[34]= 1

In[35]:= stratumText = Which[
  stratum == 0, stratumList[[1]],
  stratum == 1, stratumList[[2]],
  2 <= stratum <= 15, stratumList[[3]],
  stratum == 16, stratumList[[4]],
  stratum > 16, stratumList[[5]]
  ]

Out[35]= "Primary Server"

In[36]:= poll = If[dataPacket[[3]] > 127, -(255 - dataPacket[[3]]), dataPacket[[3]]]

Out[36]= 6

In[37]:= pollValue = 2^poll

Out[37]= 64

In[38]:= precision = 
 If[dataPacket[[4]] > 127, -(255 - dataPacket[[4]]), dataPacket[[4]]]

Out[38]= -28

In[39]:= precisionValue = 1000.0 2^precision

Out[39]= 3.72529*10^-6

In[40]:= rootDelay = dataPacket[[5 ;; 8]]

Out[40]= {0, 0, 0, 0}

In[41]:= rootDelayValue = 
 1000.0 (Fold[256 #1 + #2 &, 0, dataPacket[[5 ;; 6]]] + 
    Fold[256 #1 + #2 &, 0, dataPacket[[7 ;; 8]]]/2^16)

Out[41]= 0.

In[42]:= rootDispersion = dataPacket[[9 ;; 12]]

Out[42]= {0, 0, 0, 0}

In[43]:= rootDispersionValue = 
 1000.0 (Fold[256 #1 + #2 &, 0, dataPacket[[9 ;; 10]]] + 
    Fold[256 #1 + #2 &, 0, dataPacket[[11 ;; 12]]]/2^16)

Out[43]= 0.

In[44]:= refIdentifier = dataPacket[[13 ;; 16]]

Out[44]= {65, 67, 84, 83}

In[45]:= refIdentifierString = 
 If[Fold[And, True, (64 < # < 123 || # == 0) & /@ refIdentifier], 
  FromCharacterCode[refIdentifier], 
  ToString[dataPacket[[13]]] <> "." <> ToString[dataPacket[[14]]] <> "." <> 
   ToString[dataPacket[[15]]] <> "." <> ToString[dataPacket[[16]]]]

Out[45]= "ACTS"

In[46]:= refTimestamp = Fold[256 #1 + #2 &, 0, dataPacket[[17 ;; 20]]]

Out[46]= 3538753594

In[47]:= refTimestampMS = 1000.0 Fold[256 #1 + #2 &, 0, dataPacket[[21 ;; 24]]]/2^32

Out[47]= 54.9583

In[48]:= orgTimestamp = Fold[256 #1 + #2 &, 0, dataPacket[[25 ;; 28]]]

Out[48]= 0

In[49]:= orgTimestampMS = 1000.0 Fold[256 #1 + #2 &, 0, dataPacket[[29 ;; 32]]]/2^32

Out[49]= 0.

In[50]:= rcvTimestamp = Fold[256 #1 + #2 &, 0, dataPacket[[33 ;; 36]]]

Out[50]= 3538753601

In[52]:= rcvTimestampMS = 1000.0 Fold[256 #1 + #2 &, 0, dataPacket[[37 ;; 40]]]/2^32

Out[52]= 151.891

In[53]:= trmTimestamp = Fold[256 #1 + #2 &, 0, dataPacket[[41 ;; 44]]]

Out[53]= 3538753601

In[54]:= trmTimestampMS = 1000.0 Fold[256 #1 + #2 &, 0, dataPacket[[45 ;; 48]]]/2^32

Out[54]= 151.902

In[55]:= DateString[trmTimestamp, TimeZone -> 2]

Out[55]= "Mon 20 Feb 2012 20:06:41"

In[56]:= endPoint@ToString[]

Out[56]= "64.90.182.55:123"

Now we display all of the information obtained above in a Grid:

myPadding[x_] := 
 If[x >= 100, PaddedForm[x, {5, 2}, NumberPadding -> {"", "0"}], 
  PaddedForm[x, {4, 2}, NumberPadding -> {"0", "0"}]];

Grid[{{"Descriptions", "NTP returned value", 
   "NTP interpreted value"}, {"End point", ntpServer, 
   endPoint@ToString[]}, {"Leap Indicator", leapIndicator, 
   leapIndicatorList[[leapIndicator + 1]]}, {"Version Number", versionNumber, 
   versionNumber}, {"Mode", mode, modeList[[mode + 1]]}, {"Stratum", stratum, 
   stratumText}, {"Poll Interval", poll, pollValue}, {"Precision", precision, 
   precisionValue " ms"}, {"Root Delay", rootDelay, 
   rootDelayValue " ms"}, {"Root Dispersion", rootDispersion, 
   rootDispersionValue " ms"}, {"Reference Identifier", refIdentifier, 
   refIdentifierString}, {"Reference Timestamp", refTimestamp, 
   DateString[refTimestamp] <> " (+ " <> 
    ToString[refTimestampMS // myPadding] <> " ms)"}, {"Originate Timestamp", 
   orgTimestamp, 
   DateString[orgTimestamp] <> " (+ " <> 
    ToString[orgTimestampMS // myPadding] <> " ms)"}, {"Receive Timestamp", 
   rcvTimestamp, 
   DateString[rcvTimestamp] <> " (+ " <> 
    ToString[rcvTimestampMS // myPadding] <> " ms)"}, {"Transmit Timestamp", 
   trmTimestamp, 
   DateString[trmTimestamp] <> " (+ " <> 
    ToString[trmTimestampMS // myPadding] <> " ms)"}}, Frame -> All, 
 ItemStyle -> Directive[FontFamily -> "Courier", FontSize -> 14], 
 Alignment -> {{Right, Right, Right}, Top}, 
 Background -> {None, {Lighter[Yellow, .9], {White, 
     Lighter[Blend[{Blue, Green}], .8]}}},
 Dividers -> {{}, Table[(2 + 12 n) -> Thickness[2], {n, 0, 4}]}, 
 Spacings -> {5, 1}]

Cleanup:

udp@Close[];

ReleaseNETObject[udp];
ReleaseNETObject[sendPacket];
ReleaseNETObject[receivePacket];
ReleaseNETObject[endPoint];

UninstallNET[];
link|improve this question
2  
226 lines of code (144 without newlines) and a bunch of Out[n] lines that cannot be pasted properly... Please don't dump code on us and expect us to go through it. Reduce your problem to a minimal working example and explain clearly what the problem is and what you're trying to do. Voting to close as NaRQ until it is fixed. – R.M Feb 20 at 19:36
1  
Could you please be specific about what the question is? Is it to review the code? Or was your intention to share the code? – Szabolcs Feb 20 at 19:38
2  
Welcome to Mathematica.StackExchange.com! I'm having trouble spotting even the unspecific question here. Is it simply a request for a code review/tips on how to spiff this up? – sblom Feb 20 at 19:45
I've taken a first pass at cleaning up the code above--I think the section the question relates to is the one I've given the heading "Testing and gathering some information", but this is still rather unclear. Ernst: could you clarify this? – Oleksandr R. Feb 20 at 20:04
First of all, thanks for cleaning up the code. I was not fully aware of the possibilities here. As I wrote, I have managed to use .NET and DLLs in various different contexts but I am not quite sure if there aren't simpler means than the one I presented with the NTP example above. I would certainly appreciate the ideas of others in this respect. I have of course read the Mma .NET guide but I still had to figure a lot out for myself. I am paritculalrly with the way many functions appear in the notebook. E.g. Send[..] and Available[] are blue and ToString[.] indicates a missing argument. .NET pro – Ernst Stelzer Feb 22 at 8:06
show 1 more comment
feedback

closed as not a real question by R.M, rcollyer, Verbeia, Sjoerd C. de Vries Mar 8 at 20:32

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. See the FAQ for guidance on how to improve it.

Browse other questions tagged or ask your own question.