Programm friert nach Click auf CheckBoxGadget ein..

Für allgemeine Fragen zur Programmierung mit PureBasic.
wolfgang.ebersbach
Beiträge: 6
Registriert: 21.02.2012 23:04

Programm friert nach Click auf CheckBoxGadget ein..

Beitrag von wolfgang.ebersbach »

Hallo Forum,
ich bin ganz neu hier und bei PB. Mein erster PB Versuch läuft _fast_ genau wie ich das möchte, ausser:
Ich habe ein CheckBoxGadget (Zeile 210 im Editor, hier im Forum wohl nicht; gleich das zweite Gadget nach dem OpenWindow). Unter WindowsXP (SP2) läuft alles wie erwartet.
Unter Vista bleibt das Programm nach dem Klick auf diese Checkbox scheinbar stehen. Es reagiert danach auf keinerlei Eingabe mehr. Nach einger Zeit des wilden rumklickens (15 Sekunden) scheinen dann aber alle in der Zwischenzeit "gesammelten" Events auf einen Schlag abgearbeitet zu werden.

Code anbei. Ich bitte den grausigen Stil zu verzeihen, das ist mein erstes PB Programm und mit sehr viel "F1" in weniger als 12 Arbeitsstunden entstanden.

Code: Alles auswählen


#SerialPort = 0
Global Port$ = "COM2"                   ; Default com port; is overwritten by FindComm() anyhow
Global Msg$ = ""                        ; String Var for cosntructing the serial port string from several chunks
Global Text$ = ""                       ; Byte chunk from serial port buffer
Global *Buffer = AllocateMemory(1024)   ; serial port receive buffer
Global RadarX.f = 0                     ; X position for the neigungs display line 
Global RadarY.f = 0                     ; y position for the neigungs display line
Global AzX.f = 0                        ; x position for the azimuth display line
Global AzY.f = 0                        ; y position for the azimuth display line
Global Azimuth.f = 0                    ; azimuth value in degree
Global NeigungsBetrag.f = 0             ; neigung value
Global NeigungsWinkel.f = 0             ; neigung angel
Global ValString$ = ""                  ; part of serial port buffer left of the CR
Global AutoStoreTolerance.f = 0.5       ; tolerance for autostore - if this is not exceeded for 3 measurments in an row, the third measurement is auto-stored
Global Temperature.f = 0                ; current temperature
Global Teufe.f = 0                      ; current teufe
Global Batt = 0                         ; current battery voltage (corase)
Global Dim TeufeA.f(90000)              ; memory arrays for up to 90000 measurements used to construct the trace. 90000 is more than one day with 1 measueremnt per second.
Global Dim AzimuthA.f(90000)
Global Dim PitchA.f(90000)
Global Dim RollA.f(90000)
Global Dim TimeA$(90000)
Global Dim TempA.f(90000)
Global Dim Selected(90000)
Global Dim PosXA.f(90000)
Global Dim PosYA.f(90000)
Global ArrayPos.l = 0                   ; current position within array
Global ScrollPos.l = 0                  ; current position of the scrollbar, used for scrolling trough the memory array
Global OnlySavedFlag = 1                ; flag indicating that we want to see only values that have been saved by button or AutoSave
Global StoragePath$ = GetHomeDirectory()    ; default path for file storage
Global FileName$ = ""                   ; current file name

If ReadFile(5,"GeoTerm_storage_path.txt")   ; try to read the default storage path from a config file
  StoragePath$ = ReadString(5,#PB_Ascii)    ; read storage pth from file
  CloseFile(5)                              ; close file
EndIf                                       ; end of try to read storage path from config file

OldTeufe.f = 0                          ; old teufe, needed for construction of the trace
OldWinkel.f = 0                         ; old winkel; needed for autostore tolerance checking
GoodFlag = 0                            ; flag indicating how many good measurements in a row we had
PortOpenFlag = 0                        ; flag indicating the srial port is open; needed to be known for close
Global PortFoundFlag = 0                ; flag indicating that we found a sensor on a port
Global ImageFlag = 0                    ; flag indicating that we want to show an overlay image in DrawPane()

BigFont = LoadFont(1,"Arial",12,#PB_Font_Bold)

Procedure FindComm()                                    ; search all ports for the sensor data stream
  PortFoundFlag = 0
  SetGadgetText(7,"Suche COM Ports...")
  For n= 1 To 100                                       ; scan ports 1 to 100; This is because virtual COM ports on windows can reach very high numbers
    Port$ = "COM" + Str(n)                              ; construct port name
    SetGadgetText(7,"..." + Port$)        
    If OpenSerialPort(#SerialPort, Port$, 19200, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1024, 1024)   ; Try to open port - this function is, according to the PB Manual - "bullet proof"
      SetGadgetText(7,Port$ + " opened")            
      Delay(1200)                                       ; wait more than 1 second because the EWS data packets may be as slow as 1 per second
      Result = AvailableSerialPortInput(#SerialPort)    ; check if there is something in the input buffer
      If Result                                         ; and if so
        SetGadgetText(7,Port$ + " opened and has " + Str(Result) + "bytes data")
        ReadSerialPortData(#SerialPort,*Buffer,Result)  ; read the buffer content
        Text$ = PeekS(*Buffer, Result)                  ; get the string from the buffer "Buffer"
        Result = FindString(Text$,"D",1)                ; check if the buffer contains a "D" , the start condition of the sensor
        If Result                                       ; if so,
          SetGadgetText(7,"... Sensor auf " + Port$ + " gefunden.")
          PortFoundFlag = 1                             ; set a flag indicating that we found the port
          CloseSerialPort(#SerialPort)                  ; close the port
          Break                                         ; exit the for loop, we do not need to search further
        EndIf                                           ; if no "D" in the buffer contents
      EndIf                                             ; if nothing in the buffer
      CloseSerialPort(#SerialPort)                      ; close port
    EndIf                                               ; if port could not be opened
  Next                                                  ; try next port
  
EndProcedure                                            ; end of the FindComm procedure


Procedure SaveValues()                                  ; This procedure saves the current sensor data to a file
  Selected(ArrayPos) = 1
  PlaySound(0)                                          ; play a sound indicating that the save event is triggered; this is useful for the autosave feature
  WriteStringN(2,TimeA$(ArrayPos) + "," + StrF(AzimuthA.f(ArrayPos),1) + "," + StrF(PitchA.f(ArrayPos),1) + "," + StrF(RollA.f(ArrayPos),1) + "," + StrF(RadarX.f,1) + "," + StrF(RadarY.f,1) + "," + StrF(PosXA.f(ArrayPos),1) + "," + StrF(PosYA.f(ArrayPos),1) + "," + Str(ArrayPos) + "," + StrF(TeufeA.f(ArrayPos),1) + "," + StrF(TempA.f(ArrayPos),2) + "," + Str(Selected(ArrayPos)) , #PB_Ascii)
  FlushFileBuffers(2)                                   ; flush the file buffer; We want to have all data secure ASAP to be save in case of program crashes or power loss  
EndProcedure


Procedure DrawPane()                                    ; This procedure (re)draws the radar pane
  
  CreateImage(0,720,720)                                ; create radar pane image
  StartDrawing(ImageOutput(0))                          ; draw on pane
  FrontColor(RGB(0,0,0))                                ; default draw color is black
  DrawingMode(#PB_2DDrawing_Default)                    ; draw solid
  Box(0,0,720,720,RGB(255,255,255))                     ; draw white background box - default background is black
  LineXY(0,360,720,360,RGB(200,200,200))                ; the x axis - note, this is north-south and thus y axis of the sensor
  LineXY(360,0,360,720,RGB(200,200,200))                ; the y axis - note, this is east-west and thus x axis of the sensor
  LineXY(0,655,50,655,RGB(128,0,0))                     ; legend lines - neigung
  LineXY(0,670,50,670,RGB(255,0,0))                     ; compass
  LineXY(0,685,50,685,RGB(0,0,255))                     ; trace
  For n = 1 To 361 Step 20                             ; draw the scale lines and text
    DrawingMode(#PB_2DDrawing_Transparent)              ; draw only the outline of the circle(s) otherwise we end up with a big black filled circle
    If n > 1                                            ; do not draw the "0" at the origin, as this is annoying
      DrawText(360,360-n,Str(2*n/20),RGB(200,200,200))  ; draw the scale text
    EndIf 
    DrawingMode(#PB_2DDrawing_Outlined)                 ; draw the scale circles - only the outlnes, not filled
    Circle(360,360,n,RGB(200,200,200))                  ; draw the circle
  Next                                                  ; scaling is drawed now
  LineXY(360,360,360+RadarY.f,360-RadarX.f,RGB(128,0,0))   ; the neigung
  LineXY(360,360,360+AzY.f,360-AzX.f,RGB(255,0,0))         ; the compass
  Last.l = 1                                            ; this is the array position of the last explicit stored dataset
  For n = 1 To ArrayPos                                 ; draw all stored data points, or only the ones explicitely saved
    If OnlySavedFlag = 1                                ; if we want to see only the explicit stored data
      If Selected(n) = 1                                ; check if this data set is explicit stored
        LineXY(360+PosYA.f(Last),360-PosXA.f(Last),360+PosYA.f(n),360-PosXA.f(n),RGB(0,0,255))   ; if so, draw line from last explicit one to this one
        Last = n                                        ; now this one is the last one (for the next iteration)
      EndIf                                             ; end of "if this is explicit saved data"
    Else                                                ; If all data should be shown
      LineXY(360+PosYA.f(n-1),360-PosXA.f(n-1),360+PosYA.f(n),360-PosXA.f(n),RGB(0,0,255))  ; draw line from last data point to this one
    EndIf                                               ; end of the "explicit or not" decision 
  Next                                                  ; next data set from the array
  DrawingMode(#PB_2DDrawing_Transparent)                ; draw text
  DrawText(350,705,"S",RGB(200,200,200))                ; draw South, West, East markers
  DrawText(0,360,"W",RGB(200,200,200))
  DrawText(710,360,"E",RGB(200,200,200))
  DrawText(615,640,"Temp.: " + StrF(Temperature.f,2),RGB(0,0,0))    ; draw current temperature to lower right corner
  DrawText(615,655,"Teufe: " + StrF(Teufe.f,2),RGB(0,0,0))          ; draw current teufe to lower right corner
  DrawText(615,670,"Az: " + StrF(Azimuth.f,1),RGB(255,0,0))           ; draw current azimuth to lower right corner
  DrawText(615,685,"Abweichung: " + Str(Sqr(Pow(PosXA(ArrayPos),2) + Pow(PosYA(ArrayPos),2))/10),RGB(0,0,255))
  DrawingFont(FontID(1))
  DrawText(550,700,"Neigung: " + StrF(Neigungsbetrag.f,1) + "°, \/" + StrF(NeigungsWinkel.f,1),RGB(128,0,0))
  DrawingFont(#PB_Default)
  DrawText(0,705,Str(ArrayPos),RGB(0,0,0))                          ; draw dataset number to lower left corner
  DrawText(0,635,"Legende:",RGB(0,0,0))                             ; draw legende
  DrawText(55,650,"Neigung",RGB(128,0,0))                           
  DrawText(55,665,"Azimuth",RGB(255,0,0))
  DrawText(55,680,"Bohrspur",RGB(0,0,255))
 ; If ImageFlag = 1 
 ;   DrawingMode(#PB_2DDrawing_AlphaBlend)
 ;   DrawAlphaImage(2,100,100,200)        ; overlay map
 ; EndIf
  If ScrollPos > 0                                                      ; if the user is scrolling right now
    Circle(360+PosYA(ScrollPos),360-PosXA(ScrollPos),3,RGB(0,0,0))      ; show scroll position as circle on the measured trace
    Nb.f = Sqr(Pow(PitchA(ScrollPos),2) + Pow(RollA(ScrollPos),2))      ; calclate neigungs betrag
    DrawText(615,0,"Temp. " + StrF(TempA(ScrollPos),2),RGB(200,200,200))  ; draw temperature in the uper right corner
    DrawText(615,15,"Teufe " + Str(TeufeA(ScrollPos)),RGB(200,200,200))  ; draw teufe at this position at the upper right corner    
    DrawText(615,30,"Neigung " + StrF(Nb,1),RGB(200,200,200))           ; draw neigungs betrag in the upper right corner
    DrawText(615,45,"Abweichung: " + Str(Sqr(Pow(PosXA(ScrollPos),2) + Pow(PosYA(ScrollPos),2))/10),RGB(200,200,200))
    DrawText(0,0,Str(ScrollPos),RGB(200,200,200))                       ; draw position of current data set in the uppper left corner
  EndIf                                                                 ; end of the "if user is scrolling" decision
  StopDrawing()                                                         ; all drawing is done here
  SetGadgetState(3,ImageID(0))                                          ; copy the image from the memory buffer to the screen buffer
  FreeImage(0)                                                          ; free the memory buffer; otherwise -° memory overflow after a while
  
EndProcedure                                                  ; end of the DrawPane procedure




Procedure InitArray()                          ; This procedure emptys the memory array and the current values to 0
  
  For n = 0 To 90000                           ; loop all array positions
    TeufeA.f(n) = 0
    AzimuthA.f(n) = 0
    PitchA.f(n) = 0
    RollA.f(n) = 0
    TimeA$(n) = ""
    TempA.f(n) = 0
    Selected(n) = 0
    PosXA.f(n) = 0
    PosYA.f(n) = 0
  Next
  ArrayPos = 1                ; reset array
  TeufeA(ArrayPos) = Teufe    ; set teufe to current value
  NeigungsWinkel.f = 0        ; reset neigung and temperature
  NeigungsBetrag.f = 0
  Temperature.f = 0
  SetGadgetAttribute(8,#PB_ScrollBar_Maximum,ArrayPos)  ; reset scrollbar max value to 1
  SetGadgetState(8,0)         ; reset scrollbar position to 0
EndProcedure                  ; end of InitArray procedure


Procedure OpenPort()
  If PortFoundFlag = 1                                  ; if the sensor was found at any serial port
    If OpenSerialPort(#SerialPort, Port$, 19200, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1024, 1024)   ; try to open the port (should work, the sensor has been found there)
      PortOpenFlag = 1                                  ; remember that the port is open now; needed to close the port only if it is open - otherwise error msg.
      DisableGadget(1,0)                                ; enable messung starten button
      DisableGadget(5,0)                                ; enable autospeichern checkbox
      DisableGadget(9,0)                                ; enable autostore tolerance spingadget
      DisableGadget(10,0)                               ; enable text for the above gadget
      DisableGadget(14,0)                               ; enable "what to display" checkbox
      DisableGadget(15,0)                               ; enable storage path setting button
      HideGadget(7,1)                                   ; hide comm port search info text
      HideGadget(3,0)                                   ; show image gadget used to display the drawn image
      DisableGadget(16,1)                               ; disable rescan button
      DrawPane()                                        ; draw pane - just to have something to look at
    Else                                               ; If port could Not be found - we still could open a stored file To watch it
      MessageRequester("Unable to open port " + Port$,"Unable to open port " + Port$ + ". This should never happen, as the sensor was found on this port just seconds before.")   ; display msg
      PortOpenFlag = 0                                                                  ; reset port open flag      
    EndIf                                               ; end of "if port could be opened" decision
  Else                                                  ; If the sensor was NOT found - we still can open a file from disk to watch it.
    SetGadgetText(7,"... Keinen Sensor gefunden")        ; show the message on the area where otherwise the radar pane would be.
  EndIf                                                 ; end of IfPortFound decision
EndProcedure


; ------------- End of procedures, main program follows ---------


If OpenWindow(0, 100, 100, 920, 720, "GeoTerm")                         ; Try to open window   
  ButtonGadget(1,760,20,150,30,"Messung starten")                                       ; Start measurement button
  GadgetToolTip(1,"Startet eine neue Messung und fragt vorher nach dem Dateinamen")     ; tooltip for the above button
  DisableGadget(1,1)                                                                    ; enable only of sensor was found                    
  CheckBoxGadget(5,760,55,150,20,"Automatisches speichern")                             ; checkbox for autostore feature
  GadgetToolTip(5,"Speichert automatisch wenn drei aufeinanderfolgende Messwerte in der Neigung nicht mehr als unten eigestellt voneinander abweichen")
  DisableGadget(5,1)                                                                    ; enable only if sensor was found
  TextGadget(10,760,75,115,20,"Toleranzbereich dafuer")                                 ; text
  GadgetToolTip(10,"Toleranzbereich dafuer")                                      
  DisableGadget(10,1)                                                                   ; enable only if measurement was started
  SpinGadget(9,875,75,35,20,1,10)                                                       ; autostoretolerance
  SetGadgetState(9,5)                                                                   ; default value is 5 - this gadget can only handle integers, thus we define a range from 1 to 10 and lateron divide by 10
  SetGadgetText(9,"0,5")                                                                ; text display for default value - this gadget keeps real values and the shown text seperate
  GadgetToolTip(9,"Toleranzbereich fuer automatisches Speichern")                       
  DisableGadget(9,1)                                                                    ; we enable this only if a measurement is started
  ButtonGadget(6,760,110,150,30,"Speichern (SPACE)",#PB_Button_Default)                 ; The store button
  GadgetToolTip(6,"Speichert den aktuellen Messwert")       
  DisableGadget(6,1)                                                                    ; we enable this only if a measurement is started
  ButtonGadget(15,760,90,50,15,"..")                                                    ; the button to choose the default storage path
  GadgetToolTip(15,"Verzeichnis zum Speichern festlegen")                               
  DisableGadget(15,1)                                                                   ; we enable this only if the sensor was found
  ButtonGadget(2,760,670,150,30,"Prog. beenden")                                        ; the exit button
  GadgetToolTip(2,"Beendet das Programm")
  ButtonGadget(4,760,630,150,30,"Messung laden")                                        ; the load file button
  GadgetToolTip(4,"Laedt eine Messung von der Festplatte")  
  ScrollBarGadget(8,720,0,20,720,0,1,1,#PB_ScrollBar_Vertical)                          ; the scrollbar gadget - used to scroll trough the memory array - the trace
  GadgetToolTip(8,"Durch die vorhandenen Messungen scrollen. Oben ist die erste Messung, unten die letzte.")
  DisableGadget(8,1)                                                                    ; we enable this if a measurement is started or a file is loaded
  CreateImage(0,720,720)                                                                ; create radar pane image - this is a memory location to draw on
  ImageGadget(3,0,0,0,0,ImageID(0))                                                     ; create image gadget - this is an area on the window to display any kind of images
  HideGadget(3,1)                                                                       ; after the start, we hide this to use the room to display some messages about the serial port detection progress
  TextGadget(7,280,360,160,20,"",#PB_Text_Center | #PB_Text_Border)                     ; this is the text for the serial port detection progress messages
  SetGadgetColor(7,#PB_Gadget_BackColor,RGB(100,255,255))
 ; ButtonGadget(11,440,180,150,30,"Karte laden")
 ; GadgetToolTip(11,"Eine Karte als Hintergrund laden. Die Karte muss genau 80x80 Meter abbilden mit dem Mittelpunkt bei 40/40")
  ButtonGadget(12,760,400,150,30,"Reset Teufe")                                         ; this button allows one to (re)set the teufe at any time
  GadgetToolTip(12,"Die Teufe auf einen beliebigen Wert (in Metern) setzen.")         
  DisableGadget(12,1)                                                                   ; we enable this only if a measurement was started
  ButtonGadget(13,760,440,150,30,"Spur loeschen")                                       ; This button allows one to delete the trace, this is to reset the memory array to all 0
  GadgetToolTip(13,"Die Bohrspur loeschen.")
  DisableGadget(13,1)                                                                   ; we enable this only if a measurement was started
  CheckBoxGadget(14,760,150,150,20,"Nur gespeicherte Werte")                            ; this checkbox defines wether to display all data or only the one stored by user or AutoStore function
  GadgetToolTip(14,"Nur manuell oder per autosave gespeicherte Messwerte anzeigen.")
  SetGadgetState(14,OnlySavedFlag)                                                      ; we set this to the default state whic is only to show stored data
  DisableGadget(14,1)                                                                   ; we enable this only if a measurement was started or a file loaded
  ButtonGadget(16,760,580,150,30,"Rescan Ports")
  GadgetToolTip(16,"Die seriellen Ports neu durchsuchen (z.B. wenn Sensor ausgeschaltet wurde)")
  
  UsePNGImageDecoder()                                                                  ; use the PNG encoder (not used up to now, would be useful for map overlays)
  UseJPEGImageDecoder()                                                                 ; use the JPEG encoder (not used now, useful for map overlays)
  InitSound()                                                                           ; init the sound system - needed for the (auto)store BING sound
  CatchSound(0, ?Bing)                                                                  ; load the sound from the DATA section at the end of this file. We include the sound into the binary to be independend of the system sounds
  
  InitArray()                                                                           ; init the memory array to all 0
 
  FindComm()                                            ; find COM port
  Delay(300)                                            ; wait for port to close before re-opening
  OpenPort()  
  
              ; ------- main event loop -------

  Repeat      ; this is the main event loop. It is repeated forever untill the user exits the program
    If RunFlag = 1                                            ; if measurement was started 
      Result = AvailableSerialPortInput(#SerialPort)          ; Check for available data in the input buffer   
      If Result                                               ; if chars in buffer
        While Result                                          ; loop until buffer is empty
          ReadSerialPortData(#SerialPort, *Buffer, Result)    ; Read the data from the input buffer into memory
          Text$ = PeekS(*Buffer, Result)                      ; get the string from the buffer "Buffer"
          Msg$ + Text$                                        ; append string to the one retrieved before
          Result = AvailableSerialPortInput(#SerialPort)      ; check if more chars n buffer ( or new ones in the meantime)
        Wend                                                  ; loop until bufer is empty
        
        Result = FindString(Msg$,"LowBatt",1)                ; check for low batt message at the string
        If Result                                            ; if low batt message found
          CloseFile(1)                            ; close files
          CloseFile(2)
          SetGadgetText(1,"Messung starten")      ; change text of button to "start" - the measurement is ended now. Thus..
          DisableGadget(1,1)
          DisableGadget(4,0)                      ; enable load button
          DisableGadget(2,0)                      ; enable exit button
          DisableGadget(6,1)                      ; speichern button disablen
          DisableGadget(16,0)
          SetWindowTitle(0,"GeoTerm - no data")   ; reset window title 
          RunFlag = 0          
          If PortOpenFlag = 1                                 ; Check if serial port is open by use of the flag. There is no way to check this by a PB function
            CloseSerialPort(#SerialPort)                      ; close serial port
          EndIf
          Text$ = ""
          Msg$ = ""
          MessageRequester("Hinweis","Hinweis: Sensorelektronik hat wegen leerer Batterie abgeschaltet. Die Messung ist gespeichert.")
        EndIf
        
        Result = FindString(Msg$,"PowerDown",1)     ; check for powerdown message at the string
        If Result                                 ; if low batt message found
          CloseFile(1)                            ; close files
          CloseFile(2)
          SetGadgetText(1,"Messung starten")      ; change text of button to "start" - the measurement is ended now. Thus...
          DisableGadget(1,1)
          DisableGadget(4,0)                      ; enable load button
          DisableGadget(2,0)                      ; enable exit button
          DisableGadget(6,1)                      ; speichern button disablen
          DisableGadget(16,0)
          SetWindowTitle(0,"GeoTerm - no data")   ; reset window title 
          RunFlag = 0          
          If PortOpenFlag = 1                                 ; Check if serial port is open by use of the flag. There is no way to check this by a PB function
            CloseSerialPort(#SerialPort)                      ; close serial port
          EndIf
          Text$ = ""
          Msg$ = ""
          MessageRequester("Hinweis","Hinweis: Sensorelektronik wurde vom Benutzer abgeschaltet. Die Messung ist gespeichert")
        EndIf
        
        Result = FindString(Msg$,Chr(13),1)                   ; look for CR in assembled string
        While Result                                          ; as long as CR's are found in assembled string
          ValString$ = Left(Msg$,Result)                      ; get part at the left side of the CR
          ValString$ = ReplaceString(ValString$," ","")       ; remove all spaces - this is needed as he minus sign may be seperated from the according numer by spaces and VAL cannot handle tis
          ArrayPos = ArrayPos + 1                             ; next position in array
          If ArrayPos.l > 90000                               ; avoid memory overflow - wrap around the memory buffer in this case
            ArrayPos.l = 1
          EndIf
          Selected(ArrayPos.l) = 0                            ; this value set is not (yet) stored by user or AutoStore and thus mey be not valid
          SetGadgetAttribute(8,#PB_ScrollBar_Maximum,ArrayPos)   ; set new scrollbar maximum
          TimeStamp = Val(StringField(ValString$,1,","))      ; get timestamp from sensor
          Azimuth.f = Val(StringField(ValString$,2,",")) / 10 ; get Azimuth
          AzX.f = 360 * Cos(Radian(Azimuth))                  ; calculate X and Y coordinates for the radar pane display which has +- 300 pixels
          AzY.f = 360 * Sin(Radian(Azimuth))                  ; sin and cos return values in the +- 1 tange, thus multiply with number of image pixels
          Pitch.f = Val(StringField(ValString$,3,",")) / 10   ; get pitch value
          Roll.f = Val(StringField(ValString$,4,",")) / 10    ; get roll value
          Temperature.f = ValF(StringField(ValString$,5,","))  ; get temperature value
          Teufe.f = ValF(StringField(ValString$,7,",")) / 100  ; get teufe
          Batt = ((Val(StringField(ValString$,9,",")) -3118) / 120 ) + 8  ; get and calc battery value. As this seems to be very non-linear, do some ugly corrections here. This is sufficient for the low battery warning.
          NeigungsBetrag.f = Sqr(Pow(Pitch.f,2) + Pow(Roll.f,2))  ; calculate betrag of neigung
          NeigungsWinkel.f = Degree(ATan2(Radian(Roll.f),Radian(Pitch.f))) - 90  ; calculate angel of neigung -- warum -90 Grad ?  
          NeigungsWinkel.f = NeigungsWinkel.f + Azimuth.f     ; add azimuth to neigungswinkel
          TeufeA.f(ArrayPos.l) = Teufe.f                      ; store values to memory array
          AzimuthA.f(ArrayPos.l) = Azimuth.f
          PitchA.f(ArrayPos.l) = Pitch.f
          RollA.f(ArrayPos.l) = Roll.f
          TempA.f(ArrayPos.l) = Temperature.f
          TimeA$(ArrayPos.l) = FormatDate("%hh:%ii:%ss",Date())
          RadarX.f = (NeigungsBetrag.f * Cos(Radian(NeigungsWinkel.f))) * 10  ; calculate coordinates for radar pane display. Multiply: 350pixels / 35 grad = 5 
          RadarY.f = (NeigungsBetrag.f * Sin(Radian(NeigungsWinkel.f))) * 10  ; 360px / 36 grad
          a.f = (NeigungsBetrag.f * Cos(Radian(NeigungsWinkel.f)))           ; calc coordinates for radar pane display.
          PosXA.f(ArrayPos) = PosXA.f(ArrayPos - 1) + (Sin(Radian(a.f)) * (Teufe.f - TeufeA.f(ArrayPos-1))) * 10 ; Multiply : 360px / 36 meter = 10
          a.f = (NeigungsBetrag.f * Sin(Radian(NeigungsWinkel.f)))
          PosYA.f(ArrayPos) = PosYA.f(ArrayPos - 1) + (Sin(Radian(a.f)) * (Teufe.f - TeufeA.f(ArrayPos-1))) * 10 ; 360px / 36 meter
          
          If GetGadgetState(5) = #PB_Checkbox_Checked          ; if AutoStore feature enabled
            If Teufe = TeufeA(ArrayPos -1)                                                  ; check if we are moving the sensor right now. If not,
              If Abs((Abs(NeigungsBetrag.f) - Abs(OldWinkel.f))) < AutoStoreTolerance.f     ; check if tolarance between last value an the current one.
                GoodFlag = GoodFlag + 1                                                     ; if OK, we have one more good
              Else                                                                          ; if not, no good, old tilt is current tilt, for next comparison
                GoodFlag = 0
                OldWinkel.f = NeigungsBetrag.f
              EndIf
              If GoodFlag = 2                                        ; if we had two good comparisons ( = 3 good values in a row)
                SaveValues()                                         ; AutoSave current value
                GoodFlag = 0                                         ; reset for next comparison run
                OldWinkel.f = 0
              EndIf
            EndIf
          EndIf                                                    ; end of "If AutoSave feature on" check                             
          
          WriteStringN(1,TimeA$(ArrayPos) + "," + StrF(Azimuth.f,1) + "," + StrF(Pitch.f,1) + "," + StrF(Roll.f,1) + "," + StrF(RadarX.f,1) + "," + StrF(RadarY.f,1) + "," + StrF(PosXA.f(ArrayPos),1) + "," + StrF(PosYA.f(ArrayPos),1) + "," + Str(ArrayPos) + "," + StrF(Teufe.f,2) + "," + StrF(Temperature.f,2) + "," + Str(Selected(ArrayPos)) , #PB_Ascii)   ; save data 
          FlushFileBuffers(1)                                      ; flush file buffers. We want to have all data save ASAP
          
          SetWindowTitle(0,"GeoTerm - Batt: " + Str(Batt) + " Volt - " + GetFilePart(FileName$))  ; display battery voltage in title bar
          If Batt < 10                                                 ; if battery below 8 Volts
           SetWindowColor(0,RGB($FF,$EE,$00))                        ; set window background if battery is low
          ElseIf Batt > 10                                             ; reset window background if battery is over 8 Volts (again)
            SetWindowColor(0,-1)                                      ; reset to default background color
          EndIf               
          
          DrawPane()                            ; update the graphics. This dataset is now done
       
          Msg$ = Mid(Msg$,Result+1)             ; cut this part of the buffer content away because it is proceeded now
          Result = FindString(Msg$,Chr(13),1)   ; look for CR in the Rest
        Wend                                    ; next iteration of the "while chars in input buffer" loop
      EndIf                                     ; end of the check if any chars are in the input buffer
    EndIf                                       ; end of the check if a measurement is running - the whole thing above is otherwise not executed
    
    
    
    
    
    
    EventID = WaitWindowEvent(200)              ; refresh window every 20 ms 
    Select EventGadget()                        ; call EventGadget, which returns the number of the gadget of the last gadget event (there are other event types, too) and use this result for the following SELECT statement
    Case 1                                      ; If start/stop button pressed       
      If RunFlag = 1                            ; If already running, stop now
        CloseFile(1)                            ; close files
        CloseFile(2)
        SetGadgetText(1,"Messung starten")      ; change text of button to "start" - the measurement is ended now. Thus...
        DisableGadget(4,0)                      ; enable load button
        DisableGadget(2,0)                      ; enable exit button
        DisableGadget(6,1)                      ; speichern button disablen
        SetWindowTitle(0,"GeoTerm - no data")   ; reset window title 
        RunFlag = 0                             ; reset the run flag
      Else                                      ; If not yet running, start now
        InitArray()                             ; init memory array as it may contain data from a before loaded file or a measurement made before
        FileName$ = StoragePath$ + FormatDate("%yyyy-%mm-%dd-%hh-%ii-%ss",Date()) + ".csv"    ; construct default filename
        FileName$ = SaveFileRequester("Dateiname angeben",FileName$,"CSV Datei (*.csv)",1)    ; open file requester to possible change the file name
        If FileName$                                            ; if there is a filename
          If FindString(FileName$,".csv",1) = 0                 ; check for ".csv" extension
            FileName$ = FileName$ + ".csv"                      ; append if not ".csv"
          EndIf
          FileNameTwo$ = ReplaceString(FileName$,".csv","_selected.csv",#PB_String_NoCase)    ; construct filename for AutoSave or UserSave data file 
          If OpenFile(1,FileName$)                              ; try to open file
            WriteStringN(1,"GeoTerm measurement file created at " + FormatDate("%yyyy-%mm-%dd",Date()) + " at " + FormatDate("%hh:%ii",Date()))   ; on success, write header lines to file
            WriteStringN(1,"Format: timestamp,Azimuth,Pitch,Roll,RadarX,RadarY,PosX,PosY,Measurement#,Teufe,Temperature,Selected,CrLf")  
            SetGadgetText(1,"Messung stoppen")        ; set button text to "stop" 
            DisableGadget(4,1)                        ; disable load button
            DisableGadget(2,1)                        ; disable exit button
            DisableGadget(6,0)                        ; enable save button
           ; SetActiveGadget(6)                        ; set focus to save button
            DisableGadget(8,0)                        ; enable scrollbar
            DisableGadget(12,0)                       ; enable set teufe button
            DisableGadget(13,0)                       ; enable delete trace button
            DisableGadget(16,1)                       ; disable scan ports button
            Wt$ = GetWindowTitle(0)                   ; get the current window title
            SetWindowTitle(0,Wt$ + " - " + GetFilePart(FileName$))  ; add the filename to the current window title and display that new title 
            RunFlag = 1                               ; set run flag
          Else                                                                               ; if file could not be opened 
            MessageRequester("Error","Error: unable to open file " + FileName$ + ".csv")     ; msg box 
          EndIf
          If OpenFile(2,FileNameTwo$)                                                        ; try to open file for UserStored or AutoStored data
            WriteStringN(2,"GeoTerm measurement file created at " + FormatDate("%yyyy-%mm-%dd",Date()) + " at " + FormatDate("%hh:%ii",Date()) + " - selected measurements")   ; write header lines
            WriteStringN(2,"Format: Timestamp,Azimuth,Pitch,Roll,RadarX,RadarY,PosX,PosY,Measurement#,Teufe,Temperature,Selected,CrLf")
          Else                                                                               ; if it could not be opened
            MessageRequester("Error","Error: Unable to open file " + FileNameTwo$ + ".csv")  ; mesg box 
          EndIf
        EndIf                                     ; end of "if filename exists" 
      EndIf                                     ; end of "start or stop measurement"

      Case 2                                    ; exit button was clicked
        EventID = #PB_Event_CloseWindow         ; set event ID to that of clicking the (non existant) close button on the upper right corner
     
      Case 4                                    ; load button
        FileName$ = OpenFileRequester("Datei auswählen", StoragePath$, "CSV Dateien|*.csv;*.txt|All Files|*.*", 0)  ; show choose file dialog
        If FileName$                                          ; if filename
          If ReadFile(3,FileName$)                            ; try to pen file for reading
            HideGadget(7,1)                                       ; hide comm port search info text
            HideGadget(3,0)                                       ; show image gadget used to display the drawn image
            DisableGadget(12,1)
            DisableGadget(13,1)
            DrawPane()                                            ; draw pane - just to have something to look at
            SetWindowTitle(0,"GeoTerm - " + GetFilePart(FileName$))  ; add the filename to the current window title and display that new title 
            InitArray()                                       ; init memory array as it may contain old data from a measurement or a file loaded before
            RadarX.f = 0                                      ; reset radar pane draw coordinates and other values to 0
            RadarY.f = 0
            AzX.f = 0
            AzY.f = 0
            Temperature.f = 0
            Teufe.f = 0
            n = 0                                             ; init line counter to 0
            While Eof(3) = 0                                  ; loop all lines
              Lin$ = ReadString(3,#PB_Ascii)                  ; read a line
              If FindString(Lin$,":",1) = 3                   ; check if a line contains a ":" - this is to filter out the first two lines that contain user information
                n = n + 1                                     ; increment line counter
                TimeA$(n) = StringField(Lin$,1,",")           ; read line values into memory array
                AzimuthA(n) = ValF(StringField(Lin$,2,","))
                PitchA(n) = ValF(StringField(Lin$,3,","))
                RollA(n) = ValF(StringField(Lin$,4,","))
                PosXA(n) = ValF(StringField(Lin$,7,","))
                PosYA(n) = ValF(StringField(Lin$,8,","))
                TeufeA(n) = ValF(StringField(Lin$,10,","))
                TempA(n) = ValF(StringField(Lin$,11,","))
                Selected(n) = Val(StringField(Lin$,12,","))
              EndIf                                           ; end if the "if : found" decision
            Wend                                              ; end of the loop over the entire file
            CloseFile(3)                                      ; close file
            ArrayPos = n                                      ; set array position to the end
            DisableGadget(8,0)                                ; enable scrollbar
            SetGadgetAttribute(8,#PB_ScrollBar_Maximum,n)     ; set scrollbar max value
            DisableGadget(14,0)                               ; enable the "show only UserSaved or AutoSaved data" checkbox
            DrawPane()                                        ; draw the radar pane
          EndIf                                       ; end of "if file could be opened"
        EndIf                                     ; end of "if filename exists"
        
      Case 5                                      ; autostore checkbox clicked
        ;SetActiveGadget(6)                        ; set focus back to the speichern button
    
      Case 6                                      ; speichern button clicked or SPACE pressed
        SaveValues()                              ; store the vakues to disk
        
      Case 8                                      ; scrollbar clicked (does NOT update during scroll, unfortunately. Code for similar effect below )
        ScrollPos = GetGadgetState(8)             ; get scrollbar position
        DrawPane()                                ; (re)draw pane to show this position
        
      Case 9                                            ; autostoretolerance changed
        AutoStoreTolerance.f = GetGadgetState(9)/10     ; get new value (and divide by 10 as eplained at this gadget's creation code above )
        SetGadgetText(9,StrF(AutoStoreTolerance.f,1))   ; set new value as text to gadget; this is separate at this gadget
        ;SetActiveGadget(6)                              ; set focus back to the save button
        
      Case 11                                     ; load map - disabled right now
        FileName$ = OpenFileRequester("Kartenbild auswaehlen","","Bilder|*.bmp;*.jpg;*.png",0)  ; open open file dialog
        If FileName$                              ; if filename exists
          ImageFlag = 1                           ; set image is there flag (TODO: do this after laoding file succeeded)
          LoadImage(2,FileName$)                  ; load image (TODO : check if success)
          ResizeImage(2,400,400)                  ; resize image
          DrawPane()                              ; (re)draw radar pane
        EndIf                                     ; end of check for filename
      ;  SetActiveGadget(6)                        ; set focus back to the save button

      Case 12                                     ; set teufe button clicked
        a$ = InputRequester("Achtung!","Achtung ! Sie setzten die Teufe auf diesen Meterwert ! (Vorbelegung = aktueller Wert)",Str(Teufe.f))  ; request new value
        WriteSerialPortString(#SerialPort,"<S" + Str(Val(a$)*100) + ">",#PB_Ascii)    ; send command to sensor hardware
       ; SetActiveGadget(6)                                                            ; set focus back to the save button  
  
      Case 13                                     ; delete trace button clicked
        Res = MessageRequester("Achtung!","Achtung! Dies loescht die Bohrspur aus der Anzeige ! Die Daten auf der Festplatte bleiben bestehen.",#PB_MessageRequester_YesNo) ; ask the user again
        If Res = #PB_MessageRequester_Yes     ; if user is sure
          InitArray()                         ; reset data in memory
        EndIf                                 ; that's it. Do nothing otherwise
       ; SetActiveGadget(6)                    ; set focus back to the speichern button
        
      Case 14                                 ; OnlySavedFlag checkbox clicked
       ; SetActiveGadget(6)                    ; set focus back to speichern button
        OnlySavedFlag = GetGadgetState(14)    ; set flag
        DrawPane()                            ; redraw radar pane to show effect of command
        
      Case 15                                 ; button for defining default storage path clicked
        StoragePath$ = PathRequester("Standardmaessigen Speicherpfad festlegen",StoragePath$) ; show "choose path" dialog
        If OpenFile(5,"GeoTerm_storage_path.txt")     ; try to save value in file
          WriteString(5,StoragePath$,#PB_Ascii)
          CloseFile(5)
        EndIf
        
      Case 16
        HideGadget(3,1)
        HideGadget(7,0)
        FindComm()
        OpenPort()  
        
    EndSelect
    
    
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows      ; the code below allows one to scroll the scrollbar by the mousewheel - but works only under windows
    If EventID = 522                                  ; see http://www.purebasic.fr/german/viewtopic.php?f=6&t=19534&start=20
      If WindowMouseX(0) > 720                        ; check if mouse pointer is over scrollbar
        If WindowMouseX(0) < 740
          Stp.f = ( ArrayPos / 100 )                  ; we want max. 100 position to be scrolled
          If Stp.f < 1                                ; we cannot scroll fractions
            Stp.f = 1
          EndIf
          Gs = Gs - (EventwParam()/7864320) * Stp.f   ; calculate new scrollbar position ( which also ist the array position)
          If Gs > ArrayPos                            ; we cannot scroll past the array
            Gs = ArrayPos
          EndIf
          If Gs < 0                                   ; no negative array indices
            Gs = 0
          EndIf
          SetGadgetState(8,Gs)                        ; set scrolbar position
          ScrollPos = Gs                              ; set scroll position flag
          DrawPane()                                  ; redraw pane
        EndIf
      EndIf                                           ; end of "is mouse over scrollbar" check
    EndIf                                             ; end of EventID check
    CompilerEndIf
    
    
    If EventID = #PB_Event_Repaint                    ; if window was covered by other window
      DrawPane()                                      ; redraw radar pane; the gadgets itself are auto refreshed by PB
    EndIf
        
  Until EventID = #PB_Event_CloseWindow               ; If the user has pressed on the window close button (which does not exist here), leave the endless event loop. This is the end...
                                                      ; -------- the program ends here -----------
  If PortOpenFlag = 1                                 ; Check if serial port is open by use of the flag. There is no way to check this by a PB function
    CloseSerialPort(#SerialPort)                      ; close serial port
  EndIf
EndIf                                     ; this belongs to if window_open()

End                               ; this is the ultimate end of the program code and its execution

; ------------ data section - used to store data inside the binary --------------


DataSection
  
  Bing: IncludeBinary("ben.wav")  ; include wav file. This must be present on the compile machine in the folder this code resides.
__________________________________________________
Thread verschoben
Windows>Allgemein
21.02.2012
RSBasic
c4s
Beiträge: 1235
Registriert: 19.09.2007 22:18

Re: Programm friert nach Click auf CheckBoxGadget ein..

Beitrag von c4s »

Dein Code ist leider tatsächlich etwas unleserlich, daher muss man das Problem wohl Schritt für Schritt durchgehen. Was mir auf die Schnelle ins Auge gesprungen ist:

Code: Alles auswählen

; Zeile 391
		EventID = WaitWindowEvent(200)              ; refresh window every 20 ms
		Select EventGadget()                        ; call EventGadget, which returns the number of the gadget of the last gadget event (there are other event types, too) and use this result for the following SELECT statement
			Case 1   
Das ist falsch. Du darfst EventGadget() nur abfragen, wenn ein Gadget-Event aufgetreten ist. Soll heißen:

Code: Alles auswählen

; Zeile 391
		Select WaitWindowEvent()
			Case #PB_Event_Gadget
				Select EventGadget()
					Case #GadgetButtonStart
						; [...]
Weitere Verbesserungsideen:
- Richtig Einrücken, z.B. per Strg+A -> Rechtsklick -> "Einrückung formatieren"
- Konstanten für Gadgets, Fenster usw. verwenden
- So wenig wie möglich Code in den Event-Loop. Besser in Procedures auslagern
- In Zeile 431 verwendest du "If OpenFile(2,FileNameTwo$)"... Ich sehe aber in unmittelbarer Nähe kein CloseFile()! Also darauf auchten, dass Dateien & Co. wieder ordnungsgemäß freigegeben werden.
- Zeile 441: "EventID = #PB_Event_CloseWindow ; set event ID to that of clicking [...]" Besser nicht verwenden. Unteranderem darüber gab es vor kurzem auch eine lebhafte Diskussion im englischen Forum. <)
- Zeile 544: "If EventID = 522" auch hier, wenn möglich die API-Konstanten verwenden. In dem Fall ist 522 -> #WM_MOUSEWHEEL.
"Menschenskinder, das Niveau dieses Forums singt schon wieder!" — GronkhLP ||| "ich hogffe ihr könnt den fehle endecken" — Marvin133 ||| "Ideoten gibts ..." — computerfreak ||| "Jup, danke. Gruss" — funkheld
wolfgang.ebersbach
Beiträge: 6
Registriert: 21.02.2012 23:04

Re: Programm friert nach Click auf CheckBoxGadget ein..

Beitrag von wolfgang.ebersbach »

Hallo c4s,

danke für die schnelle Antwort. Das ganze Eventsystem habe ich noch nicht durchschaut - OK, jedes Ereignis "schmeisst" ein Event, soweit so üblich. Aber wie die Events aufgeteilt sind (Gadgetevent, API-event... ) habe ich noch nicht drauf. Ich nehme an die Serielle Schnittstelle schmeisst dann auch Events ? Ev. spuckt mir das dann ja mangels Abfrage des event-typs in die Suppe ? Habe nämlich gestern (sehr) spät abends festgestellt, dass das Problem nicht auftritt, wenn ich das Programm ohne Datenstrom an der seriellen Schnittstelle laufen lasse.
ERGO: Die ankommenden Daten sind irgendwie schuld. Oder die dadurch ausgelösten Events.

Könnte es auch sein dass das WaitWindowEvent(200) vom Timing her zu knapp ist und mit den 19200 BPS der Schnittstelle in einen Timingkonflikt gerät ? Wie handelt PB denn sowas, asynchrone Daten ?

Die Dateien werden nicht geschlossen, weil ständig Daten reingehen. Daher auch das Buffer flushen, weil die Daten so schnell wie möglich auf die Platte sollen. Geschlossen werden sie wenn man "Messung stoppen" klickt oder das Programm beendet.

Gruss,
Wolfgang
c4s
Beiträge: 1235
Registriert: 19.09.2007 22:18

Re: Programm friert nach Click auf CheckBoxGadget ein..

Beitrag von c4s »

Das Problem ist, dass die Verarbeitung der Daten im Event-Loop des Fensters geschieht. Wenn es dort also etwas länger dauert bzw. - aus welchen Gründen auch immer - anhält, können keine Events des Fensters mehr verarbeitet werden. Um die Daten effektiv neben dem Event-Handling des Fensters zu bearbeiten, müsstest du wohl auf Thread(s) setzen.
"Menschenskinder, das Niveau dieses Forums singt schon wieder!" — GronkhLP ||| "ich hogffe ihr könnt den fehle endecken" — Marvin133 ||| "Ideoten gibts ..." — computerfreak ||| "Jup, danke. Gruss" — funkheld
wolfgang.ebersbach
Beiträge: 6
Registriert: 21.02.2012 23:04

Re: Programm friert nach Click auf CheckBoxGadget ein..

Beitrag von wolfgang.ebersbach »

Danke für die Hilfe, jetzt geht alles wie erwartet.
Fürs Protokoll: Die serielle Schnittstelle wirft offenbar auch mit Events und eines davon hat wohl die Nummer 1. Somit hat ein Schnittstellenevent den Start/Stop Knopf "Bedient" da ich ja den Eventtyp nicht abgefragt hatte.

Wo gibt's eine Liste der Eventtypen und der Eventnummern ?

Gruss,
Wolfgang
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Programm friert nach Click auf CheckBoxGadget ein..

Beitrag von ts-soft »

wolfgang.ebersbach hat geschrieben: Fürs Protokoll: Die serielle Schnittstelle wirft offenbar auch mit Events und eines davon hat wohl die Nummer 1
Ich weiß nicht, wie Du auf diesen Trugschluß kommst, aber die Schnittstelle wirft definitiv keine Events!
wolfgang.ebersbach hat geschrieben: Wo gibt's eine Liste der Eventtypen und der Eventnummern ?
Die Eventtypen und Eventkonstanten findet man in der Hilfe.

Freud mich aber, das alles funktioniert :D , brauch ich mit den unübersichtlichen Code nicht weiter angucken :mrgreen:

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten