Pretty sure char is a signed 8-bit quantity (technically it’s a UTF codepoint, but from practical numeric use I think it’s the equivalent of a C signed char data type).
This means because of the sign bit, you only have 7 bits of non-negative values, i.e, 0 to 127
I think you can get 0 to 255 (all possible byte values) by using the byte datatype, and this may be more useful controlling external devices with raw bit data.
NOTE: char and byte are aliases for the struct Char and struct Byte underlying C# datatypes, for whatever that is worth.
Well it’s hard to tell where the conversion went wrong. Plain ASCII is only defined up to 127. Anything larger than that depends on the actual encoding UTF8, which is the defacto standard now is a multi byte encoding that is completely compatible to ASCII (up to 127) and can encode the whole unicode standard. Though in C# a char is actually a 16 bit value and represents an UTF16 char. So when you send out bytes it also matters how the chars are actually converted to bytes.
Are you sure that you actually receive a value of 63? Because 63 is simply the ascii character ?. The questionmark is often used as a replacement when you try to display an unsupported char as ascii. Just reading the documentation of the Write method of the SerialPort class reveals that it’s actually performs this encoding as the default is ascii and characters over 127 are not defined.
I would highly recommend to not using a string when the data you want to transmit is not text but just data. It would make more sense to use the Write overload that takes a byte array. If you don’t know how many bytes you will need beforehand you can of course use a List to accumulate your bytes and use ToArray() when you’re done. Though just declaring an array with the right size beforehand would be better for performance.
Of course bytes also only have a range that goes up to 255. If you have larger values you need some sort of multibyte encoding and that has to be processed correctly on the arduino side. Keep in mind that there are generally two major ways how larger values are serialized into a byte stream: Little endian and Big endian. Though I don’t want to go more in detail as it mainly depends on your receiving side code ^^.