-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
176 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package tmdl | ||
|
||
import "errors" | ||
|
||
// VirtualChannelMultiplexer handles frame scheduling from multiple Virtual Channels. | ||
type VirtualChannelMultiplexer struct { | ||
VChannels map[uint8]*VirtualChannel // Map of VCID to VirtualChannel | ||
Priority map[uint8]int // Scheduling weight per VC | ||
lastUsed uint8 // Tracks last scheduled VC | ||
} | ||
|
||
// NewMultiplexer initializes a Virtual Channel multiplexer. | ||
func NewMultiplexer() *VirtualChannelMultiplexer { | ||
return &VirtualChannelMultiplexer{ | ||
VChannels: make(map[uint8]*VirtualChannel), | ||
Priority: make(map[uint8]int), | ||
lastUsed: 0, | ||
} | ||
} | ||
|
||
// AddVirtualChannel registers a Virtual Channel with a priority weight. | ||
func (mux *VirtualChannelMultiplexer) AddVirtualChannel(vc *VirtualChannel, priority int) { | ||
mux.VChannels[vc.VCID] = vc | ||
mux.Priority[vc.VCID] = priority | ||
} | ||
|
||
// GetNextFrame selects the next frame for transmission based on priority. | ||
func (mux *VirtualChannelMultiplexer) GetNextFrame() (*TMTransferFrame, error) { | ||
if len(mux.VChannels) == 0 { | ||
return nil, errors.New("no virtual channels available") | ||
} | ||
|
||
// Collect all VCIDs in a slice for round-robin selection | ||
vcids := make([]uint8, 0, len(mux.VChannels)) | ||
for vcid := range mux.VChannels { | ||
vcids = append(vcids, vcid) | ||
} | ||
|
||
// Find the next eligible VC with available frames | ||
for i := 0; i < len(vcids); i++ { | ||
mux.lastUsed = (mux.lastUsed + 1) % uint8(len(vcids)) // Round-robin selection | ||
vcid := vcids[mux.lastUsed] | ||
vc := mux.VChannels[vcid] | ||
|
||
// Check if VC has frames | ||
if vc.HasFrames() { | ||
return vc.GetNextFrame() | ||
} | ||
} | ||
return nil, errors.New("no frames available in any virtual channel") | ||
} | ||
|
||
// HasPendingFrames checks if any Virtual Channel has pending frames. | ||
func (mux *VirtualChannelMultiplexer) HasPendingFrames() bool { | ||
for _, vc := range mux.VChannels { | ||
if vc.HasFrames() { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package tmdl_test | ||
|
||
import ( | ||
"github.com/ravisuhag/astro/pkg/tmdl" | ||
"testing" | ||
) | ||
|
||
func TestNewMultiplexer(t *testing.T) { | ||
mux := tmdl.NewMultiplexer() | ||
|
||
if len(mux.VChannels) != 0 { | ||
t.Errorf("Expected VChannels length 0, got %v", len(mux.VChannels)) | ||
} | ||
|
||
if len(mux.Priority) != 0 { | ||
t.Errorf("Expected Priority length 0, got %v", len(mux.Priority)) | ||
} | ||
} | ||
|
||
func TestMultiplexerAddVirtualChannel(t *testing.T) { | ||
mux := tmdl.NewMultiplexer() | ||
vcid := uint8(0x01) | ||
bufferSize := 10 | ||
priority := 1 | ||
|
||
vc := tmdl.NewVirtualChannel(vcid, bufferSize) | ||
mux.AddVirtualChannel(vc, priority) | ||
|
||
if len(mux.VChannels) != 1 { | ||
t.Errorf("Expected VChannels length 1, got %v", len(mux.VChannels)) | ||
} | ||
|
||
if mux.VChannels[vcid] != vc { | ||
t.Errorf("Expected VirtualChannel %v, got %v", vc, mux.VChannels[vcid]) | ||
} | ||
|
||
if mux.Priority[vcid] != priority { | ||
t.Errorf("Expected Priority %v, got %v", priority, mux.Priority[vcid]) | ||
} | ||
} | ||
|
||
func TestMultiplexerGetNextFrame(t *testing.T) { | ||
mux := tmdl.NewMultiplexer() | ||
vcid1 := uint8(0x01) | ||
vcid2 := uint8(0x02) | ||
bufferSize := 10 | ||
priority := 1 | ||
|
||
vc1 := tmdl.NewVirtualChannel(vcid1, bufferSize) | ||
vc2 := tmdl.NewVirtualChannel(vcid2, bufferSize) | ||
mux.AddVirtualChannel(vc1, priority) | ||
mux.AddVirtualChannel(vc2, priority) | ||
|
||
frame1 := &tmdl.TMTransferFrame{} | ||
frame2 := &tmdl.TMTransferFrame{} | ||
err := vc1.AddFrame(frame1) | ||
if err != nil { | ||
t.Fatalf("Expected no error, got %v", err) | ||
} | ||
err = vc2.AddFrame(frame2) | ||
if err != nil { | ||
t.Fatalf("Expected no error, got %v", err) | ||
} | ||
|
||
retrievedFrame, err := mux.GetNextFrame() | ||
|
||
if err != nil { | ||
t.Fatalf("Expected no error, got %v", err) | ||
} | ||
|
||
if retrievedFrame != frame1 && retrievedFrame != frame2 { | ||
t.Errorf("Expected frame1 or frame2, got %v", retrievedFrame) | ||
} | ||
|
||
retrievedFrame, err = mux.GetNextFrame() | ||
if err != nil { | ||
t.Fatalf("Expected no error, got %v", err) | ||
} | ||
|
||
if retrievedFrame != frame1 && retrievedFrame != frame2 { | ||
t.Errorf("Expected frame1 or frame2, got %v", retrievedFrame) | ||
} | ||
|
||
_, err = mux.GetNextFrame() | ||
if err == nil { | ||
t.Fatalf("Expected error, got nil") | ||
} | ||
} | ||
|
||
func TestMultiplexerHasPendingFrames(t *testing.T) { | ||
mux := tmdl.NewMultiplexer() | ||
vcid := uint8(0x01) | ||
bufferSize := 10 | ||
priority := 1 | ||
|
||
vc := tmdl.NewVirtualChannel(vcid, bufferSize) | ||
mux.AddVirtualChannel(vc, priority) | ||
|
||
if mux.HasPendingFrames() { | ||
t.Errorf("Expected HasPendingFrames to be false, got true") | ||
} | ||
|
||
frame := &tmdl.TMTransferFrame{} | ||
vc.AddFrame(frame) | ||
|
||
if !mux.HasPendingFrames() { | ||
t.Errorf("Expected HasPendingFrames to be true, got false") | ||
} | ||
|
||
mux.GetNextFrame() | ||
Check failure on line 110 in pkg/tmdl/mux_test.go
|
||
|
||
if mux.HasPendingFrames() { | ||
t.Errorf("Expected HasPendingFrames to be false, got true") | ||
} | ||
} |