175 lines
No EOL
6.6 KiB
TypeScript
175 lines
No EOL
6.6 KiB
TypeScript
import { Box, Button, Checkbox, FormControlLabel, Grid2, MenuItem, Radio, RadioGroup, TextField, Tooltip, Typography } from "@mui/material";
|
|
import { Component } from "models";
|
|
import { getAddressTypes, getFriendlyName, GetSecondaryComponents, getSubtypes, Subtype } from "pbHelpers/ComponentType";
|
|
import { ComponentAvailabilityMap, DevicePositions } from "pbHelpers/DeviceAvailability";
|
|
import { GetProductAvailability } from "products/DeviceProduct";
|
|
import { pond } from "protobuf-ts/pond";
|
|
import { quack } from "protobuf-ts/quack";
|
|
import React, { useEffect, useState } from "react";
|
|
|
|
interface Props {
|
|
addressData: quack.AddressData
|
|
deviceProduct: pond.DeviceProduct
|
|
componentSelectionCallback: (component: Component[], checked: boolean) => void
|
|
availablePositions: DevicePositions
|
|
sensorNum?: number
|
|
}
|
|
|
|
export default function ScannedI2C(props: Props){
|
|
const {addressData, deviceProduct, componentSelectionCallback, availablePositions, sensorNum} = props
|
|
const [types, setTypes] = useState<quack.ComponentType[]>([])
|
|
const [subtypeOptions, setSubtypeOptions] = useState<Array<Subtype>>([])
|
|
const [selectedPrimaryType, setSelectedPrimaryType] = useState<quack.ComponentType>(quack.ComponentType.COMPONENT_TYPE_INVALID)
|
|
const [selectedPrimarySubtype, setSelectedPrimarySubtype] = useState(0)
|
|
const [added, setAdded] = useState(false)
|
|
const [addressInUse, setAddressInUse] = useState(false)
|
|
|
|
useEffect(()=>{
|
|
let types: quack.ComponentType[] = []
|
|
//find what component types use that address, this is different than the available positions passed in
|
|
//this is meant to get all possibilities according to product type and the given address, availablePositions is the restriction of what is available
|
|
let productAvailability = GetProductAvailability(deviceProduct)
|
|
if(productAvailability){
|
|
let i2cMap = productAvailability.get(quack.AddressType.ADDRESS_TYPE_I2C)
|
|
if(i2cMap){
|
|
i2cMap.forEach((val, key) => {
|
|
let addresses = val as number[] ?? []
|
|
if(addresses.length > 0 && addresses.includes(addressData.address)){
|
|
types.push(key)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
//this if can be taken out if we dont want to select the first component type by default
|
|
if(types.length > 0) {
|
|
setSelectedPrimaryType(types[0])
|
|
buildSubtypeOptions(types[0])
|
|
checkAddressAvailable(types[0])
|
|
}
|
|
setTypes(types)
|
|
},[addressData, deviceProduct])
|
|
|
|
const buildSubtypeOptions = (compType: quack.ComponentType) => {
|
|
let subtypes = getSubtypes(compType)
|
|
let validSub: Subtype[] = []
|
|
//have to exclude subtypes that are not I2C
|
|
subtypes.forEach((sub,i) => {
|
|
let addrTypes = getAddressTypes(compType, sub.key)
|
|
if (addrTypes.includes(quack.AddressType.ADDRESS_TYPE_I2C)){
|
|
validSub.push(sub)
|
|
}
|
|
})
|
|
//set the selected on to be the first in the valid selection
|
|
if(validSub.length > 0){
|
|
setSelectedPrimarySubtype(validSub[0].key)
|
|
}
|
|
setSubtypeOptions(validSub)
|
|
}
|
|
|
|
const checkAddressAvailable = (compType: quack.ComponentType) => {
|
|
let i2cMap = availablePositions as ComponentAvailabilityMap
|
|
let compAddresses = i2cMap.get(compType) ?? []
|
|
if (!compAddresses.includes(addressData.address)){
|
|
setAddressInUse(true)
|
|
}else{
|
|
setAddressInUse(false)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const componentSelected = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => {
|
|
let toAdd: Component[] = []
|
|
setAdded(checked)
|
|
//build a component with given information and defaults for the rest
|
|
let primaryComponent = Component.create()
|
|
primaryComponent.settings.type = selectedPrimaryType
|
|
primaryComponent.settings.subtype = selectedPrimarySubtype
|
|
primaryComponent.settings.addressType = quack.AddressType.ADDRESS_TYPE_I2C
|
|
primaryComponent.settings.address = addressData.address
|
|
primaryComponent.settings.expansionLine = addressData.expansionLine
|
|
primaryComponent.settings.muxLine = addressData.muxLine
|
|
|
|
primaryComponent.settings.name = getFriendlyName(selectedPrimaryType, selectedPrimarySubtype)
|
|
toAdd.push(primaryComponent)
|
|
|
|
GetSecondaryComponents(selectedPrimaryType, selectedPrimarySubtype).forEach(secComp => {
|
|
let component = Component.create()
|
|
component.settings = secComp
|
|
toAdd.push(component)
|
|
})
|
|
|
|
//return the component and the checked status to the parent
|
|
componentSelectionCallback(toAdd, checked)
|
|
}
|
|
|
|
|
|
return (
|
|
<Box sx={{marginY: 1}}>
|
|
{sensorNum && <Typography>Sensor {sensorNum}</Typography>}
|
|
<Typography variant="caption">{addressData.expansionLine !== 0 && "Expansion Line: " + addressData.expansionLine}</Typography>
|
|
{/* may also want to specify the mux line, not sure if the sensors will have a mux line though */}
|
|
{types.length > 0 ?
|
|
<React.Fragment>
|
|
<Grid2 container direction="row" alignItems="center" justifyContent="space-between">
|
|
<Grid2 size={3}>
|
|
<RadioGroup
|
|
value={selectedPrimaryType}
|
|
onChange={(_, value) => {
|
|
let v = parseInt(value)
|
|
if (!isNaN(v)){
|
|
buildSubtypeOptions(v)
|
|
checkAddressAvailable(v)
|
|
}
|
|
}}>
|
|
{types.map((type, i) => {
|
|
return (
|
|
<FormControlLabel
|
|
disabled={added}
|
|
key={i}
|
|
value={type}
|
|
control={<Radio />}
|
|
label={getFriendlyName(type)}
|
|
/>
|
|
)
|
|
})}
|
|
</RadioGroup>
|
|
</Grid2>
|
|
<Grid2 size={8}>
|
|
{subtypeOptions.length > 0 &&
|
|
<TextField
|
|
disabled={added}
|
|
value={selectedPrimarySubtype}
|
|
fullWidth
|
|
onChange={(event)=>{
|
|
let val = +event.target.value
|
|
setSelectedPrimarySubtype(val)
|
|
}}
|
|
select>
|
|
{subtypeOptions.map(s => (
|
|
<MenuItem key={s.key} value={s.key}>{s.friendlyName}</MenuItem>
|
|
))}
|
|
</TextField>
|
|
}
|
|
</Grid2>
|
|
<Grid2 size={1}>
|
|
<Tooltip
|
|
title="Add to list to be added to the device"
|
|
children={
|
|
<Checkbox
|
|
value={added}
|
|
onChange={componentSelected}
|
|
disabled={addressInUse}
|
|
/>
|
|
}
|
|
/>
|
|
|
|
</Grid2>
|
|
</Grid2>
|
|
</React.Fragment>
|
|
:
|
|
<Typography>Sensor Not Supported By Product</Typography>
|
|
}
|
|
</Box>
|
|
)
|
|
} |