Add doc/displays-signals.md

This commit is contained in:
Ghassan Yusuf 2025-07-23 16:45:11 +03:00
parent 7308a6f9bf
commit e59abf1d87

439
doc/displays-signals.md Normal file
View File

@ -0,0 +1,439 @@
# 📡 Taekwondo Scoring System Score Control to Display Communication
> **Version:** 1.0
> **Last Updated:** July 2025
> **Target Developer:** .NET Android (Score Control) & Android TV App Developers
> **Purpose:** Define **real-time data signals** from **Score Control Unit** to **Scoreboard** and **Upcoming Matches** displays
---
## 📌 Table of Contents
- [1. Overview](#1-overview)
- [2. System Architecture](#2-system-architecture)
- [3. Communication Protocol (TCP)](#3-communication-protocol-tcp)
- [4. Scoreboard (Live Match Display)](#4-scoreboard-live-match-display)
- [5. Upcoming Matches Screen](#5-upcoming-matches-screen)
- [6. Message Format (JSON)](#6-message-format-json)
- [7. C# Server Code (Score Control)](#7-c-server-code-score-control)
- [8. Android TV App Logic](#8-android-tv-app-logic)
- [9. Display Modes & Transitions](#9-display-modes--transitions)
- [10. Best Practices](#10-best-practices)
---
## 1. Overview
The **Score Control Unit (Android tablet)** sends **real-time data** to **two Android TVs**:
| Display | Purpose |
|--------|--------|
| **Scoreboard TV** | Live match: score, timer, fighter info |
| **Upcoming Matches TV** | Lobby: next matches, tournament flow |
All communication is:
- ✅ **Real-time**
- ✅ **Bidirectional-ready** (optional)
- ✅ **Over Wi-Fi (TCP)**
- ✅ **Zero-config for users**
---
## 2. System Architecture
```
[Score Control Tablet] → Wi-Fi → [Scoreboard TV (Port 5001)]
[Upcoming Matches TV (Port 5002)]
```
- Score Control acts as **TCP server**
- TVs act as **TCP clients**
- TVs connect at startup and **stay connected**
- Score Control **broadcasts** JSON messages
> ✅ All devices on same network (`TKD_SCORING_COURT1`)
---
## 3. Communication Protocol (TCP)
### 🔌 Connection Flow
1. TV powers on → connects to `TKD_SCORING_COURT1`
2. TV app starts → connects to tablet IP (`192.168.4.1`)
3. TV sends identity:
```
DISPLAY:NAME=TV_SCOREBOARD,TYPE=SCOREBOARD,MAC=18:3D:A2:01:02:03
```
4. Score Control registers TV
5. TV listens for JSON messages
---
## 4. Scoreboard (Live Match Display)
Displays real-time match data.
### 🖼️ 13 Display Elements
| Element | Source |
|-------|--------|
| Court Number | Match data |
| Match Number | Schedule |
| Match Timer | App timer |
| Round Counter | Match state |
| Country Flag | Fighter data |
| Country ISO3 | Fighter data |
| Team Logo | Fighter data |
| Fighter Name | Match setup |
| Fighter Score | Scoring engine |
| Fighter Fouls | Penalty tracker |
| Fighter Weight (kg) | Fighter profile |
| Weight Class & Category | Match data |
| Team Name | Fighter data |
---
### 🔄 Display Modes
| Mode | Trigger | Duration |
|------|--------|---------|
| `faceoff` | Before match | 10 sec |
| `score` | Match start | 2:00 |
| `break` | Round end | 60 sec |
| `call_to_action` | Last 10 sec of break | 10 sec |
| `winner` | Match end | 15 sec |
---
## 5. Upcoming Matches Screen
Displays next 35 matches.
### 🖼️ Display Elements
- Match number
- Red vs Blue names
- Weight class
- Round
- Scheduled time
- Tournament logo
### 🔄 Auto-Advance
- Updates when current match ends
- Pulls from CSV or cloud
- Scrolls if more than 5 matches
---
## 6. Message Format (JSON)
All messages are **JSON** and end with `\n`.
---
### 6.1 To Scoreboard TV (Port 5001)
#### `faceoff` Mode
```json
{
"mode": "faceoff",
"red": {
"name": "Kim Min-jae",
"country": "KOR",
"flag": "https://flags/kor.png",
"photo": "https://photos/kim.jpg"
},
"blue": {
"name": "Lee Jung-ho",
"country": "CHN",
"flag": "https://flags/chn.png",
"photo": "https://photos/lee.jpg"
},
"weight_class": "Men's -68kg",
"round": "Semifinal"
}
```
#### `score` Mode
```json
{
"mode": "score",
"court": "1",
"match_number": "105",
"weight_class": "Men's -68kg",
"category": "Semifinal",
"round": "2",
"timer": "01:45",
"red": {
"name": "Kim Min-jae",
"country": "KOR",
"team": "Seoul TKD Club",
"logo": "https://logos/seoul.png",
"flag": "https://flags/kor.png",
"score": 8,
"fouls": 1,
"weight_kg": 67.2
},
"blue": {
"name": "Lee Jung-ho",
"country": "CHN",
"team": "Beijing TKD",
"logo": "https://logos/beijing.png",
"flag": "https://flags/chn.png",
"score": 5,
"fouls": 2,
"weight_kg": 67.8
}
}
```
#### `break` Mode
```json
{
"mode": "break",
"ad_image": "https://ads/sponsor1.png",
"highlight_video": "https://videos/round1.mp4",
"countdown": true
}
```
#### `call_to_action` Mode
```json
{
"mode": "call_to_action",
"message": "FIGHTERS, RETURN TO THE RING!",
"timer": 10
}
```
#### `winner` Mode
```json
{
"mode": "winner",
"winner": "red",
"red": {
"name": "Kim Min-jae",
"photo": "https://photos/kim.jpg",
"final_score": 8
},
"blue": {
"name": "Lee Jung-ho",
"photo": "https://photos/lee.jpg",
"final_score": 5
},
"weight_class": "Men's -68kg",
"round": "Final",
"animation": "fireworks"
}
```
---
### 6.2 To Upcoming Matches TV (Port 5002)
```json
{
"mode": "next_matches",
"matches": [
{
"match_number": "106",
"red": "Park S.",
"blue": "Wang L.",
"weight": "+87kg",
"round": "Final",
"time": "11:30",
"category": "Men's"
},
{
"match_number": "107",
"red": "Choi M.",
"blue": "Tanaka Y.",
"weight": "-58kg",
"round": "Semifinal",
"time": "11:50",
"category": "Women's"
}
],
"tournament_name": "National Taekwondo Championship 2025",
"logo": "https://logos/tournament.png"
}
```
---
## 7. C# Server Code (Score Control)
```csharp
public class DisplayServer
{
private TcpListener _scoreboardServer;
private TcpListener _matchesServer;
private List<TcpClient> _scoreboardClients = new();
private List<TcpClient> _matchesClients = new();
public async Task Start()
{
_scoreboardServer = new TcpListener(IPAddress.Any, 5001);
_matchesServer = new TcpListener(IPAddress.Any, 5002);
_scoreboardServer.Start();
_matchesServer.Start();
_ = AcceptScoreboardClients();
_ = AcceptMatchesClients();
}
private async Task AcceptScoreboardClients()
{
while (true)
{
var client = await _scoreboardServer.AcceptTcpClientAsync();
_scoreboardClients.Add(client);
_ = HandleDisplayClient(client, "SCOREBOARD");
}
}
private async Task AcceptMatchesClients()
{
while (true)
{
var client = await _matchesServer.AcceptTcpClientAsync();
_matchesClients.Add(client);
_ = HandleDisplayClient(client, "MATCHES");
}
}
private async Task HandleDisplayClient(TcpClient client, string type)
{
using var stream = client.GetStream();
using var reader = new StreamReader(stream);
string identity = await reader.ReadLineAsync();
// Validate: DISPLAY:NAME=...,TYPE=...,MAC=...
// Keep connection open
while (client.Connected)
{
await Task.Delay(1000); // Wait for broadcast
}
// Remove on disconnect
if (type == "SCOREBOARD")
_scoreboardClients.Remove(client);
else
_matchesClients.Remove(client);
}
public void BroadcastToScoreboard(object data)
{
string json = JsonSerializer.Serialize(data) + "\n";
byte[] bytes = Encoding.UTF8.GetBytes(json);
for (int i = _scoreboardClients.Count - 1; i >= 0; i--)
{
var client = _scoreboardClients[i];
if (client?.Connected == true)
{
try
{
client.GetStream().Write(bytes, 0, bytes.Length);
}
catch
{
_scoreboardClients.RemoveAt(i); // Cleanup
}
}
}
}
public void BroadcastToMatches(object data)
{
string json = JsonSerializer.Serialize(data) + "\n";
byte[] bytes = Encoding.UTF8.GetBytes(json);
for (int i = _matchesClients.Count - 1; i >= 0; i--)
{
var client = _matchesClients[i];
if (client?.Connected == true)
{
try
{
client.GetStream().Write(bytes, 0, bytes.Length);
}
catch
{
_matchesClients.RemoveAt(i);
}
}
}
}
}
```
---
## 8. Android TV App Logic
### 📺 Scoreboard TV App
- Connects to `192.168.4.1:5001`
- Sends identity
- Listens for JSON
- Renders based on `mode`
- Supports video playback for `highlight_video`
### 📺 Upcoming Matches TV App
- Connects to `192.168.4.1:5002`
- Displays scrollable list
- Updates on new message
- Shows tournament logo
---
## 9. Display Modes & Transitions
| Action | Broadcast To | Mode |
|-------|--------------|------|
| Match selected | Scoreboard | `faceoff` |
| "Shi-jak" pressed | Scoreboard | `score` |
| Round ends | Scoreboard | `break` |
| 10 sec before next round | Scoreboard | `call_to_action` |
| Match ends | Scoreboard | `winner` |
| Match ends | Upcoming Matches | `next_matches` |
| Tournament starts | Upcoming Matches | `next_matches` |
---
## 10. Best Practices
| Practice | Why |
|--------|-----|
| Use separate ports (5001, 5002) | Avoid mode conflicts |
| Send `\n` after each message | Easy parsing |
| Validate device identity | Security |
| Reconnect logic on TV | Handle Wi-Fi drops |
| Broadcast only on change | Reduce network load |
| Use UTC time in logs | Debugging |
| Include `mode` in every message | Safe rendering |
---
🎯 **This document fully defines the communication between Score Control and Displays.**
You now have everything to build **real-time, synchronized, broadcast-quality displays**.
📬 For help: Contact project lead.
```
---
### ✅ How to Use
1. Save as `DISPLAY_COMMUNICATION.md`
2. Place in `/docs` folder
3. Commit to GitHub
---
Let me know if you want:
- A **Figma mockup** of the TV screens
- A **sample Android TV app** (Kotlin)
- A **test tool** to simulate messages
- A **Lottie animation** for the winner screen
You're now building a **fully integrated, professional tournament system**. 🏆