diff --git a/angular-client/src/pages/bms-debug-page/components/cell-by-cell-heat-map/cell-by-cell-heat-map.component.ts b/angular-client/src/pages/bms-debug-page/components/cell-by-cell-heat-map/cell-by-cell-heat-map.component.ts index 56b4d662..a3f8be08 100644 --- a/angular-client/src/pages/bms-debug-page/components/cell-by-cell-heat-map/cell-by-cell-heat-map.component.ts +++ b/angular-client/src/pages/bms-debug-page/components/cell-by-cell-heat-map/cell-by-cell-heat-map.component.ts @@ -1,7 +1,7 @@ import { Component, effect, inject, input, OnInit } from '@angular/core'; import { Segment } from 'src/utils/bms.utils'; import { HeatMapService, HeatMapView } from 'src/services/heat-map.service'; -import { AlphaCells, BetaCells, CellReading, CellService } from 'src/services/cell.service'; +import { CellReading, CellService } from 'src/services/cell.service'; import { DropdownOption, SelectorConfig } from 'src/components/select-dropdown/select-dropdown.component'; import { DialogService } from 'primeng/dynamicdialog'; import { CellViewComponent } from '../cell-view/cell-view.component'; @@ -25,8 +25,8 @@ export class CellByCellHeatMapComponent implements OnInit { private heatMapService = inject(HeatMapService); private dialogService = inject(DialogService); currentSegment = input.required(); - alphaCells!: Readonly; - betaCells!: Readonly; + alphaCells!: Readonly; + betaCells!: Readonly; view = HeatMapView.Voltage; selectedCell: CellReading | undefined = undefined; cellViewSelectOptions: DropdownOption[] = [ diff --git a/angular-client/src/services/cell.service.ts b/angular-client/src/services/cell.service.ts index 46d7e7f7..43360c04 100644 --- a/angular-client/src/services/cell.service.ts +++ b/angular-client/src/services/cell.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { BMS_CONFIG } from 'src/utils/bms.config'; import { Chip, numToSegmentType, Segment } from 'src/utils/bms.utils'; import Storage from './storage.service'; import { @@ -22,14 +23,11 @@ export type CellReading = { cellNumbers: [number, number] | undefined; }; -/* 7 alpha cell reading (for 14 cells) (if we only record data for every other CellReading, or anything like that, adjacents will contain the same data for field) */ -export type AlphaCells = [CellReading, CellReading, CellReading, CellReading, CellReading, CellReading, CellReading]; -export type PerSegmentAlphaCells = [AlphaCells, AlphaCells, AlphaCells, AlphaCells, AlphaCells]; -const createSegmentAlphaCells = (segment: number): AlphaCells => { +const createSegmentCells = (segment: number, chip: Chip, count: number): CellReading[] => { return Array.from( - { length: 7 }, + { length: count }, (): CellReading => ({ - chip: Chip.Alpha, + chip, segment, temp: undefined, volt1: undefined, @@ -38,55 +36,23 @@ const createSegmentAlphaCells = (segment: number): AlphaCells => { balancing2: undefined, cellNumbers: undefined }) - ) as AlphaCells; // Type assertion here is safe due to length enforcement + ); }; -const startingPerSegmentAlphaCells: PerSegmentAlphaCells = [ - createSegmentAlphaCells(0), - createSegmentAlphaCells(1), - createSegmentAlphaCells(2), - createSegmentAlphaCells(3), - createSegmentAlphaCells(4) -]; - -/* 11 beta cells (if we only record data for every other CellReading, or anything like that, adjacents will contain the same data for field) */ -// Explicit tuple types -export type BetaCells = [CellReading, CellReading, CellReading, CellReading, CellReading, CellReading]; - -export type PerSegmentBetaCells = [BetaCells, BetaCells, BetaCells, BetaCells, BetaCells]; - -// Utility function to create a BetaCells array for a specific segment -const createSegmentBetaCells = (segment: number): BetaCells => { - return Array.from( - { length: 6 }, - (): CellReading => ({ - chip: Chip.Beta, - segment, - temp: undefined, - volt1: undefined, - volt2: undefined, - balancing1: undefined, - balancing2: undefined, - cellNumbers: undefined - }) - ) as BetaCells; + +const createPerSegmentCells = (chip: Chip, cellsPerSegment: number): CellReading[][] => { + return Array.from({ length: BMS_CONFIG.NUM_SEGMENTS }, (_, seg) => createSegmentCells(seg, chip, cellsPerSegment)); }; -// Create the main structure -const startingPerSegmentBetaCells: PerSegmentBetaCells = [ - createSegmentBetaCells(0), - createSegmentBetaCells(1), - createSegmentBetaCells(2), - createSegmentBetaCells(3), - createSegmentBetaCells(4) -]; +const startingPerSegmentAlphaCells: CellReading[][] = createPerSegmentCells(Chip.Alpha, BMS_CONFIG.ALPHA_THERM_COUNT); +const startingPerSegmentBetaCells: CellReading[][] = createPerSegmentCells(Chip.Beta, BMS_CONFIG.BETA_THERM_COUNT); @Injectable({ providedIn: 'root' }) export class CellService { private storageService: Storage; - private perSegmentAlphaCells: PerSegmentAlphaCells; - private perSegmentBetaCells: PerSegmentBetaCells; + private perSegmentAlphaCells: CellReading[][]; + private perSegmentBetaCells: CellReading[][]; constructor(storageService: Storage) { this.storageService = storageService; @@ -148,7 +114,10 @@ export class CellService { const constIndex = index; this.storageService.get(topics.betaTemp(segmentNumber, therm)).subscribe((data) => { const tempBtwnTwoCells = parseFloat(data.values[0]); - segmentBetaCells[constIndex].cellNumbers = [constIndex * 2, Math.min(constIndex * 2 + 1, 10)]; + segmentBetaCells[constIndex].cellNumbers = [ + constIndex * 2, + Math.min(constIndex * 2 + 1, BMS_CONFIG.BETA_VOLT_COUNT - 1) + ]; segmentBetaCells[constIndex].temp = tempBtwnTwoCells; }); @@ -159,7 +128,10 @@ export class CellService { const cellIndex = Math.floor(constIndex / 2); this.storageService.get(topics.betaVolt(segmentNumber, volt)).subscribe((data) => { const voltage = parseFloat(data.values[0]); - segmentBetaCells[cellIndex].cellNumbers = [cellIndex * 2, Math.min(cellIndex * 2 + 1, 10)]; + segmentBetaCells[cellIndex].cellNumbers = [ + cellIndex * 2, + Math.min(cellIndex * 2 + 1, BMS_CONFIG.BETA_VOLT_COUNT - 1) + ]; if (constIndex % 2 === 0) { segmentBetaCells[cellIndex].volt1 = voltage; } else { @@ -173,7 +145,10 @@ export class CellService { const cellIndex = Math.floor(constIndex / 2); this.storageService.get(topics.betaBurning(segmentNumber, burn)).subscribe((data) => { const balancing = parseInt(data.values[0]) === 1; - segmentBetaCells[cellIndex].cellNumbers = [cellIndex * 2, Math.min(cellIndex * 2 + 1, 10)]; + segmentBetaCells[cellIndex].cellNumbers = [ + cellIndex * 2, + Math.min(cellIndex * 2 + 1, BMS_CONFIG.BETA_VOLT_COUNT - 1) + ]; if (constIndex % 2 === 0) { segmentBetaCells[cellIndex].balancing1 = balancing; } else { @@ -184,21 +159,19 @@ export class CellService { }); }; - getAllAlphaCells = (): Readonly => { + getAllAlphaCells = (): Readonly => { return this.perSegmentAlphaCells; }; - // 0 2 4 6 8 10 12 - getAlphaCellsBySegment = (segment: number): Readonly => { + getAlphaCellsBySegment = (segment: number): Readonly => { return this.perSegmentAlphaCells[segment]; }; - getAllBetaCells = (): Readonly => { + getAllBetaCells = (): Readonly => { return this.perSegmentBetaCells; }; - // 0 2 4 6 8 10 - getBetaCellsBySegment = (segment: number): Readonly => { + getBetaCellsBySegment = (segment: number): Readonly => { return this.perSegmentBetaCells[segment]; }; } diff --git a/angular-client/src/utils/bms.config.ts b/angular-client/src/utils/bms.config.ts new file mode 100644 index 00000000..2a37fcc2 --- /dev/null +++ b/angular-client/src/utils/bms.config.ts @@ -0,0 +1,16 @@ +/** + * Central BMS configuration — change counts here to match the current accumulator. + * All segment/cell arrays and topic subscriptions derive from these values. + * + * This file is intentionally free of imports to avoid circular dependency issues + * between bms.utils.ts and topic.utils.ts. + */ +export const BMS_CONFIG = { + NUM_SEGMENTS: 5, + ALPHA_VOLT_COUNT: 14, + BETA_VOLT_COUNT: 11, + ALPHA_THERM_COUNT: 7, + BETA_THERM_COUNT: 6, + ALPHA_BURN_COUNT: 14, + BETA_BURN_COUNT: 11 +} as const; diff --git a/angular-client/src/utils/bms.utils.ts b/angular-client/src/utils/bms.utils.ts index 44e08fb1..2dc67120 100644 --- a/angular-client/src/utils/bms.utils.ts +++ b/angular-client/src/utils/bms.utils.ts @@ -1,4 +1,6 @@ import { topics } from './topic.utils'; +export { BMS_CONFIG } from './bms.config'; +import { BMS_CONFIG } from './bms.config'; export enum Chip { Alpha = 0, @@ -14,18 +16,15 @@ export const chipToString = (chip: Chip, singleLetter = false): string => { throw new Error('Invalid chip type ' + chip); } }; -export enum Segment { - Segment0 = 0, - Segment1 = 1, - Segment2 = 2, - Segment3 = 3, - Segment4 = 4 -} -export const allSegments = [Segment.Segment0, Segment.Segment1, Segment.Segment2, Segment.Segment3, Segment.Segment4]; + +/** Segment is a plain numeric index (0-based). */ +export type Segment = number; + +export const allSegments: Segment[] = Array.from({ length: BMS_CONFIG.NUM_SEGMENTS }, (_, i) => i); + export const numToSegmentType = (segment: number): Segment => { - const segmentType: Segment | undefined = segment as Segment; - if (segmentType !== undefined) { - return segmentType; + if (segment >= 0 && segment < BMS_CONFIG.NUM_SEGMENTS) { + return segment; } throw new Error('Invalid segment number ' + segment); }; @@ -37,48 +36,18 @@ export type SegmentInfo = { voltageKey: string; }; -export const segment0: SegmentInfo = { - segmentTempKey: topics.segmentTemp(Segment.Segment0), - alphaChipTempKey: topics.dieTemp(Segment.Segment0, Chip.Alpha), - betaChipTempKey: topics.dieTemp(Segment.Segment0, Chip.Beta), - voltageKey: topics.segmentVoltage(Segment.Segment0) -}; - -export const segment1: SegmentInfo = { - segmentTempKey: topics.segmentTemp(Segment.Segment1), - alphaChipTempKey: topics.dieTemp(Segment.Segment1, Chip.Alpha), - betaChipTempKey: topics.dieTemp(Segment.Segment1, Chip.Beta), - voltageKey: topics.segmentVoltage(Segment.Segment1) -}; - -export const segment2: SegmentInfo = { - segmentTempKey: topics.segmentTemp(Segment.Segment2), - alphaChipTempKey: topics.dieTemp(Segment.Segment2, Chip.Alpha), - betaChipTempKey: topics.dieTemp(Segment.Segment2, Chip.Beta), - voltageKey: topics.segmentVoltage(Segment.Segment2) -}; - -export const segment3: SegmentInfo = { - segmentTempKey: topics.segmentTemp(Segment.Segment3), - alphaChipTempKey: topics.dieTemp(Segment.Segment3, Chip.Alpha), - betaChipTempKey: topics.dieTemp(Segment.Segment3, Chip.Beta), - voltageKey: topics.segmentVoltage(Segment.Segment3) -}; - -export const segment4: SegmentInfo = { - segmentTempKey: topics.segmentTemp(Segment.Segment4), - alphaChipTempKey: topics.dieTemp(Segment.Segment4, Chip.Alpha), - betaChipTempKey: topics.dieTemp(Segment.Segment4, Chip.Beta), - voltageKey: topics.segmentVoltage(Segment.Segment4) -}; - -export const segmentInfoMap = { - [Segment.Segment0]: segment0, - [Segment.Segment1]: segment1, - [Segment.Segment2]: segment2, - [Segment.Segment3]: segment3, - [Segment.Segment4]: segment4 -}; +/** Dynamically generated map of segment index → SegmentInfo topic keys. */ +export const segmentInfoMap: Record = Object.fromEntries( + allSegments.map((seg) => [ + seg, + { + segmentTempKey: topics.segmentTemp(seg), + alphaChipTempKey: topics.dieTemp(seg, Chip.Alpha), + betaChipTempKey: topics.dieTemp(seg, Chip.Beta), + voltageKey: topics.segmentVoltage(seg) + } + ]) +); export const getConnectionDotStatusColor = (voltage: number): string => { if (voltage <= 375) { diff --git a/angular-client/src/utils/topic.utils.ts b/angular-client/src/utils/topic.utils.ts index ad68e7f8..3cd6432b 100644 --- a/angular-client/src/utils/topic.utils.ts +++ b/angular-client/src/utils/topic.utils.ts @@ -1,11 +1,12 @@ +import { BMS_CONFIG } from './bms.config'; import { Chip, chipToString, Segment } from './bms.utils'; -export const alphaTemp = (segment: Segment, cell: AlphaThermReading) => `BMS/PerCell/Alpha/${segment}/Therms/${cell}`; -export const betaTemp = (segment: Segment, cell: BetaThermReading) => `BMS/PerCell/Beta/${segment}/Therms/${cell}`; -export const alphaVolt = (segment: Segment, cell: AlphaVoltReading) => `BMS/PerCell/Alpha/${segment}/Volts/${cell}`; -export const betaVolt = (segment: Segment, cell: BetaVoltReading) => `BMS/PerCell/Beta/${segment}/Volts/${cell}`; -export const alphaBurning = (segment: Segment, cell: AlphaBurnReading) => `BMS/PerCell/Alpha/${segment}/Burning/${cell}`; -export const betaBurning = (segment: Segment, cell: BetaBurnReading) => `BMS/PerCell/Beta/${segment}/Burning/${cell}`; +export const alphaTemp = (segment: Segment, cell: number) => `BMS/PerCell/Alpha/${segment}/Therms/${cell}`; +export const betaTemp = (segment: Segment, cell: number) => `BMS/PerCell/Beta/${segment}/Therms/${cell}`; +export const alphaVolt = (segment: Segment, cell: number) => `BMS/PerCell/Alpha/${segment}/Volts/${cell}`; +export const betaVolt = (segment: Segment, cell: number) => `BMS/PerCell/Beta/${segment}/Volts/${cell}`; +export const alphaBurning = (segment: Segment, cell: number) => `BMS/PerCell/Alpha/${segment}/Burning/${cell}`; +export const betaBurning = (segment: Segment, cell: number) => `BMS/PerCell/Beta/${segment}/Burning/${cell}`; export const segmentTemp = (segment: Segment) => `BMS/Segment_Temp/${segment}`; export const segmentVoltage = (segment: Segment) => `BMS/Segment_Volt/${segment}`; export const vref = (segment: Segment, chip: Chip) => `BMS/PerCell/${chipToString(chip)}/${segment}/Vref2`; @@ -71,159 +72,13 @@ export const topics = { msgsPerSecond }; -export const enum AlphaThermReading { - Therm0 = 0 * 2, - Therm1 = 1 * 2, - Therm2 = 2 * 2, - Therm3 = 3 * 2, - Therm4 = 4 * 2, - Therm5 = 5 * 2, - Therm6 = 6 * 2 -} -export const allAlphaThermValues = [ - AlphaThermReading.Therm0, - AlphaThermReading.Therm1, - AlphaThermReading.Therm2, - AlphaThermReading.Therm3, - AlphaThermReading.Therm4, - AlphaThermReading.Therm5, - AlphaThermReading.Therm6 -]; - -export const enum BetaThermReading { - Therm0 = 0 * 2, - Therm1 = 1 * 2, - Therm2 = 2 * 2, - Therm3 = 3 * 2, - Therm4 = 4 * 2, - Therm5 = 5 * 2 -} -export const allBetaThermValues = [ - BetaThermReading.Therm0, - BetaThermReading.Therm1, - BetaThermReading.Therm2, - BetaThermReading.Therm3, - BetaThermReading.Therm4, - BetaThermReading.Therm5 -]; - -export enum BetaVoltReading { - Cell0 = 0, - Cell1 = 1, - Cell2 = 2, - Cell3 = 3, - Cell4 = 4, - Cell5 = 5, - Cell6 = 6, - Cell7 = 7, - Cell8 = 8, - Cell9 = 9, - Cell10 = 10 -} -export const allBetaVoltValues = [ - BetaVoltReading.Cell0, - BetaVoltReading.Cell1, - BetaVoltReading.Cell2, - BetaVoltReading.Cell3, - BetaVoltReading.Cell4, - BetaVoltReading.Cell5, - BetaVoltReading.Cell6, - BetaVoltReading.Cell7, - BetaVoltReading.Cell8, - BetaVoltReading.Cell9, - BetaVoltReading.Cell10 -]; -export enum AlphaVoltReading { - Cell0 = 0, - Cell1 = 1, - Cell2 = 2, - Cell3 = 3, - Cell4 = 4, - Cell5 = 5, - Cell6 = 6, - Cell7 = 7, - Cell8 = 8, - Cell9 = 9, - Cell10 = 10, - Cell11 = 11, - Cell12 = 12, - Cell13 = 13 -} -export const allAlphaVoltValues = [ - AlphaVoltReading.Cell0, - AlphaVoltReading.Cell1, - AlphaVoltReading.Cell2, - AlphaVoltReading.Cell3, - AlphaVoltReading.Cell4, - AlphaVoltReading.Cell5, - AlphaVoltReading.Cell6, - AlphaVoltReading.Cell7, - AlphaVoltReading.Cell8, - AlphaVoltReading.Cell9, - AlphaVoltReading.Cell10, - AlphaVoltReading.Cell11, - AlphaVoltReading.Cell12, - AlphaVoltReading.Cell13 -]; -export enum AlphaBurnReading { - Cell0 = 0, - Cell1 = 1, - Cell2 = 2, - Cell3 = 3, - Cell4 = 4, - Cell5 = 5, - Cell6 = 6, - Cell7 = 7, - Cell8 = 8, - Cell9 = 9, - Cell10 = 10, - Cell11 = 11, - Cell12 = 12, - Cell13 = 13 -} -export const allAlphaBurnValues = [ - AlphaBurnReading.Cell0, - AlphaBurnReading.Cell1, - AlphaBurnReading.Cell2, - AlphaBurnReading.Cell3, - AlphaBurnReading.Cell4, - AlphaBurnReading.Cell5, - AlphaBurnReading.Cell6, - AlphaBurnReading.Cell7, - AlphaBurnReading.Cell8, - AlphaBurnReading.Cell9, - AlphaBurnReading.Cell10, - AlphaBurnReading.Cell11, - AlphaBurnReading.Cell12, - AlphaBurnReading.Cell13 -]; - -export enum BetaBurnReading { - Cell0 = 0, - Cell1 = 1, - Cell2 = 2, - Cell3 = 3, - Cell4 = 4, - Cell5 = 5, - Cell6 = 6, - Cell7 = 7, - Cell8 = 8, - Cell9 = 9, - Cell10 = 10 -} -export const allBetaBurnValues = [ - BetaBurnReading.Cell0, - BetaBurnReading.Cell1, - BetaBurnReading.Cell2, - BetaBurnReading.Cell3, - BetaBurnReading.Cell4, - BetaBurnReading.Cell5, - BetaBurnReading.Cell6, - BetaBurnReading.Cell7, - BetaBurnReading.Cell8, - BetaBurnReading.Cell9, - BetaBurnReading.Cell10 -]; +/* Dynamically generated cell-index arrays derived from BMS_CONFIG */ +export const allAlphaThermValues: number[] = Array.from({ length: BMS_CONFIG.ALPHA_THERM_COUNT }, (_, i) => i * 2); +export const allBetaThermValues: number[] = Array.from({ length: BMS_CONFIG.BETA_THERM_COUNT }, (_, i) => i * 2); +export const allAlphaVoltValues: number[] = Array.from({ length: BMS_CONFIG.ALPHA_VOLT_COUNT }, (_, i) => i); +export const allBetaVoltValues: number[] = Array.from({ length: BMS_CONFIG.BETA_VOLT_COUNT }, (_, i) => i); +export const allAlphaBurnValues: number[] = Array.from({ length: BMS_CONFIG.ALPHA_BURN_COUNT }, (_, i) => i); +export const allBetaBurnValues: number[] = Array.from({ length: BMS_CONFIG.BETA_BURN_COUNT }, (_, i) => i); export enum ChipFault { VA_OV = 'VA_OV',