package main import ( "fmt" "powerpod/gotool/pb" "google.golang.org/protobuf/proto" ) // accelSamplesFromCacheStatus maps combined CACHE_STATUS entries to AccelSample // (for dashboard / WebSocket accel push). func accelSamplesFromCacheStatus(r *pb.CacheStatusResponse) []*pb.AccelSample { if r == nil { return nil } out := make([]*pb.AccelSample, 0, len(r.GetClients())) for _, c := range r.GetClients() { if c.GetAccel() == nil { continue } a := c.GetAccel() out = append(out, &pb.AccelSample{ ClientId: c.GetClientId(), Valid: a.GetValid(), X: a.GetX(), Y: a.GetY(), Z: a.GetZ(), AgeMs: a.GetAgeMs(), }) } return out } // tapEventsFromCacheStatus maps combined CACHE_STATUS entries to TapEvent // (only clients with a consumed pending tap). func tapEventsFromCacheStatus(r *pb.CacheStatusResponse) []*pb.TapEvent { if r == nil { return nil } out := make([]*pb.TapEvent, 0, len(r.GetClients())) for _, c := range r.GetClients() { if c.GetTap() == nil { continue } t := c.GetTap() out = append(out, &pb.TapEvent{ ClientId: c.GetClientId(), Valid: true, Kind: t.GetKind(), AgeMs: t.GetAgeMs(), }) } return out } // cacheStatusFromBLEStreamPayload parses a framed BLE_STREAM_TICK payload // (type byte + protobuf UartMessage) into a CacheStatusResponse-shaped view. func cacheStatusFromBLEStreamPayload(payload []byte) (*pb.CacheStatusResponse, error) { tick, err := parseBleStreamTickPayload(payload) if err != nil { return nil, err } return &pb.CacheStatusResponse{Clients: tick.GetClients()}, nil } func parseBleStreamTickPayload(payload []byte) (*pb.BleStreamTick, error) { if len(payload) < 2 { return nil, fmt.Errorf("BLE stream tick too short") } if payload[0] != byte(pb.MessageType_BLE_STREAM_TICK) { return nil, fmt.Errorf("unexpected BLE tick type 0x%02x", payload[0]) } var msg pb.UartMessage if err := proto.Unmarshal(payload[1:], &msg); err != nil { return nil, err } tick := msg.GetBleStreamTick() if tick == nil { return nil, fmt.Errorf("missing ble_stream_tick") } return tick, nil }