package m31 import ( "fmt" "time" "onehouse/protocol" ) type topology struct { inputs []point outputs []point analog []point } func newTopology(modules []Module) (topology, error) { var result topology if len(modules) == 0 || len(modules) > 16 { return result, fmt.Errorf("topology requires one through sixteen modules") } for slot, module := range modules { inputs, outputs, analog := 0, 0, 0 switch module.Model { case HostModel, MixedModel: inputs, outputs = 8, 8 case InputModel: inputs = 16 case OutputModel: outputs = 16 case AnalogModel: analog = 8 default: return topology{}, fmt.Errorf("unsupported module model in slot %d", slot) } if (slot == 0) != (module.Model == HostModel) { return topology{}, fmt.Errorf("only slot zero must contain the host") } for channel, width := range module.PulseWidths { if channel < 0 || channel >= outputs || width < 50*time.Millisecond || width > 65535*time.Millisecond || width%time.Millisecond != 0 { return topology{}, fmt.Errorf("invalid pulse channel or width in slot %d", slot) } } for channel := range inputs { result.inputs = append(result.inputs, point{ id: fmt.Sprintf("m%d.di%d", slot, channel), address: uint16(len(result.inputs)), }) } for channel := range outputs { result.outputs = append(result.outputs, point{ id: fmt.Sprintf("m%d.do%d", slot, channel), address: uint16(len(result.outputs)), pulse: uint16(module.PulseWidths[channel] / time.Millisecond), }) } for channel := range analog { result.analog = append(result.analog, point{ id: fmt.Sprintf("m%d.ao%d", slot, channel), address: uint16(len(result.analog)), }) } } return result, nil } func (t topology) descriptor() protocol.DescriptorPayload { result := protocol.DescriptorPayload{ Manufacturer: "ebyte", Model: HostModel, Firmware: "unknown", } for _, input := range t.inputs { result.Capabilities = append(result.Capabilities, protocol.Capability{ ID: input.id, Type: "switch", ReportsState: true, }) } for _, output := range t.outputs { kind := "switch" if output.pulse != 0 { kind = "pulse" } result.Capabilities = append(result.Capabilities, protocol.Capability{ ID: output.id, Type: kind, ReportsState: output.pulse == 0, AcceptsCommands: true, }) } for _, output := range t.analog { result.Capabilities = append(result.Capabilities, protocol.Capability{ ID: output.id, Type: "voltage", ReportsState: true, AcceptsCommands: true, }) } return result }