B4J Question How to send hex via rs232 ?

amorosik

Expert
Licensed User
With this Serial Connector base code, how to send hex caracthers via rs232?


1741286477184.png
 

amorosik

Expert
Licensed User
Have modified the code for recognize the hex in message textbox, and visualize in hex mode on txtLog
But, the received string seem to be less char than char sent from device to pc
Comparing RealTerm (20 char received, correct) with Serial Connector (13 char received, not correct) show the differences

The code is:
B4X:
#Region  Project Attributes
    #MainFormWidth: 800
    #MainFormHeight: 600
#End Region
#CustomBuildAction: After Packager, %WINDIR%\System32\robocopy.exe, ..\ temp\build\bin\ jssc.dll
'version 1.20
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private txtMessage As TextField
    Private cmbPort As ComboBox
    Private btnOpen As Button
    Private btnSend As Button
    Private txtLogs As TextArea
    Private astream As AsyncStreams
    Private serial As Serial
    Private chkReset As CheckBox
    Private const BAUDRATE As Int = 9600
    Private const settingsFile As String = "Settings.txt"
    Private udpListener As UDPSocket
    Private connected As Boolean
    Private PortsNames As B4XOrderedMap
    Private DataFolder As String
    
    Private isHexMode As Boolean = False ' Indica se l'ultimo comando è in formato esadecimale
End Sub


Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("1")
    MainForm.Show
    DataFolder = File.DirData("SerialConnector")
    serial.Initialize("")
    Wait For (GetPortsNames) Complete (unused As Boolean)
    cmbPort.Items.AddAll(PortsNames.Values)
    If File.Exists(File.DirApp, settingsFile) Then
        Dim m As Map = File.ReadMap(File.DirApp, settingsFile)
        If m.ContainsKey("port") Then
            Dim SavedPort As String = m.Get("port")
            If PortsNames.ContainsKey(SavedPort) Then
                cmbPort.SelectedIndex = cmbPort.Items.IndexOf(PortsNames.Get(SavedPort))
            End If
        End If
        chkReset.Checked = m.Get("reset")
    End If
    If cmbPort.SelectedIndex = -1 Then cmbPort.SelectedIndex = cmbPort.Items.Size - 1
    udpListener.Initialize2("udp", 51042, 8192, True, True)
End Sub

Sub GetPortsNames As ResumableSub
    PortsNames.Initialize
    For Each port As String In serial.ListPorts
        PortsNames.Put(port, port) 'default names
    Next
    File.Copy(File.DirAssets, "ListPorts.exe", DataFolder, "ListPorts.exe")
    Dim shl As Shell
    shl.Initialize("shl", File.Combine(DataFolder, "ListPorts.exe"), Null)
    shl.Run(5000)
    Wait For shl_ProcessCompleted (Success As Boolean, ExitCode As Int, StdOut As String, StdErr As String)
    If Success And ExitCode = 0 Then
        For Each line As String In Regex.Split(CRLF, StdOut)
            Log(line)
            Dim i As Int = line.IndexOf(" ")
            If i = -1 Then Continue
            Dim port As String = line.SubString2(0, i)
            Dim Description As String = line.Trim
            If PortsNames.ContainsKey(port) Then PortsNames.Put(port, Description)
        Next
    End If
    Return True
End Sub


Sub btnOpen_Action
    OpenAction(True)
End Sub

Sub OpenAction(User As Boolean)
    If connected Then
        connected = False
        astream.Close
        serial.Close
        btnOpen.Text = "Open"
        Return
    End If
    If User Then
        OpenAfterDelay
    Else
        Sleep(8000)
        OpenAfterDelay
    End If
    
End Sub

Private Sub OpenAfterDelay
    If cmbPort.SelectedIndex = -1 Then Return
    Try
        serial.Open(PortsNames.Keys.Get(cmbPort.SelectedIndex))
        If chkReset.Checked Then
            serial.SetParams(BAUDRATE, 8, 1, 0)
        Else
            Dim jo As JavaObject = serial
            jo = jo.GetField("sp")
            jo.RunMethod("setParams", Array(BAUDRATE, serial.DATABITS_8, serial.STOPBITS_1, serial.PARITY_ODD, False, False))
        End If
        astream.Initialize(serial.GetInputStream, serial.GetOutputStream, "astream")
        btnSend.Enabled = True
        btnOpen.Text = "Close"
    Catch
        Log(LastException)
        fx.Msgbox(MainForm, "Failed to open port", "")
    End Try
    connected = True
    btnOpen.Enabled = connected
    btnClear_Action
End Sub


Sub btnSend_Action
    Dim text As String = txtMessage.Text.Trim
    Dim data() As Byte ' Array per contenere i dati da inviare

    Try
        ' Controlla se la stringa contiene valori esadecimali (0xFF) separati da spazi
        If text.Contains("0x") Then
            isHexMode = True ' Imposta la modalità esadecimale
            Dim parts() As String = Regex.Split(" ", text) ' Divide la stringa in base agli spazi
            data = Array As Byte() ' Inizializza l'array
            For Each part As String In parts
                If part.StartsWith("0x") Then
                    Dim value As Int = Bit.ParseInt(part.SubString(2), 16) ' Converte ogni valore esadecimale
                    
                    Dim newData(data.Length + 1) As Byte
                    For i = 0 To data.Length - 1
                        newData(i) = data(i)
                    Next
                    newData(data.Length) = value
                    data = newData
                    
                    'data = data & Array As Byte(value) ' Aggiunge il byte all'array
                Else
                    
                    Log("Formato errato: " & part)
                    fx.Msgbox(MainForm, "Formato non valido. Usa stringhe ASCII o 0xNN separati da spazi.", "Errore")
                    Return
                End If
            Next
        Else
            ' Tratta la stringa come valori ASCII continui
            isHexMode = False ' Imposta la modalità esadecimale
            data = text.GetBytes("utf8") ' Converte la stringa ASCII in un array di byte
        End If

        ' Invia i dati tramite AsyncStreams
        astream.Write(data)
        Log("Inviati dati: " & text)
    Catch
        Log("Errore nella conversione o nell'invio dei dati: " & text)
        fx.Msgbox(MainForm, "Errore nella conversione o nell'invio dei dati. Controlla il formato della stringa.", "Errore")
    End Try

    txtMessage.SelectAll
    txtMessage.RequestFocus
End Sub

Sub txtMessage_Action
    btnSend_Action
End Sub

Sub AStream_NewData (Buffer() As Byte)
    ' Converte tutti i byte del buffer in una stringa (assumendo che siano codificati in UTF-8)
    Log("Char=" & Buffer.Length & "   " &  BytesToString(Buffer, 0, Buffer.Length, "utf8"))
    
    Dim output As StringBuilder
    output.Initialize

    If isHexMode Then
        ' Visualizza i dati in formato esadecimale
        For Each b As Byte In Buffer
            Dim unsignedValue As Int = Bit.And(0xFF, b) ' Converte il byte in valore senza segno
            Dim hexChar As String = Bit.ToHexString(unsignedValue) ' Converte in esadecimale
            
            ' Aggiunge lo zero iniziale se il valore è di una sola cifra
            If hexChar.Length = 1 Then
                hexChar = "0" & hexChar
            End If
            
'            output.Append("0x").Append(hexChar.ToUpperCase).Append(" ") ' Aggiunge "0x" e separa con uno spazio
            output.Append(hexChar.ToUpperCase).Append(" ") ' Aggiunge "0x" e separa con uno spazio
        Next
    Else
        ' Visualizza i dati come stringa ASCII
        output.Append(BytesToString(Buffer, 0, Buffer.Length, "utf8")) ' Converte i byte in stringa ASCII
    End If

    ' Aggiunge il risultato alla TextArea
    txtLogs.Text = txtLogs.Text & output.ToString & CRLF
    txtLogs.SetSelection(txtLogs.Text.Length, txtLogs.Text.Length)
End Sub

Sub AStream_Error
    Log("error")
End Sub

Sub AStream_Terminated
    Log("terminated")
End Sub


Sub btnClear_Action
    txtLogs.Text = ""
End Sub

Sub MainForm_Closed
    Dim m As Map = CreateMap("reset": chkReset.Checked)
    If cmbPort.SelectedIndex > -1 Then m.Put("port", PortsNames.Keys.Get(cmbPort.SelectedIndex))
    File.WriteMap(File.DirApp, settingsFile, m)
End Sub

Private Sub UDP_PacketArrived (Packet As UDPPacket)
    Try
        Dim s As String = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "utf8")
        If s.StartsWith("B4R") = False Then Return
        Dim msg() As String = Regex.Split(",", s)
        If msg.Length < 3 Or cmbPort.SelectedIndex = -1 Then Return
        If msg(1) = PortsNames.Keys.Get(cmbPort.SelectedIndex) Then
            If connected <> msg(2) Then
                OpenAction(False)
                
            End If
        End If
    Catch
        Log(LastException)
    End Try
End Sub
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Longtime User
Your question is a bit confusing. A rs232 is a device on the connection layer that sends a byte bit by bit over the rs232 line filled with start, stop and parity bits at a certain speed (the baud rate). The hexadecimal 0x10 text string is on the presentation layer the textual representation of the byte to be sent without the start, stop and parity bits. If the program is made to only use the hexadecimal byte value (without the 0x) then you will have to convert the hex string from the presentation layer to the byte value. On top of that: an ASCII terminal only uses one byte, a PC uses the extended character sequence that uses two bytes. As long as it is not clear to which device you are sending something and what it must comply with, there is no answer possible to your question.
 
Upvote 0

amorosik

Expert
Licensed User
The start bit, stop bit, and parity, have no importance for the purposes of this question
If I write that I send 0x10 it seems clear to me that I am talking about the DATA BYTE
A sequence of bits to which the serial port hardware will add the start bit, the parity bit (if set) and the stop bit
Obviously, the sender and the receiver must do so with the exact same parameters
The presentation layer has no importance, if my sensor responds to each request with a certain number X of bytes, and I 'see' them physically pass (with an oscilloscope) on the physical line, then I expect that X bytes will also be received on the software side
It does not matter which device I am using, and this is clearly visible on the video linked in the previous post on Comparing Realterm
But if it is easier to imagine what is physically there then we can assume that each device indicated as SENSx is a computer + rs232-rs485 converter
On board the SENSx computer there is a program installed that waits for requests from the master PC (the notebook in the figure)
The master PC sends a request (composed of 3 bytes as per the initial example) to a certain computer (the address of the computer is contained in the second byte sent) and a response is expected When the computer receiving the request receives the command, it responds with a sequence of bytes, which can have any value, for this reason I have indicated the two extremes 0x00 and 0xFF
Which obviously are characters that cannot be represented on the video, but this is another matter, they must not be put on the video
The point is another, and it is that SENSx respond with 20 characters, and I am sure of this because I see them from the oscilloscope and I receive them correctly if I use RealTerm, while if I use the code taken from Serial Connector and modified, which I attached to the second post, I only receive 13 characters


1741318320874.png
 
Last edited:
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Longtime User
Serial driver:
Private serial As Serial
It has been four decades since I have been involved with this subject. Based on the correct settings on the PC and the connected SENS devices, the software used remains. Maybe a few stupid questions, but:
  1. Which serial driver are you using?
  2. Is it the latest version?
  3. Which Java version are you using in the IDE?
  4. Does the problem also occur when you use the IDE with Java 1.8 Open JDK version?
  5. If the problem does not occur with Open Java 1.8, with which Java version does the problem occur?
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Longtime User
Upvote 0
Top