Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Help adding STX and ETX to data string in Perl

by CuriousMark (Initiate)
on Jul 19, 2022 at 03:58 UTC ( [id://11145580]=perlquestion: print w/replies, xml ) Need Help??

CuriousMark has asked for the wisdom of the Perl Monks concerning the following question:

Sending a data string from Perl script that requires Start (0x02) and End (0x03) of Text data string layout is

#### STX 1 byte (0x02) #### byte count 8 bytes, leading zeros, inclusive + of wrapper (payload length + 18) #### reserved 8 bytes, all zeros (required and +reserved for future use) #### payload (Data record to send) #### ETX 1 byte (0x03)
Results of code below are not STX = 0x02 and ETX = 0x03 but $hex02_ascii = E2 98 BB $hex02_ascii = E2 99 A5 example: ☻0000052500000000<payload>♥ Note "byte count" is correct as is the "reserved"

my $hex02 = 0x2; my $hex03 = 0x3; my $hex02_ascii = sprintf "%c", $hex02; my $hex03_ascii = sprintf "%c", $hex03; my $MsgLgth = 0; my $Message = " "; chomp $Message; $Message = $_; # Calculate Length of Message $MsgLgth = length($_)+18; if ( $MsgLgth < 100 ) { $Message = $hex02_ascii . '000000' . $MsgLgth . '00000000' . $Message +. $hex03_ascii; }elsif ( $MsgLgth < 1000 ) { $Message = $hex02_ascii . '00000' . $MsgLgth . '00000000' . $Message +. $hex03_ascii; }elsif ( $MsgLgth < 10000 ) { $Message = $hex02_ascii . '0000' . $MsgLgth . '00000000' . $Message +. $hex03_ascii; }elsif ( $MsgLgth < 100000 ) { $Message = $hex02_ascii . '000' . $MsgLgth . '00000000' . $Message +. $hex03_ascii; }elsif ( $MsgLgth < 1000000 ) { $Message = $hex02_ascii . '00' . $MsgLgth . '00000000' . $Message +. $hex03_ascii; }else{ # Max length is 300000 # If hit here, too long ... by a LOT print "Formated Message exceeds MaxMessageLength\n\n";

Replies are listed 'Best First'.
Re: Help adding STX and ETX to data string in Perl
by jwkrahn (Abbot) on Jul 19, 2022 at 05:19 UTC
    my $Message = $_; # Calculate Length of Message my $MsgLgth = 18 + length $Message; if ( $MsgLgth > 9 && $MsgLgth < 1_000_000 ) { $Message = sprintf "\x2%08d00000000%s\x3", $MsgLgth, $Message } else{ # Max length is 300_000 # If hit here, too long ... by a LOT print "Formated Message exceeds MaxMessageLength\n\n"; }
Re: Help adding STX and ETX to data string in Perl
by AnomalousMonk (Archbishop) on Jul 19, 2022 at 04:45 UTC

    So why not just something like

    Win8 Strawberry 5.8.9.5 (32) Tue 07/19/2022 0:41:07 C:\@Work\Perl\monks >perl use strict; use warnings; use Data::Dump qw(dd); use constant MaxMessageLength => 300_000; my $Message = 'how now brown cow'; my $MsgLgth = length($Message)+18; $MsgLgth <= MaxMessageLength or die sprintf 'Formatted Message len %ld exceeds MaxMessageLength + %ld', $MsgLgth, MaxMessageLength ; $Message = sprintf "\x02%08d00000000%s\x03", $MsgLgth, $Message; dd $Message; ^Z "\x020000003500000000how now brown cow\3"


    Give a man a fish:  <%-{-{-{-<

Re: Help adding STX and ETX to data string in Perl
by etj (Deacon) on Jul 19, 2022 at 14:39 UTC
    Both the other replies look like they'll work! I'd advise taking either of them, and turning them into a function that takes in the text to encode and the maximum length, and either returns the correctly-encoded string, or does a die on error. Something like (modifying jwkrahn's version):
    use constant MaxMessageLength => 300_000; sub stx_encode { my ($Message, $max_length) = @_; my $MsgLgth = 18 + length $Message; die "Formatted message exceeds MaxMessageLength" if $MsgLgth >= $max +_length; return sprintf "\x2%08d00000000%s\x3", $MsgLgth, $Message; } print stx_encode('hello', MaxMessageLength);
    The benefit of making a function is it's more widely reusable, and is generally better practice as one can write (and test) each piece of a program bit by bit. Edit: and creating stx_decode would be an obvious step, and then you'd have two little functions that nicely wrap that format.
Re: Help adding STX and ETX to data string in Perl
by BillKSmith (Monsignor) on Jul 20, 2022 at 22:48 UTC
    Let sprintf do all the work.
    use strict; use warnings; sub myMessage { my $payload = shift; my $format = "\N{STX}" . '%08u' # Byte count . '0' x 8 # Reserved . '%s' # Pay load . "\N{ETX}" ; return sprintf $format, 18 + length($payload), $payload; } my $result = myMessage("<PAYLOAD>"); print $result, "\n"; print unpack 'H*', $result;

    RESULT:

    >perl CuriousMark.pl .0000002700000000<PAYLOAD>. 02303030303030323730303030303030303c5041594c4f41443e03 >

    Note: Non-printing characters replaced with '.' in forum only. Hex dump is accurate.

    Bill

      Hex encoding is very inefficient to handle because it's a non-contiguous part of the ASCII table. I usually use "cavcode"(*), because that's easy to implement in most programming languages, including in C for stuff like Arduinos. And of course it works very well with framing bytes.

      sub frame2packet { my @frame = @_; my $packet = ''; foreach my $byte (@frame) { my $lowbyte = ($byte & 0x0f) + 65; my $highbyte = ($byte >> 4) + 65; $packet .= chr($highbyte); $packet .= chr($lowbyte); } return $packet; } sub packet2frame { my $packet = shift; my @chars = split//, $packet; my @frame = (); # Decode to bytes while(@chars) { my $high = shift @chars; my $low = shift @chars; my $val = ((ord($high) - 65) << 4) + (ord($low) - 65); push @frame, $val; } return @frame; }

      Writing, for example, the counterpart encoder for Arduino is also quite easy. No need for a lookup table and stuff, this can be done with very low RAM usage:

      highbyte = 0x02; Serial.write(highbyte); for(inoffs = 0; inoffs < PKT_LEN; inoffs++) { intmpbyte = inpacket[inoffs]; highbyte = ((intmpbyte >> 4) & 0x0f) + 65; lowbyte = (intmpbyte & 0x0f) + 65; Serial.write(highbyte); Serial.write(lowbyte); } highbyte = 0x03; Serial.write(highbyte);

      (*) cavcode stands for "cavac encode". Yes, named it after myself, and nobody can stop me.

      PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
        Note: There is absolutely no "hex encoding" in my solution. I added a hex dump of my result in order to display the control characters (and ASCII zero's) unambiguously in this forum.
        Bill
Re: Help adding STX and ETX to data string in Perl
by jmlynesjr (Deacon) on Jul 19, 2022 at 22:54 UTC

    If you are going to send this message across a serial link, you should consider adding a checksum or CRC-16. Also, if you send a preamble of SYN characters, the protocol can be made to recover from mangled messages. I've used this many times across serial links.

    James

    There's never enough time to do it right, but always enough time to do it over...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11145580]
Approved by Discipulus
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-04-25 07:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found