Just using dummy data for now until I get real hardware.
It is working ok except I am having trouble getting a consistent log period time (typically 1000ms)
First: I had a loop in a sub to test timer + log-period but the loop was getting killed by the winapi? & period was randomly short. (I didn't like waiting in the loop.)
Second try: I set 'Start1 = Timer' in Sub Get_Data & tested in the main loop 'If Timer > Start1+Log-interval' Then Get_Data
This worked but needed mouse to move over Window_Main to get correct period time.
Fourth try: I used 'SetTimer(Window_Main, 0, 1000, 0 )'' & timer event in 'Select Case msg.hwnd' of main loop, this didn't work but if I changed the 'Select Case msg.hwnd' to 'Select Case msg.message' the timer works (with the DEBUG line un-commented as the mouseup events stop working), but still some period time anomaly.
So If someone can have a look it will be most helpful.
sorry about the indenting(Tabs), it displays ok in my IDE (FbEdit)
Main Code: Also need WinGUI.bi to compile
Code: Select all
'-------------------------------------------------
' AC301L_GUI_Logger.bas V0.10 - FreeBasic code
' App To Get Data from AC301L PWR monitor & save To CSV file
' Created on 2023-10-09 ToniG
' Last Update 2023-10-17
' V0.10 - In Dev...
'
' KWS-AC301L_logcollect.py used for reference - Thanks kutasg'
'-------------------------------------------------
' This program is WIP....
'TooDoo:
' Startup init File
' Error Handling
' Log time period issue
' Display end of log (API does not have AppendText, only SetText)
'
'
#Include "WinGUI.bi"
#Include "AC301L_Logger.bi"
Dim Shared As HWND Window_Main, LogWindow, Editor2, FnameTextBox, FnameEditBox, COMnTextBox, Btn_StrtLog, Btn_StopLog, Btn_Copy, Btn_TstCom, Btn_ClrLog, Btn_Fname, Btn_Exit, Group1
Dim Shared As HWND Edit_Font, Check1, Button_State, Radio1, Radio2, Group2
Dim Shared As HFONT hFont
Dim Shared As HWND Label_txt2
Dim As MSG msg ' Shared vars in dev...
Dim As Long x0, y0, W1, H1, Rpos, Vpos1, Vpos2
Dim As Integer Chk1State, Chk2State, BtnX, pos1, pos2
Dim As String Text1, Text2, HelpTxt1, FnameText
Dim Shared As String CR_LF, CSV_Line, LogWindowText, CsvHdr, FileHdr, Time_, Date_
Dim Shared As Double Start1
Dim Shared As Integer LineNo 'LogStart 'StopLog
Dim Shared As Byte LogState ' 4 states of logging (start, stopped, running, paused)
Const Strt_ = 10
Const Stop_ = 20
Const Run_ = 30
Const Paus_ = 40
'#define ID_TIMER 1
Declare Sub LogError (InMessage As String, Origin As String = "")
Declare Sub MsgBox (Window_Main As HWND, InMessage As String, Origin As String)
Declare Sub Get_Data
Declare Sub ChkEvent
' Change to Constants...
W1 = 1050 ' Window Width
H1 = 720 ' Window Height
Vpos1 = 40 ' Editor 1
Vpos2 = 410 ' Editor 2
Rpos = 210 ' Right ref
BtnX = 30 ' Button x ref
CR_LF = Chr(13, 10)
Text1 = "Input: DataLog Window. "
'Text2 = "Output: Data Table. "
' Note: --* Position & size are set in resize event *--
' Create a window with text editor, buttons, etc...
Window_Main = Window_New (500, 100, W1, H1, "AC301L PWR Mon Logger V0.10 2023.10.23")
' X Y W H
LogWindow = Editor_New (20, 40, 800, 500, "",, Window_Main)
' FnameTextBox = EditBox_New (W1-200, 210, 175, 20, "DataLog_01.csv", WS_TABSTOP Or ES_READONLY, Window_Main)
FnameTextBox = EditBox_New (W1-200, 210, 175, 20, "DataLog_01.csv",, Window_Main)
COMnTextBox = EditBox_New (W1-200, 235, 50, 20, "COM3",, Window_Main)
Var Label_txt1 = Label_New (30, Vpos1 -20, 400, 20, Text1,, Window_Main)
Label_txt2 = Label_New (700, Vpos1 -20, 350, 20, "Logger Stopped ",, Window_Main) '< not "Var xxx" on this line to enable change text
'Var Label_txt2 = Label_New (30, Vpos2 - 20, 800, 20, Text2,, Window_Main)
Btn_TstCom = Button_New (W1-180, 100, 100, 40, "Test Comm",, Window_Main)
Btn_ClrLog = Button_New (W1-180, 100, 100, 40, "Clear Log",, Window_Main)
Btn_Fname = Button_New (W1-195, 160, 100, 40, "File Name",, Window_Main)
Btn_StrtLog = Button_New (W1-180, 100, 100, 40, "Start Log",, Window_Main)
Btn_StopLog = Button_New (W1-180, 100, 100, 40, "Stop Log",, Window_Main)
Btn_Copy = Button_New (W1-180, 100, 100, 40, "Copy All",, Window_Main)
Btn_Exit = Button_New (W1-180, 100, 100, 40, "EXIT",, Window_Main)
Check1 = CheckBox_New (W1-180, 100, 150, 20, "Remember settings",, Window_Main)
' Check2 = CheckBox_New (W1-180, 100, 150, 20, "Include String Len",, Window_Main)
CheckBox_SetCheck (Check1, 0)
' CheckBox_SetCheck (Check2, 0)
Group2 = GroupBox_New (W1-180, 100, 100, 70, "Index Pointers", Window_Main)
Radio1 = RadioButton_New (W1-180, 100, 100, 20, "Start Values", WS_GROUP, Window_Main) 'new group of radio buttons
Radio2 = RadioButton_New (W1-180, 100, 100, 20, "Start - End Values",, Window_Main)
Group1 = GroupBox_New (W1-180, 100, W1-10, H1-10, "", Window_Main) ' Main window border
' X, Y, W, H, are set in Window resize event (& form open)
RadioButton_SetCheck(Radio1, 1)
' Fonts
'-----------------------------------
hFont = Control_Createfont("Courier New",,, FW_BOLD)
Control_SetFont(LogWindow), hFont
Control_SetFont(Editor2), hFont
' Quick Help splash
'-------------------------------
HelpTxt1 = CR_LF + "Info:"
HelpTxt1 &= CR_LF + " Simple DataLogger for AC301-L Power Display, NOT tested yet on real hardware" + CR_LF
HelpTxt1 &= CR_LF + " Comms is RS485 (2 wire Bidirectional 5V differential signal) "
HelpTxt1 &= CR_LF + " * There is no error checking yet (program may hang on error) "
HelpTxt1 &= CR_LF + " * ."
HelpTxt1 &= CR_LF + " "
HelpTxt1 &= CR_LF + " ComTest gets 1 record from AC301-L "
HelpTxt1 &= CR_LF + " While each log is retrieved buttons are un-responsive "
HelpTxt1 &= CR_LF + " "
HelpTxt1 &= CR_LF + " It is advised to put 10V TVS protection devices on each 485 line to Mains EARTH !"
HelpTxt1 &= CR_LF + " The AC301 display is a Mains voltage device, leakage or fault may damage connected equipment"
HelpTxt1 &= CR_LF + " or electric shock hazard. Could also fit a trusted RS485 Isolator"
HelpTxt1 &= CR_LF + " AC301-L has isolated comms but do you trust these cheap products !!!"
HelpTxt1 &= CR_LF + " [Circuit not assesed yet]"
HelpTxt1 &= CR_LF + CR_LF + " Edit the filename text "
HelpTxt1 &= CR_LF + CR_LF + " --- This App is WIP, expect some issues --- "
EditBox_SetText(LogWindow, HelpTxt1)
'
FileHdr = "Data Log from AC301L AVPower Meter display"
CsvHdr = "Record"+", " + Fieldname(1) + ", " + Fieldname(2) + ", " + Fieldname(3) + ", " + Fieldname(4) _
+ ", " + Fieldname(5) + ", " + Fieldname(6) + ", " + Fieldname(7) + ", " + Fieldname(8) + ", " + Fieldname(9) + ", " + "TimeStamp" + ", " + "Log Date"
LogState = Stop_ 'initial state
' Datalogging
'---------------------------------------------------
Sub StartLog 'Open files & write headers
Date_ = Date
' Date_ = Format(Date_, yyyy-mm-dd)Date ' < Not Working...
LogLineNum = 0
FnumCOM = FreeFile
' Open Com COMn & ":9600,n,8,1,CD,CS,DS,RS,BIN" For Binary As FnumCOM' #2 ' (control lines disable)
FnumCSV = FreeFile
Open LogFileName For Binary As FnumCSV
EditBox_SetText(LogWindow, (FileHdr + " " +Date_ + CR_LF + CR_LF))
LogWindowText = EditBox_GetText(LogWindow)
'LogWindowText &= CsvHdr + CR_LF
EditBox_SetText(LogWindow, (LogWindowText + CsvHdr + CR_LF))
'EditBox_SetText(LogWindow, LogWindowText)
Print #FnumCSV, CsvHdr
End Sub
Sub Get_Data
Read_AC301 (FnumCOM, SendReq())
Write_LogFile (FnumCSV,SendReq()) ' get data & save each record
LogLineNum += 1
'' Start1 = Timer ' reset log period counter
End Sub
Sub Read_AC301 (FnumCOM As Byte, SendReq() As LongInt)
Dim LP1 As Integer
Time_ = Time
Date_ = Date
For LP1 = 1 To 9
Put #FnumCOM,, SendReq(LP1) ' request data from AC301
'' Print Err <DEBUG
Sleep 25 ' wait ms... for TX done before read value from buffer array
'Value(LP1) = Val(Input(LOC(1), 2)) '<- Just for now until know input...
' Get #COMn,, ReadValue(LP)
'ReadValue(LP1) = Val(ReadValue(LP1))
' ReadValue(LP1) = ReadValue(LP1) * Multiplier(LP1)
Next
End Sub
Sub Write_LogFile (FnumCSV As Byte,SendReq() As LongInt)
Dim LP1 As Integer
' Build CSV line
CSV_Line = Str(LogLineNum)+ ", "
For LP1 = 1 To 9
' Put #FnumCSV,, Str(SendReq(LP1))
CSV_Line &= Str(LogValue(LP1)) '+ " "
If LP1 < 9 Then CSV_Line &= ", " 'Else CSV_Line &= CR_LF
' Print #FnumCSV, Str(SendReq(LP1));", ";
Next
CSV_Line &= ", " + Time_ + ", " +Date_
LogWindowText = EditBox_GetText(LogWindow) ' Windows.bi does not have 'AppendText'
' LogWindowText &= CSV_Line + CR_LF
EditBox_SetText(LogWindow, (LogWindowText + CSV_Line + CR_LF))
' EditBox_SetText(LogWindow, LogWindowText)
Print #FnumCSV, CSV_Line
' Print #FnumCSV,
End Sub
'---------------------------------------------------
SetTimer(Window_Main, 0, 1000, 0 ) '<4th>
Do 'Main loop to check WinAPI event states:
WaitEvent(Window_Main, msg)
Select Case msg.hwnd
' Select Case msg.message '<4th> '< Timer works but with inconsistent period [but no buttons events]
Case WM_TIMER '<4th>
If LogState = Run_ Then Get_Data
' Get_Data '<<<-- DEBUG ONLY to test timer
Case Btn_TstCom
If msg.message = WM_LBUTTONUP Then
EditBox_Paste(LogWindow)
End If
Case Btn_ClrLog
If msg.message = WM_LBUTTONUP Then
' EditBox_Clear(LogWindow) '< This clears selected text
EditBox_SetText(LogWindow,"")
LogWindowText = ""
End If
Case Btn_Fname
If msg.message = WM_LBUTTONDOWN Then
' FnameText = InputBox(1000, 100, 300, "LogFile", "Enter FileName:", "DataLog_01.csv")
' EditBox_SetText(FnameTextBox, FnameText)
End If
Case Btn_StrtLog
If msg.message = WM_LBUTTONUP Then
'EditBox_GetText(Edit_Text)
If LogState = Stop_ Then
LogFileName = EditBox_GetText(FnameTextBox)
SetWindowText(Btn_StrtLog, "Pause Log") ' windows.bi command
StartLog
LogState = Run_
Else
If LogState = Run_ Then
LogState = Paus_
SetWindowText(Btn_StrtLog, "Continue")
Else
If LogState = Paus_ Then LogState = Run_
SetWindowText(Btn_StrtLog, "Pause Log")
End If
EndIf
' Start1 = Timer
End If
Case Btn_StopLog
If msg.message = WM_LBUTTONUP Then
LogState = Stop_
Close FnumCSV
Close FnumCOM
SetWindowText(Btn_StrtLog, "Start Log")
End If
Case Btn_Exit
If msg.message = WM_LBUTTONUP Then
' SendMessage(Window_Main, WM_CLOSE,0,0)' this just removed KBD focus
' DestroyWindow(Window_Main) '< Close window but exe still run as task
' PostQuitMessage(0) '< Seems to do nothing
Exit Do '< Exit Application ok
End If
Case Btn_Copy
If msg.message = WM_LBUTTONUP Then
SetFocus(LogWindow) '< This SelectALL!
SendMessage(LogWindow, EM_SETSEL, 0, -1) '< SelectAll(Does not work)
pos1 = LoWord(SendMessage(LogWindow, EM_GETSEL, 0, 0))
pos2 = HiWord(SendMessage(LogWindow, EM_GETSEL, 0, 0))
EditBox_Copy(LogWindow)
'Print "pos1="; pos1; "pos2="; pos2 ' <DEBUG
End If
Case Else
'Resize/Repos Controls x if window size change
Window_GetSize(Window_Main, x0, y0, W1, H1)
Control_Resize(LogWindow, 20, Vpos1, W1-Rpos-10, 630)
'Control_Resize(Editor2, 20, Vpos2, W1-Rpos, 250)
Control_Resize(FnameTextBox, W1-185, 210, 175, 20)
Control_Resize(COMnTextBox, W1-185, 235, 50, 20)
''COMnTextBox = EditBox_New (W1-200, 235, 50, 20, "COM3",, Window_Main)
' Control_Resize(InputBox, W1-(Rpos-300), Vpos1 + 170, 300) 'InputBox doesnt have height value so cant 'Control_Resize'
'Control_Resize(InputBox, 100, 100, 300, "LogFile", "Enter FileName:", "DataLog_01.csv")
Control_Resize(Btn_TstCom, W1-(Rpos-BtnX), Vpos1, 100, 40)
Control_Resize(Btn_ClrLog, W1-(Rpos-BtnX), Vpos1 + 60, 100, 40)
Control_Resize(Btn_Fname, W1-(Rpos-BtnX), Vpos1 + 120, 100, 40)
Control_Resize(Btn_StrtLog, W1-(Rpos-BtnX), Vpos1 + 220, 100, 40)
Control_Resize(Btn_StopLog, W1-(Rpos-BtnX), Vpos1 + 280, 100, 40)
Control_Resize(Btn_Copy, W1-(Rpos-BtnX), Vpos2 + 150, 100, 40)
Control_Resize(Btn_Exit, W1-(Rpos-BtnX), H1- 60, 100, 40)
Control_Resize(Check1, W1-(Rpos-BtnX), Vpos1 + 350, 160, 20)
' Control_Resize(Check2, W1-(Rpos-BtnX), Vpos1 + 315, 160, 20)
Control_Resize(Group2, W1-(Rpos-(BtnX)+4), Vpos1 + 40 + 365, 165, 70)
Control_Resize(Radio1, W1-(Rpos-BtnX), Vpos1 + 40 + 385, 150, 20) 'new group of radio buttons
Control_Resize(Radio2, W1-(Rpos-BtnX), Vpos1 + 40 + 410, 150, 20)
Control_Resize(Group1,x0+7, y0+5, W1-13, H1-11) '< Main window border
' W1 = 1050, H1 = 720, Vpos1 = 40, Vpos2 = 410, Rpos = 210, BtnX = 30
End Select
' this might not need here if shared As
Chk1State = CheckBox_GetCheck(Check1) ' Capture state of checkbox
'-------------------------------------------------
'' This works with 'Start1 = Timer' set in GetData Sub, but only correct period if mous moved over window.
' If LogState = Run_ Then
' If Timer > Start1+LogInterval Then Get_Data ' 1 line at a time
' EndIf
'-------------------------------------------------
If LogState = Stop_ Then LogLineNum = 0
If LogState = Stop_ Then Label_SetText(Label_txt2, "Logger Stopped " )
If LogState = Paus_ Then Label_SetText(Label_txt2, "Logger Paused " )
If LogState = Strt_ Then Label_SetText(Label_txt2, "Logger Starting " )
If LogState = Run_ Then Label_SetText(Label_txt2, "Logger Running " )
Loop Until Window_Event_Close(Window_Main, msg)
Control_DeleteFont(hFont) ' < If exit pressed
End
'Wait until window is closed:
Do
WaitEvent(Window_Main, msg) ' How to test this code(file write?)
Loop Until Window_Event_Close(Window_Main, msg)
'Delete font:
'' Control_DeleteFont(hFont)
End
AC301L_Logger.bi
Code: Select all
' Freebasic code - ToniG 2023.10.13 V0.1
'Arrays & inits inc for AC301L Logger 'AC301L_GUI_Logger.bas'
' Original python code used for reference & snippets. - Thanks kutasg
' This program is WIP....
Dim Shared SendReq(1 To 9) As LongInt
Dim Shared ReadValue(1 To 9) As Double => {0, 0, 0, 0, 0, 0, 0, 0, 0} ' Value from AC301
Dim Shared LogValue(1 To 9) As Double => {0, 0, 0, 0, 0, 0, 0, 0, 0} ' Value save to logfile
Dim Shared Fieldname (1 To 9) As String
Dim Shared Multiplier(1 To 9) As Double
Dim Shared LogFileName As String
Dim Shared As Integer StopLog, FnumCOM, FnumCSV, LogLineNum
'Dim As LongInt LogInterval 's
Dim Shared As Double LogInterval
'Dim As Long Start1, LogInterval
'Dim As Integer LP1
Dim Shared As String COMn
'Dim Shared
'Declare Sub OpenIO()
'Declare Sub CloseIO()
Declare Sub Process_Data()
Declare Sub Write_LogFile(FnumCSV As Byte,SendReq() As LongInt)
Declare Sub Read_AC301(As Byte, () As LongInt) ' (COMn, Array)
Declare Sub PrintLog (LogWindow As HWND, CSV_Line As String)
' Defaults & init values
'-------------------------
' CSV list Header
Fieldname(1) = "Volt"
Fieldname(2) = "Amp"
Fieldname(3) = "Watt"
Fieldname(4) = "Time"
Fieldname(5) = "kWh"
Fieldname(6) = "PF"
Fieldname(7) = "??"
Fieldname(8) = "Hz"
Fieldname(9) = "degC"
'Default multipliers
Multiplier(1) = 10.0
Multiplier(2) = 1000.0
Multiplier(3) = 10.0
Multiplier(4) = 1
Multiplier(5) = 1000.0
Multiplier(6) = 100.0
Multiplier(7) = 1
Multiplier(8) = 10.0
Multiplier(9) = 1
'Value(1) = 0
' Send requests to AC301L
SendReq(1) = &h0203000E0001E5FA
SendReq(2) = &h0203000F0002F43B
SendReq(3) = &h020300110002943D
SendReq(4) = &h02030019000155FE
SendReq(5) = &h020300170002743C
SendReq(6) = &h0203001D0001143F
SendReq(7) = &h0203001F0001B5FF
SendReq(8) = &h0203001E0001E43F
SendReq(9) = &h0203001A0001A5FE
' Temp for tsting values
LogValue(1) = 235
LogValue(2) = 5.3
LogValue(3) = 1245.5
LogValue(4) = 46
LogValue(5) = 1057.6
LogValue(6) = 0.90
LogValue(7) = 235
LogValue(8) = 50.0
LogValue(9) = 29.4
' LogInterval = 0.75 ' seconds
' COMn = "COM1"
'-------------------------