Files

608 lines
16 KiB
C

// ____________________________
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
// Hello world sample
//─────────────────────────────────────────────────────────────────────────────
#include "msxgl.h"
#include "network/obsonet.h"
//=============================================================================
// DEFINES
//=============================================================================
// Library's logo
#define MSX_GL "\x02\x03\x04\x05"
// Modes
#define MODE_SNIFFER 0
#define MODE_GAME 1
// Message ID
enum MESSAGE
{
MESSAGE_INVITATION = 0, // Sent at regular intervals by the server to inform of the existence of a game session
MESSAGE_JOIN_REQUEST, // Sent by the player who wishes to join a game session
MESSAGE_JOIN_VALID, // + PlayerID Sent by the server to accept a join request
MESSAGE_UPDATE, // + struct Player Sent by the player during the game session
};
// Message ID
enum STATE
{
STATE_MENU_INIT = 0,
STATE_MENU,
STATE_HOSTING_INIT,
STATE_HOSTING,
STATE_BROWSE_INIT,
STATE_BROWSE,
STATE_JOINING_INIT,
STATE_JOINING,
STATE_PLAYING_INIT,
STATE_PLAYING,
};
// Functions prototypes
void DisplaySniffer();
void UpdateSniffer();
void DisplayGame();
void UpdateGame();
// Process mode structure
struct Process
{
callback Display;
callback Update;
};
// Player structure
struct Player
{
u8 Y;
u8 X;
u8 Shape;
u8 Color;
//---------- End of Sprite buffer
u8 ID;
u8 Direction;
};
// Vector structure
struct Vector
{
i8 X;
i8 Y;
};
//=============================================================================
// READ-ONLY DATA
//=============================================================================
// Fonts data
#include "font/font_mgl_sample8.h"
// Character animation data
const c8 g_ChrAnim[] = { '|', '\\', '-', '/' };
// Process mode table
const struct Process g_ModeTab[2] =
{
{ DisplaySniffer, UpdateSniffer },
{ DisplayGame, UpdateGame },
};
// Broadcast MAC address
const u8 g_BroadcastMAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
// Vector structure
const struct Vector g_MoveTab[8] =
{
{ 0, 1 },
{ -1, 1 },
{ -1, 0 },
{ -1, -1 },
{ 0, -1 },
{ 1, -1 },
{ 1, 0 },
{ 1, 1 },
};
//=============================================================================
// MEMORY DATA
//=============================================================================
u8 g_Buffer[1514+2]; // Max Ethernet frame size + 2 bytes for size value
bool g_Pending;
u8 g_Mode;
u8 g_Server[6];
u8 g_Frame;
u8 g_State;
u8 g_PlayerNum;
u8 g_Slot;
struct Player g_Player[32];
//=============================================================================
// FUNCTIONS
//=============================================================================
//-----------------------------------------------------------------------------
//
void Erase(u8 sx, u8 sy, u16 num)
{
u16 dst = g_ScreenLayoutLow + (sy * g_PrintData.ScreenWidth) + sx;
VDP_FillVRAM(0, dst, g_ScreenLayoutHigh, num);
}
//-----------------------------------------------------------------------------
//
const c8* GetEtherTypeName(u16 id)
{
switch (id)
{
case ETHERTYPE_IPV4 : return "IPv4";
case ETHERTYPE_ARP : return "ARP";
case ETHERTYPE_WOLAN : return "WoLAN";
case ETHERTYPE_AVTP : return "AVTP";
case ETHERTYPE_IETF : return "IETF";
case ETHERTYPE_SRP : return "SRP";
case ETHERTYPE_DEC_MOP : return "DEC MOP";
case ETHERTYPE_DECNET : return "DECnet";
case ETHERTYPE_DEC_LAT : return "DEC LAT";
case ETHERTYPE_RARP : return "RARP";
case ETHERTYPE_ETHERTALK : return "Eth Talk";
case ETHERTYPE_AARP : return "AARP";
case ETHERTYPE_VLANTF : return "VLANtf";
case ETHERTYPE_SLPP : return "SLPP";
case ETHERTYPE_VLACP : return "VLACP";
case ETHERTYPE_IPX : return "IPX";
case ETHERTYPE_QNX : return "QNX Qnet";
case ETHERTYPE_IPV6 : return "IPv6";
case ETHERTYPE_EFC : return "EFC";
case ETHERTYPE_LACP : return "LACP";
case ETHERTYPE_COBRA : return "CobraNet";
case ETHERTYPE_MPLS_UNI : return "MPLS uni";
case ETHERTYPE_MPLS_MUL : return "MPLS mul";
case ETHERTYPE_PPPOE_DISC : return "PPPoE D";
case ETHERTYPE_PPPOE_SES : return "PPPoE S";
case ETHERTYPE_HOMEPLUG_MME : return "HomePlug";
case ETHERTYPE_EAP : return "EAPoLAN";
case ETHERTYPE_PROFINET : return "PROFINET";
case ETHERTYPE_SCSI : return "H-SCSI";
case ETHERTYPE_ATA : return "ATA";
case ETHERTYPE_ETHERCAT : return "EtherCAT";
case ETHERTYPE_SVLAN : return "S-Tag";
case ETHERTYPE_POWERLINK : return "Powerlnk";
case ETHERTYPE_GOOSE : return "GOOSE";
case ETHERTYPE_GSE : return "GSE";
case ETHERTYPE_SV : return "SV";
case ETHERTYPE_MIKROTIK : return "MikroTik";
case ETHERTYPE_LLDP : return "LLDP";
case ETHERTYPE_SERCOS : return "SERCOS3";
case ETHERTYPE_HOMEPLUG_PHY : return "HP PHY";
case ETHERTYPE_MRP : return "IEC62439";
case ETHERTYPE_MACSEC : return "MACsec";
case ETHERTYPE_PBB : return "PBB";
case ETHERTYPE_PTP : return "PTP";
case ETHERTYPE_NCSI : return "NC-SI";
case ETHERTYPE_PRP : return "PRP";
case ETHERTYPE_CFM : return "CFM/OAM";
case ETHERTYPE_FCOE : return "FCoE";
case ETHERTYPE_FCOE_INI : return "FCoE Ini";
case ETHERTYPE_ROCE : return "RoCE";
case ETHERTYPE_TTE : return "TTE";
case ETHERTYPE_1905 : return "1905.1";
case ETHERTYPE_HSR : return "HSR";
case ETHERTYPE_ECTP : return "ECTP";
case ETHERTYPE_RT : return "802.1CB";
};
return "Unknown";
}
//-----------------------------------------------------------------------------
//
const c8* GetSendResultName(u8 val)
{
switch (val)
{
case ONET_SYNC_SUCCESS : return "Success"; // Packet successfully sent
case ONET_SYNC_ERROR_LENGTH : return "Error length"; // Invalid packet length
case ONET_SYNC_ERROR_CARRIER : return "Error carrier"; // Transmission aborted due to carrier loss
case ONET_SYNC_ERROR_COLLISION : return "Error collision"; // Transmission aborted due to excessive collisions
};
return "Unknown";
}
//-----------------------------------------------------------------------------
//
const c8* GetSendStatusName(u8 val)
{
switch (val)
{
case ONET_SEND_NONE : return "None"; // No packets have been sent since the last execution of RTL_RESET
case ONET_SEND_PROGRESS : return "Progress"; // Transmission in progress
case ONET_SEND_SUCESSS : return "Sucess"; // The packet has been successfully sent
case ONET_SEND_ERROR_CARRIER : return "Error carrier"; // Transmission aborted due to carrier loss
case ONET_SEND_ERROR_COLLISION : return "Error collision"; // Transmission aborted due to excessive collisions
};
return "Unknown";
}
//-----------------------------------------------------------------------------
//
void Print_DrawSlot(u8 slot)
{
Print_DrawInt(Sys_SlotGetPrimary(slot));
if (Sys_SlotIsExpended(slot))
{
Print_DrawChar('-');
Print_DrawInt(Sys_SlotGetSecondary(slot));
}
}
//-----------------------------------------------------------------------------
//
void Print_DrawMAC(const u8* addr)
{
Print_DrawHex8(*addr++);
Print_DrawChar('.');
Print_DrawHex8(*addr++);
Print_DrawChar('.');
Print_DrawHex8(*addr++);
Print_DrawChar('.');
Print_DrawHex8(*addr++);
Print_DrawChar('.');
Print_DrawHex8(*addr++);
Print_DrawChar('.');
Print_DrawHex8(*addr++);
}
//-----------------------------------------------------------------------------
//
void DisplayHead()
{
Print_Clear();
Print_SetPosition(0, 0);
Print_DrawText(MSX_GL " OBSONET SAMPLE");
Print_DrawLineH(0, 1, 32);
}
//-----------------------------------------------------------------------------
//
void DisplayFoot()
{
Print_DrawLineH(0, 22, 32);
Erase(0, 23, 32);
Print_SetPosition(0, 23);
if (g_Mode == MODE_SNIFFER)
Print_DrawFormat("F1:Game R:Reset%s", (g_Pending) ? " G:Get D:Discard" : "");
else
Print_DrawFormat("F1:Sniffer");
}
//-----------------------------------------------------------------------------
//
void DisplaySniffer()
{
g_Pending = false;
VDP_DisableSpritesFrom(0);
DisplayHead();
DisplayFoot();
Print_SetPosition(0, 3);
Print_DrawText("Slot :");
g_Slot = ONET_Initialize();
if (g_Slot == 0xFF)
{
Print_DrawText("Not found!");
return;
}
Print_DrawSlot(g_Slot);
Print_DrawFormat("\nBIOS :%s", ONET_HasBIOS() ? "Yes" : "No");
Print_DrawFormat("\nVer. :%i.%i.%i", g_ONET_Version[0], g_ONET_Version[1], g_ONET_Version[2]);
Print_DrawText( "\nMAC :");
Print_DrawMAC(g_ONET_MAC);
Print_DrawFormat("\nConn. :%s", ONET_GetStatus() ? "Yes" : "No");
Print_DrawFormat("\nActive :%s", ONET_IsActivate() ? "Yes" : "No");
u8 rec = ONET_GetReceptConfig();
Print_DrawFormat("\nRecept :%2xh Sm%s BC%s MC%s All%s", rec,
(rec & ONET_RECEPT_SMALL) ? "\x0C" : "\x0B",
(rec & ONET_RECEPT_BROADCAST) ? "\x0C" : "\x0B",
(rec & ONET_RECEPT_MULTICAST) ? "\x0C" : "\x0B",
(rec & ONET_RECEPT_ALL) ? "\x0C" : "\x0B");
Print_DrawText("\nPacket :");
}
//-----------------------------------------------------------------------------
//
void UpdateSniffer()
{
struct ONET_PacketInfo info;
if (ONET_GetSlot() == 0xFF)
return;
if (!g_Pending)
{
Erase(8, 10, 32-8);
bool bInf = ONET_GetPacketInfo(&info);
Print_SetPosition(8, 10);
if (bInf)
{
Print_DrawFormat("Yes S=%i H=%4x %s", info.Size, info.Head, GetEtherTypeName(info.Head));
g_Pending = TRUE;
DisplayFoot();
}
else
{
Print_DrawText("No");
DisplayFoot();
}
}
if (g_Pending)
{
if (Keyboard_IsKeyPressed(KEY_G)) // Get Packet
{
if (ONET_GetPacket(g_Buffer))
{
Erase(0, 11, 32*11);
Print_SetPosition(0, 11);
Print_DrawCharX(0x1C, 32);
Print_DrawFormat("\nSize %i bytes", *(i16*)g_Buffer);
Print_DrawText("\nDest. "); Print_DrawMAC(g_Buffer + 2);
Print_DrawText("\nSource "); Print_DrawMAC(g_Buffer + 8);
u8* buf;
if (info.Head > 1500)
{
buf = g_Buffer + 14;
}
else
{
Print_DrawFormat("\nLength %i", *(i16*)(g_Buffer + 14));
buf = g_Buffer + 22;
}
Print_DrawFormat("\nType %2x%2x (%s)", buf[0], buf[1], GetEtherTypeName(Math_Swap(*(u16*)buf)));
buf += 2;
Print_DrawText("\nRaw ");
u16 size = MIN(info.Size, 8*6);
for (u8 i = 0; i < size; ++i)
{
if ((i > 0) && ((i % 8) == 0))
{
g_PrintData.CursorX = 8;
g_PrintData.CursorY++;
}
Print_DrawHex8(*buf++);
if ((i % 8) != 7)
g_PrintData.CursorX++;
}
g_Pending = FALSE;
DisplayFoot();
}
}
else if (Keyboard_IsKeyPressed(KEY_D)) // Discard Packet
{
ONET_GetPacket(0);
g_Pending = FALSE;
DisplayFoot();
}
}
}
//-----------------------------------------------------------------------------
//
void DisplayGame()
{
VDP_DisableSpritesFrom(0);
g_State = STATE_MENU_INIT;
DisplayHead();
DisplayFoot();
}
//-----------------------------------------------------------------------------
//
void InitPlayer()
{
struct Player* ply = &g_Player[0];
ply->ID = 0;
ply->X = Math_GetRandom8();
ply->Y = Math_GetRandom8() / 2 + 32;
ply->Direction = Math_GetRandom8() % 8;
ply->Shape = 0xB0 + ply->Direction;
ply->Color = 2 + Math_GetRandom8() % 14;
VDP_SetSpriteSM1(ply->ID, ply->X, ply->Y, ply->Shape, ply->Color);
}
//-----------------------------------------------------------------------------
//
inline void SetMAC(u8* dest, const u8* src) { Mem_Copy(src, dest, 6); }
//-----------------------------------------------------------------------------
//
void SendBroadcast(u8 msg, const u8* data, u16 size)
{
// Prepare header
struct EtherHeader* head = (struct EtherHeader*)g_Buffer;
SetMAC(head->Dest, g_BroadcastMAC);
SetMAC(head->Source, ONET_GetMACAddress());
head->Type = Math_Swap(ETHERTYPE_IPV4);
// Prepare data
g_Buffer[14] = msg;
if (size)
Mem_Copy(data, g_Buffer + 15, size);
// Send data
ONET_SendPacketAsync(g_Buffer, size + 15);
}
//-----------------------------------------------------------------------------
// Pseudo game FSM
void UpdateGame()
{
switch (g_State)
{
case STATE_MENU_INIT:
Erase(0, 2, 20*32);
Print_SetPosition(0, 3);
Print_DrawText("State: Menu");
Print_DrawText("\nMAC: ");
Print_DrawMAC(g_ONET_MAC);
Print_DrawText("\n\n1. Host");
Print_DrawText("\n2. Join");
InitPlayer();
g_State = STATE_MENU;
case STATE_MENU:
if (Keyboard_IsKeyPressed(KEY_1))
g_State = STATE_HOSTING_INIT;
if (Keyboard_IsKeyPressed(KEY_2))
g_State = STATE_BROWSE_INIT;
break;
case STATE_HOSTING_INIT:
Erase(0, 2, 20*32);
Print_SetPosition(0, 3);
Print_DrawText("State: Hosting");
Print_DrawText("\nLocal: ");
Print_DrawMAC(g_ONET_MAC);
Print_DrawText("\nServer: ");
Print_DrawMAC(g_ONET_MAC);
g_PlayerNum = 1;
g_State = STATE_HOSTING;
break;
case STATE_BROWSE_INIT:
Erase(0, 2, 20*32);
Print_SetPosition(0, 3);
Print_DrawText("State: Browsing");
Print_DrawText("\nMAC: ");
Print_DrawMAC(g_ONET_MAC);
break;
case STATE_BROWSE:
break;
case STATE_JOINING_INIT:
Erase(0, 2, 20*32);
Print_SetPosition(0, 3);
Print_DrawText("State: Joining");
break;
case STATE_JOINING:
break;
case STATE_PLAYING_INIT:
Erase(0, 2, 20*32);
Print_SetPosition(0, 3);
Print_DrawText("State: Playing");
g_State = STATE_PLAYING;
break;
case STATE_HOSTING:
if ((g_Frame % 32) == 0)
SendBroadcast(MESSAGE_INVITATION, NULL, 0);
// u8 res = ONET_GetSendStatus();
// Erase(0, 20, 32);
// Print_SetPosition(0, 20);
// Print_DrawText("Status: ");
// Print_DrawText(GetSendStatusName(res));
case STATE_PLAYING:
{
// Handle local player
struct Player* ply = &g_Player[0];
if (Keyboard_IsKeyPressed(KEY_RIGHT))
{
ply->Direction++;
ply->Direction %= 32;
ply->Shape = 0xB0 + (ply->Direction / 4);
}
else if (Keyboard_IsKeyPressed(KEY_LEFT))
{
ply->Direction--;
ply->Direction %= 32;
ply->Shape = 0xB0 + (ply->Direction / 4);
}
if (Keyboard_IsKeyPressed(KEY_UP))
{
const struct Vector* vec = &g_MoveTab[ply->Direction / 4];
ply->X += vec->X;
ply->Y += vec->Y;
}
// Handle local player send info
if ((g_Frame % 8) == 0)
SendBroadcast(MESSAGE_UPDATE, (const u8*)ply, sizeof(struct Player));
// u8 res = ONET_GetSendStatus();
// Erase(0, 20, 32);
// Print_SetPosition(0, 20);
// Print_DrawText("Status: ");
// Print_DrawText(GetSendStatusName(res));
// Update distant players
// Draw players
for (u8 i = 0; i < g_PlayerNum; ++i)
VDP_WriteVRAM((const u8*)&g_Player[i], g_SpriteAttributeLow + (i * 4), g_SpriteAttributeHigh, 3);
}
break;
}
}
//-----------------------------------------------------------------------------
// Program entry point
void main()
{
VDP_SetMode(VDP_MODE_SCREEN1);
VDP_SetColor(0);
VDP_ClearVRAM();
// Initialize font
Print_SetTextFont(g_Font_MGL_Sample8, 1);
Print_SetColor(0xF, 0x0);
// Initialize sprite
VDP_SetSpriteFlag(VDP_SPRITE_SIZE_8);
VDP_LoadSpritePattern(g_Font_MGL_Sample8 + 4, 0, sizeof(g_Font_MGL_Sample8) / 8 - 4);
g_Mode = MODE_SNIFFER;
g_ModeTab[g_Mode].Display();
g_Pending = false;
bool bPressed = FALSE;
while (!Keyboard_IsKeyPressed(KEY_ESC))
{
Halt();
Print_SetPosition(31, 0);
Print_DrawChar(g_ChrAnim[g_Frame & 0x03]);
g_ModeTab[g_Mode].Update();
if (Keyboard_IsKeyPressed(KEY_F1))
{
if ((!bPressed) && (g_Slot != 0xFF))
{
g_Mode = 1 - g_Mode;
g_ModeTab[g_Mode].Display();
bPressed = TRUE;
}
}
else
bPressed = FALSE;
if (Keyboard_IsKeyPressed(KEY_R))
g_ModeTab[g_Mode].Display();
g_Frame++;
}
}