SerialPort copy string instead of file

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
shokarta
Posts: 13
Joined: 14 Oct 2012 05:54

SerialPort copy string instead of file

#1 Post by shokarta » 28 Aug 2020 05:05

Dear all,

im using this so far:

Code: Select all

mode COM3 BAUD=9600 PARITY=n DATA=8
copy Ascii\5.chr \\.\COM3
copy Ascii\64.chr \\.\COM3
copy Ascii\33.chr \\.\COM3
copy Ascii\0.chr \\.\COM3
copy Ascii\154.chr \\.\COM3
which basicaly sends 5 chars into serial port.
each number (filename) represents ascii symbol (the number is DEC value, and inside each file is only one single character which stands for the symbol of the ascii DEC).

Example:
according to https://www.ascii-code.com/ the filename 64.chr contains only "@"

So im looking for a way to send those 5 characters as string, not as external file…

Is it posible somehow?

Thank you

elzooilogico
Posts: 122
Joined: 23 May 2016 15:39
Location: Spain

Re: SerialPort copy string instead of file

#2 Post by elzooilogico » 28 Aug 2020 08:26

have you tried

Code: Select all

echo hello>COM3
or

Code: Select all

set /p str=“hello" <nul >\\.\COM3
the diference here is that first writes hello plus CR+LF, and the second one does not.

penpen
Expert
Posts: 1864
Joined: 23 Jun 2013 06:15
Location: Germany

Re: SerialPort copy string instead of file

#3 Post by penpen » 29 Aug 2020 08:39

I think the main issue here is the NULL-byte (stored in "0.chr"), so you can't use single byte codepages to echo that value and have to workaround that.
I couldn't find a codepage that enables you to echo the whole byte sequence as a single string, but you might use a mix of ANSI and unicode characters:

Code: Select all

@echo off
setlocal enableExtensions enableDelayedExpansion
for /f "tokens=*" %%a in ('chcp') do for %%b in (%%a) do set "cp=%%~nb"
>nul chcp 65000
set "U_0005=+AAU-"
set "U_4021_009A=+IUCaAA-"

>nul chcp 850
(
	cmd /a /c"<nul set /p "=!U_0005!""
	cmd /u /c"<nul set /p "=!U_4021_009A!""
) >> COM3

>nul chcp %cp%
goto :eof
Note that i defined all those UTF16-LE encoded characters using a base64-representation in UTF-7 (codepage 65000).
For further information, see:
https://en.wikipedia.org/wiki/UTF-7 and
https://en.wikipedia.org/wiki/Base64.
Also note that codepage 850 is needed, because it is the only codepage that defines all ANSI codepoints x00-xff.


penpen

shokarta
Posts: 13
Joined: 14 Oct 2012 05:54

Re: SerialPort copy string instead of file

#4 Post by shokarta » 31 Aug 2020 00:59

Helo penpen,
this works like a charm, however this makes zero sence to me…

I was trying to break it up line by line to see what each line is doing, however no luck of understanding…
Would you please break it down with comments what each line does?

also, in the conversion, there are two things that does not make sence to me:
1) the "U_" always at the beginning stands for what?
2) as im writing bytes (5,64,33,0,154), from your lines i see you are acually passing only 3 bytes:

Code: Select all

cmd /a /c"<nul set /p "=!U_0005!""
cmd /u /c"<nul set /p "=!U_4021_009A!""
- which would be (5,33,0) ?

at the end, this probably would be just matter of me not understanding the line by line, so if I can kindly ask you to tear it down so I can understand?

Thank you!

shokarta
Posts: 13
Joined: 14 Oct 2012 05:54

Re: SerialPort copy string instead of file

#5 Post by shokarta » 31 Aug 2020 01:31

So lets say would need to send bytes (5,97,16,0,138,5,97,17,0,137,5,97,18,0,136), in order to convert it it would look like:
1) Express the character's Unicode numbers (UTF-16) in Binary:

Code: Select all

5	= 0x05	= 00000101
97	= 0x61	= 01100001
16	= 0x10	= 00010000
0	= 0x00	= 00000000
138	= 0x8A	= 10001010

5	= 0x05	= 00000101
97	= 0x97	= 01100001
17	= 0x11	= 00010001
0	= 0x00	= 00000000
137	= 0x89	= 10001001

5	= 0x05	= 00000101
97	= 0x97	= 01100001
18	= 0x12	= 00010010
0	= 0x00	= 00000000
136	= 0x88	= 10001000
2) Concatenate the binary sequences:

Code: Select all

00000101 01100001 00010000 00000000 10001010 00000101 01100001 00010001 00000000 10001001 00000101 01100001 00010010 00000000 10001000
3) Regroup the binary into groups of six bits, starting from the left:

Code: Select all

000001 010110 000100 010000 000000 001000 101000 000101 011000 010001 000100 000000 100010 010000 010101 100001 000100 100000 000010 001000
4) If the last group has fewer than six bits, add trailing zeros:
- does not in this case, so same as above

5) Replace each group of six bits with a respective Base64 code:

Code: Select all

000001	= B
010110	= W
000100	= E
010000	= Q
000000	= A
001000	= I
101000	= o
000101	= F
011000	= Y
010001	= R
000100	= E
000000	= A
100010	= i
010000	= Q
010101	= V
100001	= h
000100	= E
100000	= g
000010	= C
001000	= I
so adding this to your code it would look like:

Code: Select all

set "U_0005=+AAU-"
set "U_4021_009A=+IUCaAA-"
and

Code: Select all

cmd /a /c"<nul set /p "=!U_0005!""
cmd /u /c"<nul set /p "=!U_4021_009A!""
this is where I got lost…

so conversion above should be ok, how do i implement this to be sent via your script?

penpen
Expert
Posts: 1864
Joined: 23 Jun 2013 06:15
Location: Germany

Re: SerialPort copy string instead of file

#6 Post by penpen » 31 Aug 2020 15:12

shokarta wrote:
31 Aug 2020 00:59
1) the "U_" always at the beginning stands for what?
It has no special purpose - my first name starts with an U and that way i could list both variables at the same time using the command "set U_" (without doublequotes)

Also both labels do contain data with different semantics - which probably is very confusing (sorry for that):
U_0005 contains the unicode character U+0005 and should be the character that under codepage 850 is mapped to byte 0x05 (*).
U_4021_009A contains two unicode character, which UCS-2 representation is the byte sequence 40 21 00 9A, so that are U+2140 and U+9A00.

(*) A look at codepage 850 reveals, that i used the wrong value there... - the correct character i should have used instead is U+2663, see:
https://de.wikipedia.org/wiki/Codepage_850.
Luckily it works, which i suspect depends on a faulty behaviour of cmd.exe - so that might stop working at any time when MS fix that.

You might lookup unicode characters here:
https://www.compart.com/de/unicode/U+2663

shokarta wrote:
31 Aug 2020 00:59
2) as im writing bytes (5,64,33,0,154), from your lines i see you are acually passing only 3 bytes:
No. That are three UCS-2 characters and each of them is 2 bytes long.
The command "cmd /a /c..." starts a new cmd.exe instance which outputs characters in ANSI encoding.
The command "cmd /u /c..." starts a new cmd.exe instance which outputs characters in UCS-2 encoding.

So the first "cmd/a" i used outputs the byte 0x05 (by accident :roll: ), while the other command sends 2 UCS-2 characters to stdout (which was redirected to COM3).

shokarta wrote:
31 Aug 2020 00:59
at the end, this probably would be just matter of me not understanding the line by line, so if I can kindly ask you to tear it down so I can understand?
The idea is to use UTF-7 replacement base64 encoding to load Unicode characters into environment variables.
Then single characters should be mapped by codepage 850 to the byte that should be send to COM3 (using cmd/a).
Double-byte-characters are send to COM3 using UCS-2 encoding.

To get to the base 64 strings you need, you just have to reverse the process.
Note that this method can't use the NULL character U+0000.
If you are using varying byte-sequences, then in some instances you can avoid that by splitting the string in the right places, in others it is impossible:
- possible instance sample (hex) --> splited into: 01 02 00 00 03 04 --> 01, 02 00, 00 03, 04
- impossible instance sample (hex): 00 00 01 02

You should always be aware of that issue. So i would still make use of the file "0.chr".

Your example could be processed like that:

Code: Select all

@echo off
setlocal enableExtensions enableDelayedExpansion
for /f "tokens=*" %%a in ('chcp') do for %%b in (%%a) do set "cp=%%~nb"
:: define UTF16-LE characters using UTF-7
:: result byte sequence (decimal) : 5, 97, 16, 0, 138, 5, 97, 17, 0, 137, 5, 97, 18, 0, 136
:: result byte sequence (hex)     : 05 61 10 00 8A 05 61 11 00 89 05 61 12 00 88
:: possible split into code values:   05, 6110 008A 0561 1100 8905 6112 0088
:: apply ANSI and UCS_2 encoding  : U+2663, U+1061 U+8A00 U+6105 U+0011 U+0589 U+1261 U+8800
:: nibble sequence                :    2    6    6     3  ;    1    0    6     1    8    A     0    0    6     1    0    5     0    0    1     1    0    5     8    9    1     2    6    1     8    8    0     0
:: bit sequence (+padding: _)     : 0010 0110 0110  0011__; 0001 0000 0110  0001 1000 1010  0000 0000 0110  0001 0000 0101  0000 0000 0001  0001 0000 0101  1000 1001 0001  0010 0110 0001  1000 1000 0000  0000__
:: base 64 bit sequence           : 001001  100110  001100; 000100  000110  000110  001010  000000  000110  000100  000101  000000  000001  000100  000101  100010  010001  001001  100001  100010  000000  000000
:: base 64 encoding               :      J       m       M;      E       G       G       K       A       G       E       F       A       B       E       F       i       R       J       h       i       A       A
:: base64 string: +JmM- +EGGKAGEFABEFiRJhiAA-
>nul chcp 65000
set "ANSI_1=+JmM-"
set "UCS2_1=+EGGKAGEFABEFiRJhiAA-"

>nul chcp 850
(
	cmd /a /c"<nul set /p "=!ANSI_1!""
	cmd /u /c"<nul set /p "=!UCS2_1!""
) >> COM3

>nul chcp %cp%
goto :eof

penpen

Post Reply