Serial Port

Just starting out? Need help? Post your questions and find answers here.
Dano
User
User
Posts: 41
Joined: Fri Jul 16, 2004 4:20 am
Location: Edmonton, Ab, Canada

Serial Port

Post by Dano »

I work in CNC machining industry and would like to program a simple CNC send/receive program that gets the data from the serial port on the CNC control and sends data to it. I have searched the forum and have all the sample serial port code but I can't make sense of it, specifically hitting receive on my program and then waiting for the user to hit send on the control, and hitting send on my program and sending the program data from the file to the control. I have all the settings of the control and know the Open Serial Port command, but after that I am lost when it comes to the actual process of sending or receiving data. Anyone with experience with input would be most welcome, I am missing something simple I know, but if pointed in the right direction I don't think I am that far off.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Serial Port

Post by infratec »

Hi.

if you wait for serial input of the CNC, you have to use AvailableSerialInput() in a loop.
To avoid an unusable GUI, you should do all the serial stuff in an own thread.

For further hints I need a piece of code from you.

Bernd
Dano
User
User
Posts: 41
Joined: Fri Jul 16, 2004 4:20 am
Location: Edmonton, Ab, Canada

Re: Serial Port

Post by Dano »

Thank You for replying, after reading your explanation a light went on and I figured out the following code which works except for how to finish, the code uses the percent sign which signifies start and end of the program but I would rather wait until it is done sending and then strip the excess characters. I haven't done sending yet as I thought it would be the easier of the two.

Code: Select all

comID.l=0
a.l=0
b.l=0
c.l=0
Text.s=""
Buffer.b=0
Enumeration
  #Window_0
EndEnumeration
Enumeration
  #Text01
  #Label01
  #Gadget_50
 EndEnumeration

Procedure Open_Window_0()
  If OpenWindow(#Window_0, 0, 0, 370, 200, "Serial Communications", #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
    TextGadget(#Text01, 10, 30, 310, 20, "")
    ;EditorGadget(#Label01, 50, 30, 310, 100, #PB_Editor_ReadOnly)
    ButtonGadget(#Gadget_50, 10, 10, 80, 20, "Receive File")
 EndIf
EndProcedure
Open_Window_0()
Repeat
Event = WaitWindowEvent()

If Event = #PB_Event_Gadget
   
GadgetID = EventGadget()
    
If GadgetID = #Gadget_50

If OpenSerialPort(comID, "COM1", 9600, #PB_SerialPort_EvenParity, 7, 2, #PB_SerialPort_XonXoffHandshake, 1024, 1024) 
   SetGadgetText(#Text01, "Ready to Receive")
   If CreateFile(1, "c:\Text.txt")
Repeat 
        While AvailableSerialPortInput(comID) > 0
          
            
            If ReadSerialPortData(comID, @Buffer, 1) ; Read Byte
             SetGadgetText(#Text01, "Receiving") 
              Text = Text + Chr(Buffer)
            
            Receive = 1
            If Right(Text,1)="%"
              a=a+1
              If a=2
                WriteString(1, Text)
                Break 2
               EndIf 
             EndIf 
             If Right(Text,1)=Chr(13)
               b=b+1
               If b=2
                 c=Len(Text)
                 Text=RemoveString(Text, Chr(13),c, 1)
                 b=0
                 WriteString(1, Text)
                 Text=""
               EndIf
               EndIf
          EndIf
          
  Wend
          
 
Until a=2 
        CloseFile(1)
          SetGadgetText(#Text01, "Finished")
Else
  MessageRequester("Information","Can not create the file!")
	
EndIf
 Else
    MessageRequester("Error", "Can't open the serial port: "+Port$)
  EndIf 

CloseSerialPort(0)

EndIf

EndIf

Until Event = #PB_Event_CloseWindow	

End
Last edited by Dano on Tue Jul 29, 2014 5:21 am, edited 1 time in total.
morosh
Enthusiast
Enthusiast
Posts: 329
Joined: Wed Aug 03, 2011 4:52 am
Location: Beirut, Lebanon

Re: Serial Port

Post by morosh »

I just made similar project, here is the code:
HTH

Code: Select all

EnableExplicit
Import  ""
  PB_Gadget_SendGadgetCommand(hWnd, EventType)
EndImport

Define comport.s, fname.s, ligne.s, a.s, b.s
Global xcur.f, ycur.f
Define.l Event, WindowID, GadgetID, EventType, EventMenu
Global Dim buftx.a(100)
Global Dim bufrx.a(100)
Global nrecv.a
Declare wait(x.a, str.s)
Declare sendincx(x.a)
Declare senddecx(x.a)
Declare sendincy(x.a)
Declare senddecy(x.a)
Declare sendincz(x.a)
Declare senddecz(x.a)

Declare sendincxl(x.u)
Declare senddecxl(x.u)
Declare sendincyl(x.u)
Declare senddecyl(x.u)
Declare sendinczl(x.u)
Declare senddeczl(x.u)

Declare gotoxy(x.f, y.f)

If Not OpenPreferences("config.txt")
  MessageRequester("Error","config.txt not found",#PB_MessageRequester_Ok)
  End
EndIf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
comport= ReadPreferenceString("COMPORT","comx")

If Not OpenSerialPort(0, comport, 9600, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1024, 1024)
  MessageRequester("Error","Can't open Serial Port",#PB_MessageRequester_Ok)
  End
EndIf
SerialPortTimeouts(0,100,100,10,10,100)
SetGadgetFont(#PB_Default, LoadFont(0, "Arial", 11))

OpenWindow(0, 100, 100, 800,600,"ROBOT DRILL 2014",#PB_Window_MinimizeGadget | #PB_Window_SizeGadget | #PB_Window_SystemMenu)  
ButtonGadget(0,50, 50,100,30,"AUTO", #PB_Button_Toggle)
ButtonGadget(1,200, 50,150,30,"GOTO ORIGIN")
TextGadget(2,400, 50,150,30,"")
ButtonGadget(10,50, 100,100,30,"X ++")
ButtonGadget(11,150, 100,100,30,"X - -")
ButtonGadget(12,50, 150,100,30,"Y ++")
ButtonGadget(13,150, 150,100,30,"Y - -")
ButtonGadget(14,50, 200,100,30,"Z ++")
ButtonGadget(15,150, 200,100,30,"Z - -")
TextGadget(#PB_Any, 275,105,100,30,"STEPs X:")
TextGadget(#PB_Any, 275,155,100,30,"STEPs Y:")
TextGadget(#PB_Any, 275,205,100,30,"STEPs Z:")
StringGadget(20,355,100,50,25,"100")
StringGadget(21,355,150,50,25,"100")
StringGadget(22,355,200,50,25,"100")
ButtonGadget(16,50, 250,200,30,"LOAD DRILL DATA")
PB_Gadget_SendGadgetCommand(GadgetID(0), #PB_EventType_LeftClick)
Repeat
  Event = WaitWindowEvent() ; This line waits until an event is received from Windows
  WindowID = EventWindow() ; The Window where the event is generated, can be used in the gadget procedures
  GadgetID = EventGadget() ; Is it a gadget event?
  EventType = EventType() ; The event type
  
  Select Event    
    Case #PB_Event_Gadget         ;Event = WaitWindowEvent()
      If GadgetID=0
        If GetGadgetState(0)=1
          SetGadgetText(0,"MANUAL")
          DisableGadget(10,0)
          DisableGadget(11,0)
          DisableGadget(12,0)
          DisableGadget(13,0)
          DisableGadget(14,0)
          DisableGadget(15,0)
          DisableGadget(16,0)
          DisableGadget(20,0)
          DisableGadget(21,0)
          DisableGadget(22,0)
        Else
          SetGadgetText(0,"AUTO")
          DisableGadget(10,1)
          DisableGadget(11,1)
          DisableGadget(12,1)
          DisableGadget(13,1)
          DisableGadget(14,1)
          DisableGadget(15,1)
          DisableGadget(16,1)
          DisableGadget(20,1)
          DisableGadget(21,1)
          DisableGadget(22,1)
        EndIf
      ElseIf GadgetID=10
        sendincxl(Val(GetGadgetText(20)))
      ElseIf GadgetID=11
        senddecxl(Val(GetGadgetText(20)))
      ElseIf GadgetID=12
        sendincyl(Val(GetGadgetText(21)))
      ElseIf GadgetID=13
        senddecyl(Val(GetGadgetText(21)))
      ElseIf GadgetID=14
        sendinczl(Val(GetGadgetText(22)))
      ElseIf GadgetID=15
        senddeczl(Val(GetGadgetText(22)))
      ElseIf GadgetID=16
        fname = OpenFileRequester("Drill data file", "drill_data.dri", "Drill (*.dri)|*.dri", 0)
        SetGadgetText(2,"Waiting origin")
        Delay(100)
        buftx(0)= %11000000
        WriteSerialPortData(0,@buftx(),1)
        xcur=0
        ycur=0
        wait($39,"origin reached")
        ReadFile(0,fname)

        ligne=ReadString(0)  
        a=StringField(ligne, 1, " ")
        b=StringField(ligne, 3, " ")

        sendincz(100)
        gotoxy(Val(a),0)          
        gotoxy(Val(a),Val(b))          
        gotoxy(0,Val(b))          
        gotoxy(0,0)          
        senddecz(100)

        While Not Eof(0)
          ligne=ReadString(0)  
          a=StringField(ligne, 1, " ")
          b=StringField(ligne, 3, " ")
          gotoxy(Val(a),Val(b))          
          sendincz(100)
          senddecz(100)
        Wend
        SetGadgetText(2,"End")
        buftx(0)= %11000001
        WriteSerialPortData(0,@buftx(),1)
                
      ElseIf GadgetID=1
        SetGadgetText(2,"Waiting origin")
        Delay(100)
        buftx(0)= %11000000
        WriteSerialPortData(0,@buftx(),1)
        xcur=0
        ycur=0
        wait($39,"origin reached")
      EndIf
      
  EndSelect
Until Event = #PB_Event_CloseWindow ; End of the event loop

Procedure wait(x.a, str.s)
  Repeat
    nrecv=AvailableSerialPortInput(0)
    If nrecv <> 0
      ReadSerialPortData(0,@bufrx(),1)
      If bufrx(0)=x
        SetGadgetText(2,str)
        Beep_(500,300)
        Break
      EndIf
    EndIf
    Delay(100)
  ForEver
EndProcedure

Procedure sendincx(x.a)
  buftx(0)= %10000001
  buftx(1)=x
  WriteSerialPortData(0,@buftx(),2)
  SetGadgetText(2,"Waiting inc x")
  wait($31,"inc x reached")
EndProcedure

Procedure senddecx(x.a)
  buftx(0)= %10000010
  buftx(1)=x
  WriteSerialPortData(0,@buftx(),2)
  SetGadgetText(2,"Waiting dec x")
  wait($32,"dec x reached")
EndProcedure

Procedure sendincy(x.a)
  buftx(0)= %10000100
  buftx(1)=x
  WriteSerialPortData(0,@buftx(),2)
  SetGadgetText(2,"Waiting inc y")
  wait($33,"inc y reached")
EndProcedure

Procedure senddecy(x.a)
  buftx(0)= %10001000
  buftx(1)=x
  WriteSerialPortData(0,@buftx(),2)
  SetGadgetText(2,"Waiting dec y")
  wait($34,"dec y reached")
EndProcedure

Procedure sendincz(x.a)
  buftx(0)= %10010000
  buftx(1)=x
  WriteSerialPortData(0,@buftx(),2)
  SetGadgetText(2,"Waiting inc z")
  wait($35,"inc z reached")
EndProcedure

Procedure senddecz(x.a)
  buftx(0)= %10100000
  buftx(1)=x
  WriteSerialPortData(0,@buftx(),2)
  SetGadgetText(2,"Waiting dec z")
  wait($36,"dec z reached")
EndProcedure

Procedure sendincxl(x.u)    ; x en 0.1 mm
  Define i.a, q.a, r.a
  x=4*x
  q=0
  r=x
  If x> 125
    q=x/125
    r= x % 125
  EndIf
  Debug "x="+Str(x)
  Debug "incx     q="+Str(q)
  Debug "incx     r="+Str(r)
  For i=1 To q
    sendincx(125)
  Next
  If r <> 0 : sendincx(r) : EndIf
EndProcedure

Procedure senddecxl(x.u)
  Define i.a, q.a, r.a
  x=4*x
  q=0
  r=x
  If x> 125
    q=x/125
    r= x % 125
  EndIf
  Debug "x="+Str(x)
  Debug "decx        q="+Str(q)
  Debug "decx        r="+Str(r)
  For i=1 To q
    senddecx(125)
  Next
  If r <> 0 : senddecx(r) : EndIf
EndProcedure

Procedure sendincyl(x.u)
  Define i.a, q.a, r.a
  x=4*x
  q=0
  r=x
  If x> 125
    q=x/125
    r= x % 125
  EndIf
  Debug "y="+Str(x)
  Debug "incy     q="+Str(q)
  Debug "incy     r="+Str(r)
  For i=1 To q
    sendincy(125)
  Next
  If r <> 0 : sendincy(r) : EndIf
EndProcedure

Procedure senddecyl(x.u)
  Define i.a, q.a, r.a
  x=4*x
  q=0
  r=x
  If x> 125
    q=x/125
    r= x % 125
  EndIf
  Debug "y="+Str(x)
  Debug "decy      q="+Str(q)
  Debug "decy      r="+Str(r)
  For i=1 To q
    senddecy(125)
  Next
  If r <> 0 : senddecy(r) : EndIf
EndProcedure

Procedure sendinczl(x.u)
  Define i.a, q.a, r.a
  x=4*x
  q=0
  r=x
  If x> 125
    q=x/125
    r= x % 125
  EndIf
  Debug "z="+Str(x)
  Debug "incz      q="+Str(q)
  Debug "incz      r="+Str(r)
  For i=1 To q
    sendincz(125)
  Next
  If r <> 0 : sendincz(r) : EndIf
EndProcedure

Procedure senddeczl(x.u)
  Define i.a, q.a, r.a
  x=4*x
  q=0
  r=x
  If x> 125
    q=x/125
    r= x % 125
  EndIf
  Debug "z="+Str(x)
  Debug "decz    q="+Str(q)
  Debug "decz    r="+Str(r)
  For i=1 To q
    senddecz(125)
  Next
  If r <> 0 : senddecz(r) : EndIf
EndProcedure

Procedure gotoxy(x.f, y.f)
  Define dx.f, dy.f
  dx=x-xcur
  dy=y-ycur
  Debug "dx="+Str(dx)
  Debug "dy="+Str(dy)
  If dx > 0
    sendincxl(dx*10)
  ElseIf dx < 0
    senddecxl(-dx*10)
  EndIf
  
  If dy > 0
    sendincyl(dy*10)
  ElseIf dy < 0
    senddecyl(-dy*10)
  EndIf
  xcur=x
  ycur=y  
EndProcedure

PureBasic: Surprisingly simple, diabolically powerful
Dano
User
User
Posts: 41
Joined: Fri Jul 16, 2004 4:20 am
Location: Edmonton, Ab, Canada

Re: Serial Port

Post by Dano »

Morosh,
Looks like you are actually controlling a drill through the serial port, but doesn't look like you need to receive a program like I do.
That should help when I get to the send part of my program. Thanks for sharing your code.
My next steps are the send part and putting them in a thread, which should allow me to keep it active in memory just waiting for
my cnc control to send a program to it.
I haven't used the thread part of purebasic yet so any hints from anyone would be appreciated.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Serial Port

Post by infratec »

Hi Dano,

try this (no guaranty, since I can not test it) :

Code: Select all

EnableExplicit

#Port$ = "COM1"
#XON = $11
#XOFF = $13

#TextFile$ = "C:\Text.txt"

Enumeration
  #Text01
  #SendButton
  #ReceiveButton
  #Editor01
EndEnumeration

Enumeration #PB_Event_FirstCustomValue
  #OpenSerialPortFailure
  #FileError
  #SetStatusBarField_1
  #SetStatusBarField_2
  #ShowContent
  #ReceiveFinished
  #SendFinished
EndEnumeration


Structure ThreadParameterStructure
  Thread.i
  Port$
  FileName$
  FileContent$
  StatusText_01$
  StatusText_02$
  Exit.i
EndStructure



Procedure Receive(*p.ThreadParameterStructure)
 
  Protected.a Byte
  Protected.i Port, State, Count, File
  Protected Text$
 
  Port = OpenSerialPort(#PB_Any, *p\Port$, 9600, #PB_SerialPort_EvenParity, 7, 2, #PB_SerialPort_XonXoffHandshake, 1024, 1024)
  If Port
   
    While AvailableSerialPortInput(Port)
      ReadSerialPortData(Port, @Byte, 1) ; to remove available rubbish
    Wend
   
    *p\StatusText_01$ = "Waiting for file ..."
    PostEvent(#SetStatusBarField_1)
   
    Byte = #XON
    WriteSerialPortData(Port, @Byte, 1) ; to be sure :)
   
    Repeat
     
      If AvailableSerialPortInput(Port)
       
        While AvailableSerialPortInput(Port) And Not *p\Exit
          If ReadSerialPortData(Port, @Byte, 1) ; Read Byte
            Select State
              Case 0
                If Byte = '%'
                  *p\StatusText_01$ = "receiving file ..."
                  PostEvent(#SetStatusBarField_1)
                  State = 1
                  Text$ + Chr(Byte)
                EndIf
              Case 1
                If Byte <> '%'
                  Text$ + Chr(Byte)
                  Count + 1
                  *p\StatusText_02$ = Str(Count)
                  PostEvent(#SetStatusBarField_2)
                Else
                  Text$ + Chr(Byte)
                  Text$ = ReplaceString(Text$, #LF$ + #CR$ + #CR$, #CRLF$)
                  *p\FileContent$ = Text$
                  PostEvent(#ShowContent)
                  File = CreateFile(#PB_Any, #TextFile$)
                  If File
                    WriteString(File, Text$, #PB_Ascii)
                    CloseFile(File)
                    *p\StatusText_01$ = "File received"
                    PostEvent(#SetStatusBarField_1)
                  Else
                    *p\StatusText_01$ = "File error !!!"
                    PostEvent(#SetStatusBarField_1)
                  EndIf
                  *p\Exit = #True
                EndIf
            EndSelect
          EndIf
        Wend
       
      Else
        Delay(10)
      EndIf
     
    Until *p\Exit
   
    *p\StatusText_02$ = ""
    PostEvent(#SetStatusBarField_2)
   
    CloseSerialPort(Port)
  Else
    PostEvent(#OpenSerialPortFailure)
  EndIf
 
  PostEvent(#ReceiveFinished)
 
EndProcedure




Procedure Send(*p.ThreadParameterStructure)
 
  Protected.a Byte
  Protected.i Port, State, Count, File, FileSize
  Protected Text$
 
 
  Repeat
   
    Port = OpenSerialPort(#PB_Any, *p\Port$, 9600, #PB_SerialPort_EvenParity, 7, 2, #PB_SerialPort_XonXoffHandshake, 1024, 1024)
    If Port
     
      File = ReadFile(#PB_Any, *p\FileName$)
      If File
        FileSize = Lof(File)
        Text$ = ReadString(File, #PB_Ascii|#PB_File_IgnoreEOL, FileSize)
        CloseFile(File)
       
        *p\FileContent$ = Text$
        PostEvent(#ShowContent)
       
        If Len(Text$)
          *p\StatusText_01$ = "sending file ..."
          PostEvent(#SetStatusBarField_1)
         
          Repeat
           
            If AvailableSerialPortOutput(Port) < 1024
              WriteSerialPortData(Port, @Text$ + Count, 1)
              Count + 1
             
              *p\StatusText_02$ = Str(Count) + " / " + Str(FileSize)
              PostEvent(#SetStatusBarField_2)
             
            Else
              Delay(1)
            EndIf
           
          Until Count = FileSize Or *p\Exit
         
        EndIf
       
        *p\Exit = #True
       
      Else
        PostEvent(#FileError)
        *p\Exit = #True
      EndIf
     
      *p\StatusText_02$ = ""
      PostEvent(#SetStatusBarField_2)
     
      CloseSerialPort(Port)
     
    Else
      PostEvent(#OpenSerialPortFailure)
    EndIf
   
  Until *p\Exit
 
  PostEvent(#SendFinished)
 
EndProcedure




Procedure TerminateThread(*TP.ThreadParameterStructure)
  If IsThread(*TP\Thread)
    *TP\Exit = #True
    If WaitThread(*TP\Thread, 500) = 0
      KillThread(*TP\Thread) ; should never happen
    EndIf
  EndIf
EndProcedure





;-Main
Define.i Event, Exit, Thread, ParaCount, i
Define ThreadParameter.ThreadParameterStructure


CompilerIf Not #PB_Compiler_Thread
  MessageRequester("Hint", "You have to enable 'Thread-Safe' in compiler settings")
  End
CompilerEndIf


ThreadParameter\Port$ = #Port$
ThreadParameter\Exit = #False


OpenWindow(0, 0, 0, 370, 200, "Serial Communications", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

TextGadget(#Text01, 10, 30, 310, 20, "")
ButtonGadget(#SendButton, 40, 10, 80, 20, "Send File", #PB_Button_Toggle)
ButtonGadget(#ReceiveButton, 210, 10, 80, 20, "Receive File", #PB_Button_Toggle)
EditorGadget(#Editor01, 10, 50, 310, 100, #PB_Editor_ReadOnly)

CreateStatusBar(0, WindowID(0))
AddStatusBarField(150)
AddStatusBarField(100)


ParaCount = CountProgramParameters() - 1
For i = 0 To ParaCount
  Select LCase(ProgramParameter(i))
    Case "s"
      i + 1
      ThreadParameter\FileName$ = ProgramParameter(i)
      SetGadgetState(#SendButton, 1)
      PostEvent(#PB_Event_Gadget, 0, #SendButton)
      ;ThreadParameter\Thread = CreateThread(@Send(), @ThreadParameter)
    Case "r"
      i + 1
      ThreadParameter\FileName$ = ProgramParameter(i)
      SetGadgetState(#ReceiveButton, 1)
      PostEvent(#PB_Event_Gadget, 0, #ReceiveButton)
      ;ThreadParameter\Thread = CreateThread(@Receive(), @ThreadParameter)
  EndSelect
Next i


;-Main loop
Repeat

  Event = WaitWindowEvent()
 
  Select Event
    Case #OpenSerialPortFailure
      MessageRequester("Error", "Was not able to open " + ThreadParameter\Port$)
     
    Case #FileError
      MessageRequester("Error", "Was not able to open " + ThreadParameter\FileName$)
     
    Case #ShowContent
      SetGadgetText(#Editor01, ThreadParameter\FileContent$)
     
    Case #SetStatusBarField_1
      StatusBarText(0, 0, ThreadParameter\StatusText_01$, #PB_StatusBar_Center)
     
    Case #SetStatusBarField_2
      StatusBarText(0, 1, ThreadParameter\StatusText_02$, #PB_StatusBar_Center)
     
    Case #ReceiveFinished
      SetGadgetState(#ReceiveButton, 0)
      PostEvent(#PB_Event_Gadget, 0, #ReceiveButton)
     
    Case #SendFinished
      SetGadgetState(#SendButton, 0)
      PostEvent(#PB_Event_Gadget, 0, #SendButton)
     
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #ReceiveButton
          If GetGadgetState(#ReceiveButton)
            If Len(ThreadParameter\FileName$) = 0
              ThreadParameter\FileName$ = #TextFile$
            EndIf
            ThreadParameter\Port$ = #Port$
            ThreadParameter\Exit = #False
            ThreadParameter\Thread = CreateThread(@Receive(), @ThreadParameter)
            DisableGadget(#SendButton, #True)
          Else
            TerminateThread(@ThreadParameter)
            DisableGadget(#SendButton, #False)
            StatusBarText(0, 0, "")
            ThreadParameter\FileName$ = ""
          EndIf
         
        Case #SendButton
          If GetGadgetState(#SendButton)
            If Len(ThreadParameter\FileName$) = 0
              ThreadParameter\FileName$ = OpenFileRequester("Choose a file ...", "", "*.*|*.*", 0)
            EndIf
            If Len(ThreadParameter\FileName$)
              ThreadParameter\Port$ = #Port$
              ThreadParameter\Exit = #False
              ThreadParameter\Thread = CreateThread(@Send(), @ThreadParameter)
              DisableGadget(#ReceiveButton, #True)
            Else
              SetGadgetState(#SendButton, 0)
            EndIf
          Else
            TerminateThread(@ThreadParameter)
            DisableGadget(#ReceiveButton, #False)
            StatusBarText(0, 0, "")
            ThreadParameter\FileName$ = ""
          EndIf
         
      EndSelect
     
    Case #PB_Event_CloseWindow
      TerminateThread(@ThreadParameter)
      Exit = #True
  EndSelect
 
Until Exit
Bernd
Last edited by infratec on Mon Jul 28, 2014 7:24 am, edited 2 times in total.
Dano
User
User
Posts: 41
Joined: Fri Jul 16, 2004 4:20 am
Location: Edmonton, Ab, Canada

Re: Serial Port

Post by Dano »

Infratec,
You have a much better grasp of the advanced parts of Purebasic than I do, your use of pointers and threading leaves me in the dust. I can't wait to try the code on monday( I have been sick the last few days)
I was so happy when I finally got my program to receive a program from the control, this code makes it so much more eloquent, it clears the buffer to be sure first, then receives the program in a thread safe way,
I feel like a professional touch has just been added. Much appreciation goes to you, I'm sure as well as my program worked this will work a thousand times better.

Thanks again,

Dan
Dano
User
User
Posts: 41
Joined: Fri Jul 16, 2004 4:20 am
Location: Edmonton, Ab, Canada

Re: Serial Port

Post by Dano »

Infratec,
Your code worked good, I needed to do some processing with the carriage return/ linefeed so I need to still modify it to bring the code in one line at a time but other than that it worked great. The threading was really good, no unnecessary slowdown of the computer while it was waiting for code. I thought the sending would be easier, but I am struggling again, I wonder if I could avail myself of your expertise, do you have some sample code for sending? Here is what I have started,
including an editor that shows the code as I bring it in/send it

Code: Select all

EnableExplicit

#Port$ = "COM1"
#XON = $11
#XOFF = $13

#TextFile$ = "C:\Text.txt"

Enumeration
#Text01
#Gadget_50
#Gadget_51
#Editor01
EndEnumeration

Enumeration #PB_Event_FirstCustomValue
#OpenSerialPortFailure
#SetStatusBarField_1
#SetStatusBarField_2
#ReceiveFinished
EndEnumeration


Structure ThreadParameterStructure
StatusText_01$
StatusText_02$
Exit.i
EndStructure



Procedure Receive(*p.ThreadParameterStructure)

Protected.a Byte
Protected.i Port, State, Count, File
Protected Text$, orig.s, news.s

Port = OpenSerialPort(#PB_Any, #Port$, 9600, #PB_SerialPort_EvenParity, 7, 2, #PB_SerialPort_XonXoffHandshake, 1024, 1024)
If Port

While AvailableSerialPortInput(Port)
ReadSerialPortData(Port, @Byte, 1) ; to remove available rubbish
Wend

*p\StatusText_01$ = "Waiting for file ..."
PostEvent(#SetStatusBarField_1)

Byte = #XON
WriteSerialPortData(Port, @Byte, 1) ; to be sure :)

Repeat

If AvailableSerialPortInput(Port)

While AvailableSerialPortInput(Port) And Not *p\Exit
If ReadSerialPortData(Port, @Byte, 1) ; Read Byte
Select State
Case 0 
If Byte = '%'
*p\StatusText_01$ = "receiving file ..."
PostEvent(#SetStatusBarField_1)
State = 1
Text$ + Chr(Byte)
EndIf
Case 1
If Byte <> '%'
Text$ + Chr(Byte)
Count + 1
*p\StatusText_02$ = Str(Count)
PostEvent(#SetStatusBarField_2)

Else
Text$ + Chr(Byte)
orig=Chr(10)+Chr(13)+Chr(13)
news=Chr(13)+Chr(10)
Text$ = ReplaceString(Text$,orig,news)
AddGadgetItem(#Editor01,-1, Text$)
File = CreateFile(#PB_Any, #TextFile$)
If File
WriteString(File, Text$)
CloseFile(File)
*p\StatusText_01$ = "File received"
PostEvent(#SetStatusBarField_1)
Else
*p\StatusText_01$ = "File error !!!"
PostEvent(#SetStatusBarField_1)
EndIf
*p\Exit = #True
EndIf
EndSelect
EndIf
Wend

Else
Delay(10)
EndIf

Until *p\Exit

*p\StatusText_02$ = ""
PostEvent(#SetStatusBarField_2)

CloseSerialPort(Port)
Else
PostEvent(#OpenSerialPortFailure)
EndIf

PostEvent(#ReceiveFinished)

EndProcedure

Procedure Send()
Protected.a Byte
Protected.i Port, State, Count, File
Protected Text$, orig.s, news.s


Repeat

If Port = OpenSerialPort(#PB_Any, #Port$, 9600, #PB_SerialPort_EvenParity, 7, 2, #PB_SerialPort_XonXoffHandshake, 1024, 1024)

While AvailableSerialPortOutput(Port)


If File

Else

EndIf




Wend

Else
MessageRequester("Error", "Can't open the serial port: "+Port)
EndIf

Until File


EndProcedure
Define.i Event, Exit, Thread
Define ThreadParameter.ThreadParameterStructure


CompilerIf Not #PB_Compiler_Thread
MessageRequester("Hint", "You have to enable 'Thread-Safe' in compiler settings")
End
CompilerEndIf


OpenWindow(0, 0, 0, 370, 200, "Serial Communications", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

TextGadget(#Text01, 10, 30, 310, 20, "")
ButtonGadget(#Gadget_50, 210, 10, 80, 20, "Receive File")
ButtonGadget(#Gadget_51, 40, 10, 80, 20, "Send File")
EditorGadget(#Editor01, 10, 50, 310, 100, #PB_Editor_ReadOnly)
CreateStatusBar(0, WindowID(0))
AddStatusBarField(150)
AddStatusBarField(100)

Repeat

Event = WaitWindowEvent()

Select Event
Case #OpenSerialPortFailure
MessageRequester("Error", "Was not able to open " + #Port$)

Case #SetStatusBarField_1
StatusBarText(0, 0, ThreadParameter\StatusText_01$, #PB_StatusBar_Center)

Case #SetStatusBarField_2
StatusBarText(0, 1, ThreadParameter\StatusText_02$, #PB_StatusBar_Center)

Case #ReceiveFinished
; do something or not :)

Case #PB_Event_Gadget
Select EventGadget()
Case #Gadget_50 ;Receive Button
If GetGadgetState(#Gadget_50)
Thread = CreateThread(@Receive(), @ThreadParameter)
Else
If IsThread(Thread)
ThreadParameter\Exit = #True
If WaitThread(Thread, 500) = 0
KillThread(Thread) ; should never happen
EndIf
EndIf
StatusBarText(0, 0, "")
EndIf
EndSelect
Case #Gadget_51 ;Send Button
Send()
Case #PB_Event_CloseWindow
If IsThread(Thread)
ThreadParameter\Exit = #True
If WaitThread(Thread, 500) = 0
KillThread(Thread) ; should never happen
EndIf
EndIf
Exit = #True
EndSelect

Until Exit
Thanks,
Dan
Last edited by Dano on Tue Jul 29, 2014 5:20 am, edited 1 time in total.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Serial Port

Post by infratec »

Hi,

I changed my listing above.
As usual: untested.

Bernd
User avatar
A.D.
User
User
Posts: 98
Joined: Tue Oct 06, 2009 9:11 pm

Re: Serial Port

Post by A.D. »

I wrote this program, maybe you like to use it: https://www.dropbox.com/s/e430dr068y3c1 ... x_0818.zip
I suggest to download the "com2com driver". It installs a virtual serial port connection to your os so you can
test your code with it (just start two instances of your program, one to send data and the other one to receive...)

com2com:
http://sourceforge.net/projects/com0com/

ncmax source:
https://www.dropbox.com/s/cm65h6i4lqpe2wj/Source.zip


Greets
Alexander
Repeat
PureBasic
ForEver
Dano
User
User
Posts: 41
Joined: Fri Jul 16, 2004 4:20 am
Location: Edmonton, Ab, Canada

Re: Serial Port

Post by Dano »

Infratec,
Your code works beautifully, I have to pour through it so I can understand it a bit better. I still want the EditorGadget to update as I'm bringing in or sending the code, rather than all at once. It seems that the only way to update
the gadget is with AddGadgetItem, which adds a whole line, I don't think there is a way to add each single character while I am bringing in the text. Probably there is an api call to do so. Anyways failing
that I must then use ReadSerialPortString instead of ReadSerialPortData and then update the EditorGadget after the CRLF. Another way might be using the Scintilla Editor, I'm sure if I check their docs there must be a
way to add individual characters rather than a whole line, which would mean I don't have to touch your code. Anyways I think I can handle the rest. You don't know what you've done for me, sitting in the forum is a post from 8 years
ago when I attempted serial port communications using the MVCom library and couldn't get it to work. I gave up thinking it too hard and stopped programming in Purebasic for many years(unrelated). Now I have come back and see native serialport commands (Thanks Fred and team) and many other nice improvements to the language, and thought I'd try again, and now thanks to your help I have a working program, and have other projects I am undertaking with PB. I greatly appreciate it!

Alexander,
Looking at your program, a freeware serial communications program, I think it is just what I was looking for before I decided to try programming the serial ports myself. I wonder if you might consider translating it to english? I can't
understand what is going on there in the code and in the help file.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Serial Port

Post by infratec »

Hi,

nice that it works for you :wink:

I would stay with ReadSerialPortData().
Since it is used byte by byte, you can simply check for Byte = #LF or soemthing like that.

You can also write directly in Gadgets or in the StatusBar inside of the thread, but ...

If you close the program it can happen that your thread hangs, because he want to some of this stuff,
but it is not proccessed anymore.

But I think you can manage the rest.

One of the best things with PB is not only the language, it is this forum.

Bernd
User avatar
A.D.
User
User
Posts: 98
Joined: Tue Oct 06, 2009 9:11 pm

Re: Serial Port

Post by A.D. »

Hi Dano!

I will translate my program to english language, not sure if i have time to do it right now, but i'll translate it as soon as possible.
I had the same problem with adding single letters to the editor gadget, but its possible with SetGadgetItemText(#Gadget, Pos, Text.s) :

Code: Select all

 ...
 programdata = programdata + dat.s ; i store my data here
 Bytes = Bytes + Len(dat.s) ; count bytes transmitted
 SetGadgetItemText(#Editor_73, g, dat.s) : g + Len(dat.s) ;sets at position g new arrived data + increment g (position)
 SendMessage_(GadgetID(#Editor_73), #EM_SETSEL,-1,-1) ;scroll editor gadget down
 ...
 
Greets

Alexander
Repeat
PureBasic
ForEver
Dano
User
User
Posts: 41
Joined: Fri Jul 16, 2004 4:20 am
Location: Edmonton, Ab, Canada

Re: Serial Port

Post by Dano »

Alexander,
I didn't even think of the SetGadgetItemText, but it makes sense that it would work, thanks for the tip, and for translating your program to english, whenever you have time,
no hurry. I appreciate that.

Bernd,
I have a question. I am passing parameters to the program, an S or R for send/receive, and a filename. I now can't use the constant #TextFile$ as it will change every time.
I'm wondering if I can use Global for a string say TextFile$ which I can get from ProgramParameter and use in my thread Procedure. Or is it because of the threading you can't do this?
Do you have an elegant solution without using the constant #TextFile$? Sorry probably simple question, I tried a few things and they didn't work, but I will try again tomorrow.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Serial Port

Post by infratec »

Hi,

I extended my listing above.

Bernd
Post Reply