1- import { Menu , Box , Text , Stack , Container , Group , NumberInput , Select , Table , ActionIcon , Button } from "@mantine/core" ;
1+ import {
2+ Menu ,
3+ Box ,
4+ Text ,
5+ Stack ,
6+ Container ,
7+ Group ,
8+ NumberInput ,
9+ Select ,
10+ Table ,
11+ ActionIcon ,
12+ Button ,
13+ } from "@mantine/core" ;
214import { IconCaretDownFilled , IconRefresh } from "@tabler/icons-react" ;
315import { useEffect , useState } from "react" ;
416import { Read } from "../../wailsjs/go/main/App" ;
@@ -19,12 +31,14 @@ export enum dataTypes {
1931export function ReadTable ( ) {
2032 // rawData array of modbusData
2133 const [ rawData , setRawData ] = useState < modbusData [ ] > ( [ ] ) ;
22- const [ typeArray , setTypeArray ] = useState < dataTypes [ ] > ( Array ( rawData . length ) . fill ( dataTypes . U16 ) ) ;
23- const [ error , setError ] = useState < string > ( '' )
34+ const [ typeArray , setTypeArray ] = useState < dataTypes [ ] > (
35+ Array ( rawData . length ) . fill ( dataTypes . U16 )
36+ ) ;
37+ const [ error , setError ] = useState < string > ( "" ) ;
2438
2539 // Form data TODO: replace with mantine form handler
26- const [ address , setAddress ] = useState < string | number > ( '' ) ;
27- const [ quantity , setQuantity ] = useState < string | number > ( '' ) ;
40+ const [ address , setAddress ] = useState < string | number > ( "" ) ;
41+ const [ quantity , setQuantity ] = useState < string | number > ( "" ) ;
2842 const [ type , setReadType ] = useState < string > ( "Holding Register" ) ;
2943
3044 // Update the array of data types whenever the number of fields returned changes.
@@ -36,62 +50,77 @@ export function ReadTable() {
3650
3751 // Copy of raw data as getting the typed data consumes the array.
3852 const rawDataCopy = [ ...rawData ] ;
39- const typedData : ( { address : number , value : any } | undefined ) [ ] = typeArray . map ( ( type , i ) => {
40- // Iterate through the array of data types and convert respectively.
41- // Consumes the array since there will be a different number of output elements depending
42- // on the data types selected
43- if ( rawDataCopy . length == 0 ) return { address : 0 , value : 0 } ;
44- switch ( type ) {
45- case dataTypes . BIN :
46- {
53+ const typedData : ( { address : number ; value : any } | undefined ) [ ] =
54+ typeArray . map ( ( type , i ) => {
55+ // Iterate through the array of data types and convert respectively.
56+ // Consumes the array since there will be a different number of output elements depending
57+ // on the data types selected
58+ if ( rawDataCopy . length == 0 ) return { address : 0 , value : 0 } ;
59+ switch ( type ) {
60+ case dataTypes . BIN : {
4761 const val = rawDataCopy . shift ( ) ;
4862 // Convert to binary showing leading zeros
49- const stringVal = val ! . Value . toString ( 2 ) . padStart ( 16 , '0' )
50- const strings = stringVal . match ( / .{ 1 , 4 } / g)
51- return { address : val ! . Address , value : strings ?. join ( ' ' ) } ;
63+ const stringVal = val ! . Value . toString ( 2 ) . padStart ( 16 , "0" ) ;
64+ const strings = stringVal . match ( / .{ 1 , 4 } / g) ;
65+ return { address : val ! . Address , value : strings ?. join ( " " ) } ;
5266 }
53- case dataTypes . U16 :
54- {
67+ case dataTypes . U16 : {
5568 const val = rawDataCopy . shift ( ) ;
5669 return { address : val ! . Address , value : val ! . Value } ;
5770 }
58- case dataTypes . U32 :
59- {
71+ case dataTypes . U32 : {
6072 const val1 = rawDataCopy . shift ( ) ;
6173 const val2 = rawDataCopy . shift ( ) ;
62- return { address : val1 ! . Address , value : ( ( val1 ! . Value << 16 ) >>> 0 ) + ( val2 ! . Value >>> 0 ) } ;
74+ return {
75+ address : val1 ! . Address ,
76+ value : ( ( val1 ! . Value << 16 ) >>> 0 ) + ( val2 ! . Value >>> 0 ) ,
77+ } ;
6378 }
64- case dataTypes . I16 :
65- {
79+ case dataTypes . I16 : {
6680 const val = rawDataCopy . shift ( ) ;
6781 const value = val ! . Value ;
6882 // Convert U16 to I16 using 2's complement
69- const signedValue = value > 0x7FFF ? value - 0x10000 : value ;
83+ const signedValue = value > 0x7fff ? value - 0x10000 : value ;
7084 return { address : val ! . Address , value : signedValue } ;
7185 }
72- case dataTypes . I32 :
73- {
86+ case dataTypes . I32 : {
7487 const val1 = rawDataCopy . shift ( ) ;
7588 const val2 = rawDataCopy . shift ( ) ;
7689 const combinedValue = ( val1 ! . Value << 16 ) + val2 ! . Value ;
77- const signedValue = combinedValue > 0x7FFFFFFF ? combinedValue - 0x100000000 : combinedValue ;
90+ const signedValue =
91+ combinedValue > 0x7fffffff
92+ ? combinedValue - 0x100000000
93+ : combinedValue ;
7894 return { address : val1 ! . Address , value : signedValue } ;
7995 }
80- case dataTypes . F32 :
81- {
96+ case dataTypes . F32 : {
8297 const val1 = rawDataCopy . shift ( ) ;
8398 const val2 = rawDataCopy . shift ( ) ;
84- const u32 = new Uint32Array ( [ ( ( val1 ! . Value << 16 ) >>> 0 ) + ( val2 ! . Value >>> 0 ) ] )
85- return { address : val1 ! . Address , value : new Float32Array ( u32 . buffer ) [ 0 ] } ;
99+ const u32 = new Uint32Array ( [
100+ ( ( val1 ! . Value << 16 ) >>> 0 ) + ( val2 ! . Value >>> 0 ) ,
101+ ] ) ;
102+ let val = new Float32Array ( u32 . buffer ) [ 0 ] ;
103+ let displayVal = "" ;
104+ if ( val < 1 ) {
105+ displayVal = val . toPrecision ( 4 ) ;
106+ } else if ( val % 1 < 0.001 ) {
107+ displayVal = val . toFixed ( 0 ) ;
108+ } else {
109+ displayVal = val . toFixed ( 3 ) ;
110+ }
111+ return {
112+ address : val1 ! . Address ,
113+ value : displayVal ,
114+ } ;
86115 }
87- }
88- } ) ;
116+ }
117+ } ) ;
89118
90119 // Sets an index to an array type. Needs to also handle removing or re-adding the following element
91120 // depending on the number of registers the type requires
92121 function setType ( i : number , type : dataTypes ) {
93122 if ( typeArray [ i ] === type ) {
94- return
123+ return ;
95124 }
96125 switch ( type ) {
97126 // 16 bit types
@@ -101,7 +130,11 @@ export function ReadTable() {
101130 setTypeArray ( ( prev ) => {
102131 let previousType = prev [ i ] ;
103132 prev [ i ] = type ;
104- if ( previousType === dataTypes . U32 || previousType === dataTypes . I32 || previousType === dataTypes . F32 ) {
133+ if (
134+ previousType === dataTypes . U32 ||
135+ previousType === dataTypes . I32 ||
136+ previousType === dataTypes . F32
137+ ) {
105138 prev . splice ( i + 1 , 0 , dataTypes . U16 ) ;
106139 }
107140 return [ ...prev ] ;
@@ -118,9 +151,17 @@ export function ReadTable() {
118151 let previousType = prev [ i ] ;
119152 prev [ i ] = type ;
120153 // if previous type was 16 bit
121- if ( previousType === dataTypes . U16 || previousType === dataTypes . I16 || previousType === dataTypes . BIN ) {
154+ if (
155+ previousType === dataTypes . U16 ||
156+ previousType === dataTypes . I16 ||
157+ previousType === dataTypes . BIN
158+ ) {
122159 // if next type in a rray is 32 bit then convert it back to 16 bit as the first register has just been nicked
123- if ( prev [ i + 1 ] === dataTypes . U32 || prev [ i + 1 ] === dataTypes . I32 || prev [ i + 1 ] === dataTypes . F32 ) {
160+ if (
161+ prev [ i + 1 ] === dataTypes . U32 ||
162+ prev [ i + 1 ] === dataTypes . I32 ||
163+ prev [ i + 1 ] === dataTypes . F32
164+ ) {
124165 prev [ i + 1 ] = dataTypes . U16 ;
125166 } else {
126167 prev . splice ( i + 1 , 1 ) ;
@@ -135,103 +176,169 @@ export function ReadTable() {
135176 // Call the read function from the go backend
136177 function ReadModbus ( ) {
137178 if ( address === "" || quantity === "" ) {
138- setError ( "Enter an address and quantity." )
139- setRefreshRate ( "None" )
140- return
179+ setError ( "Enter an address and quantity." ) ;
180+ setRefreshRate ( "None" ) ;
181+ return ;
141182 }
142183 Read ( type , address as number , quantity as number )
143184 . then ( ( data ) => {
144185 if ( data . length < rawData . length ) {
145186 setTypeArray ( Array ( data . length ) . fill ( dataTypes . U16 ) ) ;
146187 }
147188 setRawData ( data ) ;
148- setError ( '' )
189+ setError ( "" ) ;
149190 } )
150191 . catch ( ( err ) => {
151- setError ( err )
152- setRefreshRate ( "None" )
192+ setError ( err ) ;
193+ setRefreshRate ( "None" ) ;
153194 notifications . show ( {
154195 title : "Failed to Read" ,
155- message : err
156- } )
196+ message : err ,
197+ } ) ;
157198 } ) ;
158199 }
159200
160- let content = error ? ( < Text > { error } </ Text > ) : (
161- < ResultDisplay type = { type } typeArray = { typeArray } typedData = { typedData } setType = { setType } />
162- )
201+ let content = error ? (
202+ < Text > { error } </ Text >
203+ ) : (
204+ < ResultDisplay
205+ type = { type }
206+ typeArray = { typeArray }
207+ typedData = { typedData }
208+ setType = { setType }
209+ />
210+ ) ;
163211
164- const [ refreshRate , setRefreshRate ] = useState < string > ( "None" )
212+ const [ refreshRate , setRefreshRate ] = useState < string > ( "None" ) ;
165213 const [ opened , setOpened ] = useState ( false ) ;
166214
167215 useEffect ( ( ) => {
168216 // Don't auto fetch if set to none or the menu is open
169217 if ( refreshRate == "None" || opened ) return ;
170- let refresh = 0
218+ let refresh = 0 ;
171219 switch ( refreshRate ) {
172220 case "1s" :
173221 refresh = 1000 ;
174- break
222+ break ;
175223 case "2s" :
176224 refresh = 2000 ;
177- break
225+ break ;
178226 case "5s" :
179227 refresh = 5000 ;
180- break
228+ break ;
181229 case "10s" :
182230 refresh = 10000 ;
183- break
231+ break ;
184232 case "30s" :
185233 refresh = 30000 ;
186- break
234+ break ;
187235 }
188- const interval = setInterval ( ReadModbus , refresh )
189- return ( ) => clearInterval ( interval )
190- } , [ refreshRate , address , quantity , opened ] ) // Needs to depend on all of these or ReadModbus will become out of date compared to the inputs
191-
236+ const interval = setInterval ( ReadModbus , refresh ) ;
237+ return ( ) => clearInterval ( interval ) ;
238+ } , [ refreshRate , address , quantity , opened ] ) ; // Needs to depend on all of these or ReadModbus will become out of date compared to the inputs
192239
193240 return (
194241 < Stack >
195242 < Group justify = "" >
196- < NumberInput label = "Start Register:" min = { 0 } placeholder = "Start Register" size = "xs"
197- radius = "xs" onChange = { setAddress } />
198- < NumberInput placeholder = "Quantity" label = "Quantity:" size = "xs" min = { 1 } max = { 125 }
199- radius = "xs" onChange = { setQuantity } />
200- < Select data = { [ "Holding Register" , "Discrete Input" , "Input Register" , "Coil" ] } value = { type } size = "xs" label = "Register Type"
201- radius = "xs" onChange = { value => { setReadType ( value ! ) ; setRawData ( [ ] ) } } />
243+ < NumberInput
244+ label = "Start Register:"
245+ min = { 0 }
246+ placeholder = "Start Register"
247+ size = "xs"
248+ radius = "xs"
249+ onChange = { setAddress }
250+ />
251+ < NumberInput
252+ placeholder = "Quantity"
253+ label = "Quantity:"
254+ size = "xs"
255+ min = { 1 }
256+ max = { 125 }
257+ radius = "xs"
258+ onChange = { setQuantity }
259+ />
260+ < Select
261+ data = { [
262+ "Holding Register" ,
263+ "Discrete Input" ,
264+ "Input Register" ,
265+ "Coil" ,
266+ ] }
267+ value = { type }
268+ size = "xs"
269+ label = "Register Type"
270+ radius = "xs"
271+ onChange = { ( value ) => {
272+ setReadType ( value ! ) ;
273+ setRawData ( [ ] ) ;
274+ } }
275+ />
202276 < br />
203- < RefreshSelector opened = { opened } setOpened = { setOpened } refreshRate = { refreshRate } setRate = { setRefreshRate } ReadModbus = { ReadModbus } />
277+ < RefreshSelector
278+ opened = { opened }
279+ setOpened = { setOpened }
280+ refreshRate = { refreshRate }
281+ setRate = { setRefreshRate }
282+ ReadModbus = { ReadModbus }
283+ />
204284 </ Group >
205285 { content }
206286 </ Stack >
207287 ) ;
208288
209- function RefreshSelector ( props : { opened : boolean , setOpened : ( b : boolean ) => void , setRate : ( rate : string ) => void , refreshRate : string , ReadModbus : ( ) => void } ) {
289+ function RefreshSelector ( props : {
290+ opened : boolean ;
291+ setOpened : ( b : boolean ) => void ;
292+ setRate : ( rate : string ) => void ;
293+ refreshRate : string ;
294+ ReadModbus : ( ) => void ;
295+ } ) {
210296 return (
211297 < div >
212- < Button size = "xs" onClick = { props . ReadModbus } variant = "default" p = { "2px" } style = { { borderBottomRightRadius : 0 , borderTopRightRadius : 0 , borderRight : "0px" } } >
298+ < Button
299+ size = "xs"
300+ onClick = { props . ReadModbus }
301+ variant = "default"
302+ p = { "2px" }
303+ style = { {
304+ borderBottomRightRadius : 0 ,
305+ borderTopRightRadius : 0 ,
306+ borderRight : "0px" ,
307+ } }
308+ >
213309 < IconRefresh />
214310 </ Button >
215- < Menu shadow = "md" width = { 80 } opened = { props . opened } onChange = { props . setOpened } >
311+ < Menu
312+ shadow = "md"
313+ width = { 80 }
314+ opened = { props . opened }
315+ onChange = { props . setOpened }
316+ >
216317 < Menu . Target >
217- < Button size = "xs" variant = "default" style = { { borderBottomLeftRadius : 0 , borderTopLeftRadius : 0 , borderLeft : "0px" } } >
218- {
219- props . refreshRate == "None" ?
220- < IconCaretDownFilled /> : < Text > { props . refreshRate } </ Text >
221- }
318+ < Button
319+ size = "xs"
320+ variant = "default"
321+ style = { {
322+ borderBottomLeftRadius : 0 ,
323+ borderTopLeftRadius : 0 ,
324+ borderLeft : "0px" ,
325+ } }
326+ >
327+ { props . refreshRate == "None" ? (
328+ < IconCaretDownFilled />
329+ ) : (
330+ < Text > { props . refreshRate } </ Text >
331+ ) }
222332 </ Button >
223333 </ Menu . Target >
224334 < Menu . Dropdown >
225335 < Menu . Label > Refresh Rate</ Menu . Label >
226- {
227- [ "None" , "1s" , "5s" , "10s" , "30s" ] . map ( ( v ) => (
228- < Menu . Item onClick = { ( ) => props . setRate ( v ) } > { v } </ Menu . Item >
229- ) )
230- }
336+ { [ "None" , "1s" , "5s" , "10s" , "30s" ] . map ( ( v ) => (
337+ < Menu . Item onClick = { ( ) => props . setRate ( v ) } > { v } </ Menu . Item >
338+ ) ) }
231339 </ Menu . Dropdown >
232340 </ Menu >
233341 </ div >
234- )
342+ ) ;
235343 }
236344}
237-
0 commit comments