{"version":3,"file":"display-host.mjs","names":[],"sources":["../../src/hosts/display-host.ts"],"sourcesContent":["/* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD */\n/* SPDX-License-Identifier: Apache-2.0 */\n\n/**\n * In-memory BrookesiaHost for Display — Node/vitest only, not used on device.\n * Import: `@brookesia/service/hosts/display`\n */\n\nimport type { BrookesiaHost } from '../common/brookesia-host.ts';\nimport { serializeRpcError, serializeRpcResult } from '../common/rpc-json.ts';\nimport { DISPLAY_FUNCTIONS, DISPLAY_SERVICE_NAME } from '../display/display-client.ts';\nimport type {\n  DisplayOutputInfo,\n  DisplaySourceInfo,\n  DisplayTouchGestureConfig,\n} from '../display/display-types.ts';\n\ntype BacklightState = {\n  brightness: number;\n  on: boolean;\n};\n\ntype DisplayMockState = {\n  outputs: DisplayOutputInfo[];\n  sources: DisplaySourceInfo[];\n  nextSourceId: number;\n  activeSources: Map<string, string>;\n  backlight: Map<number, BacklightState>;\n  touchGesture: Map<number, DisplayTouchGestureConfig>;\n};\n\nlet nextHandle = 1;\nconst handles = new Map<number, DisplayMockState>();\n\nconst DEFAULT_OUTPUTS: DisplayOutputInfo[] = [\n  {\n    id: 1,\n    name: 'Output0',\n    width: 240,\n    height: 240,\n    pixel_format: 'RGB565',\n    slot: 'HalPanel',\n    panel_instance: 'Display:Panel0',\n    group_id: 'main_display',\n    backlight: { instance: 'Display:Backlight0', on_off_supported: true },\n  },\n];\n\nfunction defaultState(): DisplayMockState {\n  return {\n    outputs: DEFAULT_OUTPUTS.map((o) => ({ ...o })),\n    sources: [],\n    nextSourceId: 1,\n    activeSources: new Map(),\n    backlight: new Map([[1, { brightness: 100, on: true }]]),\n    touchGesture: new Map(),\n  };\n}\n\nfunction getState(handle: number): DisplayMockState {\n  const state = handles.get(handle);\n  if (!state) {\n    throw new Error(`Display memory host: invalid handle ${handle}`);\n  }\n  return state;\n}\n\nexport type DisplayHostOptions = {\n  outputs?: DisplayOutputInfo[];\n  sources?: DisplaySourceInfo[];\n};\n\nexport function createDisplayHost(options?: DisplayHostOptions): BrookesiaHost {\n  const seedOutputs = options?.outputs ?? DEFAULT_OUTPUTS;\n  const seedSources = options?.sources ?? [];\n\n  return {\n    service_available(name: string): boolean {\n      return name === DISPLAY_SERVICE_NAME;\n    },\n\n    start_service(name: string): number {\n      if (name !== DISPLAY_SERVICE_NAME) {\n        throw new Error(`Display memory host: unknown service ${name}`);\n      }\n      const handle = nextHandle++;\n      const state = defaultState();\n      state.outputs = seedOutputs.map((o) => ({ ...o }));\n      state.sources = seedSources.map((s) => ({ ...s }));\n      state.nextSourceId = Math.max(1, ...state.sources.map((s) => s.id ?? 0)) + 1;\n      handles.set(handle, state);\n      return handle;\n    },\n\n    stop_service(handle: number): void {\n      handles.delete(handle);\n    },\n\n    call_function(handle: number, functionName: string, paramsJson: string): string {\n      const state = getState(handle);\n      const params = JSON.parse(paramsJson) as Record<string, unknown>;\n\n      try {\n        if (functionName === DISPLAY_FUNCTIONS.GetOutputs) {\n          return serializeRpcResult([...state.outputs]);\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.GetSources) {\n          return serializeRpcResult([...state.sources]);\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.RegisterSource) {\n          const source = params.Source as DisplaySourceInfo;\n          const id = state.nextSourceId++;\n          state.sources.push({ ...source, id });\n          return serializeRpcResult(id);\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.UnregisterSource) {\n          const sourceName = String(params.SourceName ?? '');\n          state.sources = state.sources.filter((s) => s.name !== sourceName);\n          for (const [outputName, active] of state.activeSources) {\n            if (active === sourceName) {\n              state.activeSources.delete(outputName);\n            }\n          }\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.RequestOutput) {\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.ReleaseOutput) {\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.SetActiveSource) {\n          const outputName = String(params.OutputName ?? '');\n          const sourceName = String(params.SourceName ?? '');\n          state.activeSources.set(outputName, sourceName);\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.GetActiveSource) {\n          const outputName = String(params.OutputName ?? '');\n          return serializeRpcResult(state.activeSources.get(outputName) ?? '');\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.SetTouchGestureConfig) {\n          const outputId = Number(params.OutputId ?? 0);\n          state.touchGesture.set(outputId, { ...(params.Config as DisplayTouchGestureConfig) });\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.GetTouchGestureConfig) {\n          const outputId = Number(params.OutputId ?? 0);\n          return serializeRpcResult(state.touchGesture.get(outputId) ?? { enabled: false });\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.SetBacklightBrightness) {\n          const outputId = Number(params.OutputId ?? 0);\n          const brightness = Number(params.Brightness ?? 0);\n          const entry = state.backlight.get(outputId) ?? { brightness: 100, on: true };\n          entry.brightness = brightness;\n          state.backlight.set(outputId, entry);\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.GetBacklightBrightness) {\n          const outputId = Number(params.OutputId ?? 0);\n          const entry = state.backlight.get(outputId);\n          return serializeRpcResult(entry?.brightness ?? 0);\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.SetBacklightOnOff) {\n          const outputId = Number(params.OutputId ?? 0);\n          const on = Boolean(params.On);\n          const entry = state.backlight.get(outputId) ?? { brightness: 100, on: true };\n          entry.on = on;\n          state.backlight.set(outputId, entry);\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.GetBacklightOnOff) {\n          const outputId = Number(params.OutputId ?? 0);\n          const entry = state.backlight.get(outputId);\n          return serializeRpcResult(entry?.on ?? false);\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.LoadData) {\n          return serializeRpcResult();\n        }\n\n        if (functionName === DISPLAY_FUNCTIONS.ResetData) {\n          const outputId = Number(params.OutputId ?? 0);\n          state.backlight.set(outputId, { brightness: 100, on: true });\n          return serializeRpcResult();\n        }\n\n        return serializeRpcError(`unknown function ${functionName}`);\n      } catch (err) {\n        const message = err instanceof Error ? err.message : String(err);\n        return serializeRpcError(message);\n      }\n    },\n  };\n}\n\nexport function resetDisplayHostState(): void {\n  handles.clear();\n  nextHandle = 1;\n}\n"],"mappings":"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"}