Your Universal Remote Control Center
RemoteCentral.com
Philips Pronto Professional Forum - View Post
Previous section Next section Previous page Next page Up level
Up level
The following page was printed from RemoteCentral.com:

Login:
Pass:
 
 

Page 1 of 2
Topic:
Reading TCP return string with HEX
This thread has 23 replies. Displaying posts 1 through 15.
Post 1 made on Tuesday November 2, 2010 at 14:17
rap
Long Time Member
Joined:
Posts:
September 2006
59
I've read many of the threds on sockets and HEX. So far the info has got me to this point for my first ever TCP connection:

var socket = new TCPSocket(false);//new async socket
var result;
var header = "ISCP\x00\x00\x00\x10\x00\x00\x00\x08\x01\x00\x00\x00"

System.print("Trying connection to DHC 40.1...");


socket.connect("192.168.1.50", 60128, 3000);// port 60128, 3000 s\msec

socket.onConnect = function() {
System.print("Connection to DHC 40.1 sucessful!");

socket.write(header+"!1PWR01\r");// power on
System.delay(250);//wait 250 msec
socket.write(header+"!1PWRQSTN\r");//query power

}

result = "";
socket.onData = function() {
result = socket.read();
//result += socket.read(); //tried += and =, same result
System.print("Data: " + result);
}

Results: Connection is successful, power on command performs, but the issue is collecting the return string which is supposed to come back with the same header sent follwed by ASCII response string something like "!1PWR01\x1A"

What is collected is only "ISCP" from the header. Then all else after that is lost. I'm using the _PS_DEBUG_ panel for output.

Something simple that I'm missing?

edit: The device is an Integra DHC 40.1 preamp/processor

Last edited by rap on November 2, 2010 14:27.
Post 2 made on Tuesday November 2, 2010 at 14:31
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
System.print may not show you everything that is in the message as there are embedded NULL characters in the message. However, the length of the string returned should be reported as something larger than 4.

You will also likely need to use myString.charCodeAt(index) to examine the string character by character to maybe build a byte array. ;-)

You might want to go here and download the ProntoPro Communications document that Barry has published.

[Link: the-gordons.net]
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 3 made on Tuesday November 2, 2010 at 17:15
rap
Long Time Member
Joined:
Posts:
September 2006
59
Thank you Lyndel. Just enough info to jump start the thinking again.

With you comments I determines that the Integra returns 26 bytes of data on each event (async connection.) Within the string is the "!" character that begins the message of interest. So now it's just a matter to indexOf("!") and peel off the back part of the strings.

The Pronto debug panel now looks like a scrolling message board as you push buttons on the roll the volume up/dwn on the pre/pro.

Barry's docs and you were a big help! Thank you both.
Post 4 made on Tuesday November 2, 2010 at 18:03
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
Barry has a nice function in that doc that uses an array to translate unprintable characters into readable strings. ;-) Thought that might help.
Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 5 made on Tuesday November 2, 2010 at 18:39
sWORDs
Long Time Member
Joined:
Posts:
November 2006
373
What I do with return strings like this is match them with a regular expression. Something like:

onData=function(a){
    b=a.match(/(ISCP\x00\x00\x00\x10\x00\x00\x00\x08\x01\x00\x00\x00!)([\x00-\x7F])(.*)(\r)/);
   
System.print(b[2]);
};

You could even create expression for every case, but I'm not sure how well that works performance wise.

Also please note that you think that you're sending "ISCP\x00\x00\x00\x10\x00\x00\x00\x08\x01\x00\x00\x00" +"!1PWRQSTN\r" but what you're actually sending is: 49 53 43 50 00 00 00 10 00 00 00 08 01 00 00 00 21 31 50 57 52 51 53 54 4e 0d.

There is no such thing as ASCII in the TCP frame, all you're doing is trying to read as character codes or asking to send the character code. The socket send and onData methods will simply convert before sending or after receiving.

So to make life a little easier:
"ISCP\x00" = "\x49\x53\x43\x50\x00" = String.fromCharCode(73,83,67,80,0)
parseInt(0x49,16) = 73

a = "ISCP\x00"
a.charCodeAt(0) = 73
a.charCodeAt(1) = 83
a.charCodeAt(2) = 67
a.charCodeAt(3) = 80
a.charCodeAt(4) = 0

Last edited by sWORDs on November 2, 2010 20:02.
OP | Post 6 made on Tuesday November 2, 2010 at 21:22
rap
Long Time Member
Joined:
Posts:
September 2006
59
"Also please note that you think that you're sending "ISCP\x00\x00\x00\x10\x00\x00\x00\x08\x01\x00\x00\x00" +"!1PWRQSTN\r" but what you're actually sending is: 49 53 43 50 00 00 00 10 00 00 00 08 01 00 00 00 21 31 50 57 52 51 53 54 4e 0d.

There is no such thing as ASCII in the TCP frame, all you're doing is trying to read as character codes or asking to send the character code. The socket send and onData methods will simply convert before sending or after receiving."

This much I understand...the rest I'm sure I'll figure out.
Now, I think I need to check out the TCP simulator mod. The thread on the subject is terrific.
Post 7 made on Tuesday November 2, 2010 at 21:23
sydinstaller
Active Member
Joined:
Posts:
February 2004
740
Also.
Remember that each string will be a different length and have a different header.

Here are some examples (My system uses ~ to show a HEX byte):
sets System Standby:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~50~57~52~30~30
sets System On:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~50~57~52~30~31
gets the System Power Status:
49~53~43~50~00~00~00~10~00~00~00~0A~01~00~00~00~21~31~50~57~52~51~53~54~4E
sets Audio Muting Off:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~41~4D~54~30~30
sets Audio Muting On:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~41~4D~54~30~31
sets Audio Muting Wrap-Around:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~41~4D~54~54~47
gets the Audio Muting State:
49~53~43~50~00~00~00~10~00~00~00~0A~01~00~00~00~21~31~41~4D~54~51~53~54~4E
sets Speaker Off:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~41~30~30
sets Speaker On:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~41~30~31
sets Speaker Switch Wrap-Around:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~41~55~50
gets the Speaker State:
49~53~43~50~00~00~00~10~00~00~00~0A~01~00~00~00~21~31~53~50~41~51~53~54~4E
sets SurrBack Speaker :
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~4C~53~42
sets Front High Speaker / SurrBack+Front High Speakers:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~4C~46~48
sets Front Wide Speaker / SurrBack+Front Wide Speakers:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~4C~46~57
sets Front High+Front Wide Speakers:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~4C~48~57
sets Speaker Switch Wrap-Around:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~53~50~4C~55~50
gets the Speaker State:
49~53~43~50~00~00~00~10~00~00~00~0A~01~00~00~00~21~31~53~50~4C~51~53~54~4E
sets Volume Level Up:
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~4D~56~4C~55~50
sets Volume Level Down:
49~53~43~50~00~00~00~10~00~00~00~0A~01~00~00~00~21~31~4D~56~4C~44~4F~57~4E
sets Volume Level Up 1dB Step:
49~53~43~50~00~00~00~10~00~00~00~09~01~00~00~00~21~31~4D~56~4C~55~50~31
sets Volume Level Down 1dB Step:
49~53~43~50~00~00~00~10~00~00~00~0B~01~00~00~00~21~31~4D~56~4C~44~4F~57~4E~31
gets the Volume Level:
49~53~43~50~00~00~00~10~00~00~00~0A~01~00~00~00~21~31~4D~56~4C~51~53~54~4E

NET TUNE COMMANDS
FF KEY (CONTINUOUS*):
49~53~43~50~00~00~00~10~00~00~00~08~01~00~00~00~21~31~4E~54~43~46~46
REW KEY (CONTINUOUS*):
49~53~43~50~00~00~00~10~00~00~00~09~01~00~00~00~21~31~4E~54~43~52~45~57
REPEAT KEY:
49~53~43~50~00~00~00~10~00~00~00~0C~01~00~00~00~21~31~4E~54~43~52~45~50~45~41~54
RANDOM KEY:
49~53~43~50~00~00~00~10~00~00~00~0C~01~00~00~00~21~31~4E~54~43~52~41~4E~44~4F~4D
DISPLAY KEY:
49~53~43~50~00~00~00~10~00~00~00~0D~01~00~00~00~21~31~4E~54~43~44~49~53~50~4C~41~59
ALBUM KEY:
49~53~43~50~00~00~00~10~00~00~00~0B~01~00~00~00~21~31~4E~54~43~41~4C~42~55~4D
ARTIST KEY:
49~53~43~50~00~00~00~10~00~00~00~0C~01~00~00~00~21~31~4E~54~43~41~52~54~49~53~54
GENRE KEY:
49~53~43~50~00~00~00~10~00~00~00~0B~01~00~00~00~21~31~4E~54~43~47~45~4E~52~45
PLAYLIST KEY:
49~53~43~50~00~00~00~10~00~00~00~0E~01~00~00~00~21~31~4E~54~43~50~4C~41~59~4C~49~53~54


Rough translation of header:
ISCP
49 53 43 50

Header Size
00 00 00 10

Data Size
00 00 00 14

Version
01

Padding if needed
00 00 00


Hope this helps.

D.
Post 8 made on Tuesday November 2, 2010 at 23:48
Barry Gordon
Founding Member
Joined:
Posts:
August 2001
2,157
The only thing that ever exists in a computer memory are numbers. The only thing that ever gets sent between two computers using any method of communications (TCP, UDP, IR, RS232) is numbers. As far as a computer is concerned there is no such thing as ASCII, there is no such thing as HEX, there is no such thing as strings, no pictures, no music, nothing except numbers.

How we talk about those numbers, how we write down those numbers in an attempt to convey understanding is where many get confused. Those are just representations of the data. How we assign those numbers to represent real world quantities are just manifestations of our minds and agreement to do it uniformly.

We build transducers, hardware, to convert those numbers into pictures and sounds, and we do so by convention and agreement. We build other transducers to go the other way converting sounds and pictures into numbers for the computer to accept.

The data will always be numbers, and if we look at the memory or the data stream as a sequence of bytes, then each byte contains a number in the range of 0-255. We could look at the entire memory or an entire data stream as one very large number but that makes it very hard to discuss let alone write down.

It is not hard at the lower levels it is only hard we we are ambiguous in how we describe the numbers.
Post 9 made on Wednesday November 3, 2010 at 04:33
sWORDs
Long Time Member
Joined:
Posts:
November 2006
373



After reading the specs I'm seeing a better regex, If I've got some time left tonight I'll test it.
 

/(ISCP)([\x00-\x7F][\x00-\x7F][\x00-\x7F][\x00-\x7F])([\x00-\x7F][\x00-\x7F][\x00-\x7F][\x00-\x7F])(\x01)(\x00\x00\x00)(!)(0-9)([A-Z][A-Z][A-Z])([\x00-\x7F].*)(\x1a\r\n)/

 [0] = all
 [1] = eISCPHeader    = ISCP (ISCP)
 [2] = HeaderSize     = \x00\x00\x00\x10 ([\x00-\x7F][\x00-\x7F][\x00-\x7F][\x00-\x7F])
 [3] = DataSize       = \x00\x00\x00\x08 ([\x00-\x7F][\x00-\x7F][\x00-\x7F][\x00-\x7F])
 [4] = Version        = \x01 (\x01)
 [5] = Reserved       = \x00\x00\x00 (\x00\x00\x00)
 [6] = StartCharacter = ! (!)
 [7] = DestUnittype   = 1 (0-9)
 [8] = ISCPCommand    = PWR ([A-Z][A-Z][A-Z])
 [9] = ISCPParameter  = 01 ([\x00-\x7F].*)
[10] = EndCharacter   = \x1a\r\n
(\x1a\r\n)

This way you could switch [8] and parse [9] and would only need to work with ASCII. [10] could be \x1a or \x1a\r or \x1a\r\n depending on the device, it might even just be \r, \n or \r\n as I see people using that aswell, however that's not how it's documented and I'm suspecting they still have unreadable characters.

Last edited by sWORDs on November 3, 2010 09:24.
OP | Post 10 made on Wednesday November 3, 2010 at 10:04
rap
Long Time Member
Joined:
Posts:
September 2006
59

In an email from Integra I was provided with the exact header/string layout. Each is 24 bytes according to the document, however each string I receive is exactly 26 bytes long and very consistent. I've just been monitoring the async events from the Integra and parsing the string. I can't believe they omitted this from the Excel spreadsheet, without it I would really be lost!

I'm happy to post it but I can't figure out how insert a picture on the forum, there is no way to "browse" to the file location to upload...different story.

My, albeit, simple brute force technique that I'm experimenting with works.
substr(indexOf("!") + 2, 3) find the "code" - e.g. "PWR" = power
substr(indexOf("!") + 5, 2) find the "value" - e.g. "00" = off...

I do what you suggest, sWORDs, Switch on (code) and use the value accordingly.

Volume levels come back as hex so off to the hex converter next.

I'm still working to understand how the a.match() works exactly. It's pretty cryptic but looks compact and a bit more elegant that what I have done.

Post 11 made on Wednesday November 3, 2010 at 10:24
sWORDs
Long Time Member
Joined:
Posts:
November 2006
373
26 looks right:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
49 53 43 50 00 00 00 10 00 00 00 08 01 00 00 00 21 31 50 57 52 30 30 1A 0D 0A


That would mean end character is \x1a\r\n

Test if:
System.print(result.charCodeAt(result.length-3));
System.print(result.charCodeAt(result.length-2));
System.print(result.charCodeAt(result.length-1));

Gives:
26
13
10

Last edited by sWORDs on November 3, 2010 10:36.
Post 12 made on Wednesday November 3, 2010 at 10:25
Sogliphy
Long Time Member
Joined:
Posts:
July 2007
186
result = "";
socket.onData = function() {
result = socket.read();
//result += socket.read(); //tried += and =, same result
System.print("Data: " + result);
}

Note: even though this might work in most cases, over TCP there really is NO guarantee that a "packet" (TCP is a stream-oriented protocol, not packet-oriented like UDP) will be delivered as a whole in 'socket.read()'.

It is possible that sometimes you will only receive part of a "packet", or multiple packets, or a combination of both. This depends on the TCP/IP stack of both endpoints, as well as on which IP packets are dropped during transmission.

Hence, you should do something like result += socket.read(), and strip out a complete "packet" from result, once that is processed.
OP | Post 13 made on Wednesday November 3, 2010 at 11:57
rap
Long Time Member
Joined:
Posts:
September 2006
59
sWORDs, you are correct. The EOL is dependent on model of equipment and can be either 1, 2, or 3 characters which is in the documentation that you also posted above. The model DHC 40.1 appears to use 3 chars so it's a consistent 26 bytes.

Sogliphy, thanks for the info. This makes reading/parsing the data a bit more complicated.
If async event one sends only 13 of the 26 bytes for example, I presume that on each onData() it's possible to get some or all of the remaining 13 bytes plus the beginning of the next async event. I'm presuming that the device will keep sending data until events stop. I'm also presuming that the device is sending in 26 byte "chunks" and although that is what's happening there no reason to presume that. Do I understand that correctly?

And after each message parsing, var result will need to be reset somehow (either to "" or the beginning of the next message) or it will continue to concatenate.

edit: I just gave Jon Welfringer's TCP simulator mod a try. Wow, isn't that nice. Thank you Jon. RC is a terrific resource. I hope to be able to give back one day.

So, with the simulator installed, the first connect the device returned a 26 char string and then two 52 char strings! My parsing routine fails, it only finds the first message. Back to the drawing board on this. However, it's still pretty consistent send/receiving 26 byte chunks/"packets."

Last edited by rap on November 3, 2010 12:51.
Post 14 made on Wednesday November 3, 2010 at 18:29
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
Not that much more difficult. ;-) You clear the receive buffer on connect and then you append during read. After that you "peel off" a single message. To do this, you should likely "bone up" on String.split() and the Array.join(). You will need to do a split on '\n'. You will then need to use String.substring() to adjust the data buffer to remove the characters you processed. ;-)
Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 15 made on Wednesday November 3, 2010 at 18:59
sWORDs
Long Time Member
Joined:
Posts:
November 2006
373

Wireshark ethernet frame data part (standby on an Onkyo 1008):

49 53 43 50 00 00 00 10 00 00 00 0a 01 00 00 00 21 31 50 57 52 30 30 1a 0d 0a



Code (you will need to write the .parse functions and a send function, it's quick and dirty but working, just use the original remote or turn the volume knob):
eISCP = {
 IP: "192.168.1.100",
 Port: "60128",
    Header: "ISCP",
    HeaderSize: "[\x00-\xFF][\x00-\xFF][\x00-\xFF][\x00-\xFF]",
    DataSize: "[\x00-\xFF][\x00-\xFF][\x00-\xFF][\x00-\xFF]",
    Version: "\x01",
    Reserved: "\x00\x00\x00",
    StartCharacter: "!",
    DestUnittype: "1",
    ISCPCommand: "[A-Z][A-Z][A-Z]",
    ISCPParameter: "[\x00-\x7F].*",
    EndCharacter: "\x1a\r\n"
};
eISCP.RegEx = new RegExp("("+eISCP.Header+")("+eISCP.HeaderSize+")("+eISCP.DataSize+")("+eISCP.Version+")("+eISCP.Reserved+")("+eISCP.StartCharacter+")("+eISCP.DestUnittype+")("+eISCP.ISCPCommand+")("+eISCP.ISCPParameter+")("+eISCP.EndCharacter+")");
eISCP.Socket = new TCPSocket(false);
eISCP.Socket.connect(eISCP.IP, eISCP.Port, 3000);
eISCP.Socket.onData = function(){
    v = eISCP.Socket.read();
    x = v.match(eISCP.RegEx);
    if (x) {
        switch (x[8]) {
            case "PWR":
                eISCP.SystemPower.Status = eISCP.SystemPower.Parse(x[9]);
                break;
            case "AMT":
                eISCP.AudioMuting.Status = eISCP.AudioMuting.Parse(x[9]);
                break;
            case "SPA":
                eISCP.SpeakerA.Status = eISCP.SpeakerA.Parse(x[9]);
                break;
            case "SPB":
                eISCP.SpeakerB.Status = eISCP.SpeakerB.Parse(x[9]);
                break;
            case "SPL":
                eISCP.SpeakerLayout.Status = eISCP.Layout.Parse(x[9]);
                break;
        }
    }
};
eISCP.Socket.Reconnect = function(){
    eISCP.Socket = new TCPSocket(false);
    eISCP.Socket.connect(eISCP.IP, eISCP.Port, 3000);
};
eISCP.Socket.onIOError = function(){
    Activity.scheduleAfter(5000, eISCP.Socket.Reconnect);
};
eISCP.Socket.onClose = function(){
    Activity.scheduleAfter(5000, eISCP.Socket.Reconnect);
};

Last edited by sWORDs on November 3, 2010 22:16.
Page 1 of 2


Jump to


Protected Feature Before you can reply to a message...
You must first register for a Remote Central user account - it's fast and free! Or, if you already have an account, please login now.

Please read the following: Unsolicited commercial advertisements are absolutely not permitted on this forum. Other private buy & sell messages should be posted to our Marketplace. For information on how to advertise your service or product click here. Remote Central reserves the right to remove or modify any post that is deemed inappropriate.

Hosting Services by ipHouse