return race results immediately instead of waiting for race to finish

main
DustyP 9 months ago
parent dd66141a1d
commit 8edf6f7a77

@ -1 +1,50 @@
# Start with a Go base image
FROM golang:1.21-bullseye as builder
# Install dependencies for cross-compilation
RUN apt-get update && apt-get install -y \
gcc-aarch64-linux-gnu \
libc6-dev-arm64-cross \
&& rm -rf /var/lib/apt/lists/*
# Set up working directory
WORKDIR /app
# Copy go.mod and go.sum files first for better caching
COPY go.mod ./
# COPY go.sum ./ # Uncomment if you have a go.sum file
# Download dependencies
RUN go mod download
# Copy the source code
COPY . .
# Set environment variables for cross-compilation to ARM64 (Raspberry Pi 4)
ENV GOOS=linux
ENV GOARCH=arm64
ENV CC=aarch64-linux-gnu-gcc
ENV CGO_ENABLED=1
# Build the application
RUN go build -o track-gopher-arm64 ./examples/main.go
# Create a minimal runtime image
FROM arm64v8/debian:bullseye-slim
# Install required runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Set up working directory
WORKDIR /app
# Copy the binary from the builder stage
COPY --from=builder /app/track-gopher-arm64 .
# Make the binary executable
RUN chmod +x ./track-gopher-arm64
# Command to run when the container starts
ENTRYPOINT ["./track-gopher-arm64"]

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
@ -161,12 +160,16 @@ func (dc *DerbyClock) Results() []*Result {
// readLoop continuously reads from the serial port // readLoop continuously reads from the serial port
func (dc *DerbyClock) readLoop() { func (dc *DerbyClock) readLoop() {
buffer := make([]byte, 0, 256)
for { for {
select { select {
case <-dc.stopReading: case <-dc.stopReading:
return return
default: default:
line, err := dc.reader.ReadString('\n') // Read a single byte
b := make([]byte, 1)
_, err := dc.port.Read(b)
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {
// Only log if it's not EOF // Only log if it's not EOF
@ -176,19 +179,11 @@ func (dc *DerbyClock) readLoop() {
continue continue
} }
// Process the line // Add the byte to our buffer
dc.processLine(line) buffer = append(buffer, b[0])
}
}
}
// processLine handles a line of text from the derby clock
func (dc *DerbyClock) processLine(line string) {
// Trim any whitespace and carriage returns
line = strings.TrimSpace(line)
if line == "C" { // Check for race start signal "C\r\n"
// Race has started if len(buffer) >= 3 && string(buffer[len(buffer)-3:]) == "C\r\n" {
dc.mu.Lock() dc.mu.Lock()
dc.status = StatusRunning dc.status = StatusRunning
dc.results = nil dc.results = nil
@ -196,83 +191,108 @@ func (dc *DerbyClock) processLine(line string) {
// Send race start event // Send race start event
dc.eventChan <- Event{Type: EventRaceStart} dc.eventChan <- Event{Type: EventRaceStart}
return
}
// Check if this is a results line // Clear the buffer
if strings.Contains(line, "=") { buffer = buffer[:0]
results := parseResults(line) continue
}
// Check for lane result pattern (n=t.ttttc)
// We need to look for an equals sign followed by digits, a period, more digits, and a finish character
if b[0] == '=' || b[0] == ' ' || b[0] == '\r' || b[0] == '\n' {
// These characters could indicate a complete result or a separator
// Try to extract a result from the buffer
result := dc.tryExtractResult(buffer)
if result != nil {
dc.mu.Lock() dc.mu.Lock()
// Add results to our stored results // Add result to our stored results
for _, result := range results {
dc.results = append(dc.results, result) dc.results = append(dc.results, result)
// Determine finish place based on how many results we have
result.FinishPlace = len(dc.results)
dc.mu.Unlock()
// Send lane finish event // Send lane finish event
dc.eventChan <- Event{ dc.eventChan <- Event{
Type: EventLaneFinish, Type: EventLaneFinish,
Result: result, Result: result,
} }
}
// If we have results, the race is now finished // If we hit a newline, this might be the end of all results
if len(results) > 0 { if b[0] == '\n' {
// Check if we should consider the race complete
dc.mu.Lock()
if dc.status == StatusRunning {
dc.status = StatusFinished dc.status = StatusFinished
dc.mu.Unlock()
// Send race complete event // Send race complete event
dc.eventChan <- Event{Type: EventRaceComplete} dc.eventChan <- Event{Type: EventRaceComplete}
} } else {
dc.mu.Unlock() dc.mu.Unlock()
} }
// Clear the buffer after a newline
buffer = buffer[:0]
}
}
}
}
}
} }
// parseResults parses a line of results from the derby clock // tryExtractResult attempts to extract a lane result from the buffer
func parseResults(line string) []*Result { func (dc *DerbyClock) tryExtractResult(buffer []byte) *Result {
parts := strings.Split(line, " ") // Convert buffer to string for easier processing
results := make([]*Result, 0, len(parts)) bufStr := string(buffer)
for i, part := range parts { // Look for the pattern: n=t.ttttc
if !strings.Contains(part, "=") { // where n is the lane number, t.tttt is the time, and c is the finish character
continue for i := 0; i < len(bufStr); i++ {
if bufStr[i] == '=' {
// Found an equals sign, try to extract a lane number before it
j := i - 1
for j >= 0 && bufStr[j] >= '0' && bufStr[j] <= '9' {
j--
} }
j++ // Move back to the first digit
// Format is "n=0.0000c" if j < i { // We found at least one digit
laneStr := strings.Split(part, "=")[0] laneStr := bufStr[j:i]
timeAndPlace := strings.Split(part, "=")[1]
if len(timeAndPlace) < 2 { // Now look for the time and finish character after the equals sign
continue k := i + 1
for k < len(bufStr) && (bufStr[k] == '.' || (bufStr[k] >= '0' && bufStr[k] <= '9')) {
k++
} }
// Extract time and place character if k < len(bufStr) && k > i+1 { // We found a time and a finish character
timeStr := timeAndPlace[:len(timeAndPlace)-1] timeStr := bufStr[i+1 : k]
placeChar := timeAndPlace[len(timeAndPlace)-1:] finishChar := bufStr[k : k+1]
// Parse lane number // Parse the lane number
lane, err := strconv.Atoi(laneStr) lane, err := strconv.Atoi(laneStr)
if err != nil { if err != nil {
continue continue
} }
// Parse time // Parse the time
timeVal, err := strconv.ParseFloat(timeStr, 64) timeVal, err := strconv.ParseFloat(timeStr, 64)
if err != nil { if err != nil {
continue continue
} }
// Determine place // Create and return the result
place := i + 1 return &Result{
// Create result
result := &Result{
Lane: lane, Lane: lane,
Time: timeVal, Time: timeVal,
FinishPlace: place, FinishPlace: 0, // Will be set by the caller
FinishSymbol: placeChar, FinishSymbol: finishChar,
}
}
}
} }
results = append(results, result)
} }
return results return nil
} }

@ -1,6 +1,6 @@
module track-gopher module track-gopher
go 1.23.5 go 1.24.1
require go.bug.st/serial v1.6.2 require go.bug.st/serial v1.6.2

Loading…
Cancel
Save