Skip to content

Basic example (C#)

This program is a simple example of how the RedBox protocol can be used to fetch a parameter from a scale located on the local network, within a .NET console application.

Prerequisites

Project configuration

  • The Google.Protobuf and Grpc.Tools NuGet packages should be installed.
  • The RedBox protocol protobuf file must be included in the project root (or subfolders).
Example.csproj
...[Other project configuration]

<ItemGroup>
<PackageReference Include="Grpc.Tools" Version="2.67.0">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Google.Protobuf" Version="3.28.3" />
</ItemGroup>

<ItemGroup>
    <Protobuf Include="redbox.proto" GrpcServices="Client" />
</ItemGroup>
  • For use with C#, make sure the protobuf definition includes the csharp_namespace option.
smartbox.proto
syntax = "proto3";

option csharp_namespace = "Proto";

message Request
...

This will ensure C# types are generated in the configured namespace whenever changes are made to the protobuf definition.

Alternatively, you could use the protoc compiler to generate the C# types from the protobuf definition, in which case only the Google.Protobuf NuGet package is required for serialization/deserialization.

Program

The generated protobuf types are used to create a request send it to the scale, after which the response is parsed and printed to the console.

Optional assertions are used to validate the received data.

Program.cs
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using Google.Protobuf;
using Proto;

const string IP_ADDRESS = "192.168.0.102";
const int PORT = 49112;
const byte PREAMBLE = 0x3a;

using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(IPAddress.Parse(IP_ADDRESS), PORT));

var request = new Request() // Protobuf generated type
{
    MessageId = 69,
    Type = Request.Types.Type.GetParameter,
    GetParameter = new ParameterReference()
    {
        PageId = (uint)PageID.Wifi,
        ParameterId = (uint)Wifi_Parameter.MacAddr
    }
};
byte[] payload = request.ToByteArray(); // Protobuf byte serialization
byte[] lenBytes = [(byte)payload.Length, (byte)(payload.Length >> 8)];
byte[] packet = [PREAMBLE, .. lenBytes, .. payload];

socket.Send(packet); // Send [0x3A, (len & 0xFF), (len >> 8), ...payload(len bytes)]

byte[] recvBuffer = new byte[3];
var count = socket.Receive(recvBuffer, 3, SocketFlags.None); // Receive [0x3A, (len1), (len2)]
Debug.Assert(count == 3);
Debug.Assert(recvBuffer[0] == PREAMBLE);
int len = recvBuffer[1] | (recvBuffer[2] << 8);

recvBuffer = new byte[len];
count = socket.Receive(recvBuffer, len, SocketFlags.None); // Receive [...payload(len bytes)]
Debug.Assert(count == len);

var response = Response.Parser.ParseFrom(recvBuffer); // Protobuf deserialization

Console.WriteLine($"Got response: {response.PayloadCase} with message id: {response.MessageId}");
Debug.Assert(response.MessageId == 69);
Debug.Assert(response.PayloadCase == Response.PayloadOneofCase.Parameter);
Debug.Assert(response.Parameter.PageId == PageID.Wifi);
Debug.Assert(response.Parameter.ParameterId == (uint)Wifi_Parameter.MacAddr);
Debug.Assert(response.Parameter.Value.ValueCase == ParameterValue.ValueOneofCase.String);
Console.WriteLine($"Got Mac Address {response.Parameter.Value.String}\n");
Console.ReadKey();