Skip to content

Commit

Permalink
UART replacement now changes baud by listening to writes to the Next …
Browse files Browse the repository at this point in the history
…UART I/O ports.

Renamed project to UARTReplacement.
  • Loading branch information
Threetwosevensixseven committed Jan 24, 2020
1 parent fc5eaac commit 4a42f26
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 123 deletions.
2 changes: 1 addition & 1 deletion CSpectPlugins.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RTC", "RTC\RTC.csproj", "{0
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "I2CTestHarness", "I2CTestHarness\I2CTestHarness.csproj", "{3708E183-3E15-4D20-8726-46C452B951C7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UARTForwarder", "UARTForwarder\UARTForwarder.csproj", "{B620589D-3613-40FB-ACFB-9C825D474D7F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UARTReplacement", "UARTReplacement\UARTReplacement.csproj", "{B620589D-3613-40FB-ACFB-9C825D474D7F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
106 changes: 0 additions & 106 deletions UARTForwarder/SerialPort.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UARTForwarder")]
[assembly: AssemblyTitle("UARTReplacement")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UARTForwarder")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyProduct("UARTReplacement")]
[assembly: AssemblyCopyright("Copyright © 2020 Robin Verhagen-Guest")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand Down
250 changes: 250 additions & 0 deletions UARTReplacement/SerialPort.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Plugins.UARTReplacement
{
public class SerialPort : IDisposable
{
private System.IO.Ports.SerialPort port;
private int clock = 27000000; // CSpect defaults to HDMI timings
private int prescaler = 234; // Next baud defaults to 115200 (more accurately 115384 with integer division)

public SerialPort(string PortName, int BaudRate)
{
try
{
port = new System.IO.Ports.SerialPort();
port.PortName = PortName;
int baud = Baud;
port.BaudRate = baud > 0 ? baud : 115200;
port.Parity = System.IO.Ports.Parity.None;
port.DataBits = 8;
port.StopBits = System.IO.Ports.StopBits.One;
port.Handshake = System.IO.Ports.Handshake.None;
LogClock(false);
LogPrescaler("");
port.Open();
}
catch (Exception /*ex*/)
{
port = null;
}
}

public void Write(byte[] buffer, int offset, int count)
{
if (port != null)
port.Write(buffer, offset, count);
}

/// <summary>
/// If there is a byte available in the UART buffer return it, otherwise a value representing no data.
/// </summary>
/// <param name="Success">Output parameter indicating whether the result was a valid byte or no data.</param>
/// <returns>A byte from the UART buffer, or a value representing no data.</returns>
public byte ReadByte(out bool Success)
{
try
{
if (port != null)
{
var b = Convert.ToByte(port.ReadByte());
Success = true;
return b;
}
}
catch
{
}
Success = false;
return 0xff;
}

/// <summary>
/// Given a raw byte read from REG_VIDEO_TIMING, and another raw byte written to PORT_UART_CONTROL,
/// updates the clock and potentially also bits 17:13 of the prescaler.
/// </summary>
/// <param name="BaudByte">Read from REG_VIDEO_TIMING, used to update the clock.</param>
/// <param name="VideoTimingByte">Written to PORT_UART_CONTROL, used to update bits 17:13 of the prescaler.</param>
/// <returns></returns>
public int SetPrescalerAndClock(byte BaudByte, byte VideoTimingByte)
{
if (port == null)
return 0;
int mode = VideoTimingByte & 7;
switch (mode)
{
case 0:
clock = 28000000;
break;
case 1:
clock = 28571429;
break;
case 2:
clock = 29464286;
break;
case 3:
clock = 30000000;
break;
case 4:
clock = 31000000;
break;
case 5:
clock = 32000000;
break;
case 6:
clock = 33000000;
break;
case 7:
clock = 27000000;
break;
default:
clock = 28000000;
break;
}
if ((BaudByte & 0x10) == 0x10)
{
// Get bits 14..17 of the new prescaler
int newBits = (BaudByte & 0x07) << 14;
// Mask out everything of the existing prescaler except bits 14..17
int oldBits = prescaler & 0x3fff;
// Combine the two sets of bits
prescaler = oldBits | newBits;
port.BaudRate = Baud;
LogClock(false);
LogPrescaler("17:14");
}
else
{
port.BaudRate = Baud;
LogClock();
}
return clock;
}

/// <summary>
/// Given a raw byte written to PORT_UART_RX, parses the high bit to decide whether it represents a change
/// to bits 6:0 or 13:7, and updates the prescaler accordingly.
/// </summary>
/// <param name="BaudByte">The raw byte written to I/O port PORT_UART_RX.</param>
/// <returns>Returns the newly recalculated baud.</returns>
public int SetPrescaler(byte BaudByte)
{
if (port == null)
return 0;
if ((BaudByte & 0x80) == 0)
{
// Get bits 0..6 of the new prescaler
int newBits = BaudByte & 0x7f;
// Mask out everything of the existing prescaler except bits 0..6
int oldBits = prescaler & 0x1ff80;
// Combine the two sets of bits
prescaler = oldBits | newBits;
port.BaudRate = Baud;
LogPrescaler("6:0");
}
else
{
// Get bits 7..13 of the new prescaler
int newBits = (BaudByte & 0x7f) << 7;
// Mask out everything of the existing prescaler except bits 7..13
int oldBits = prescaler & 0x1c07f;
// Combine the two sets of bits
prescaler = oldBits | newBits;
port.BaudRate = Baud;
LogPrescaler("13:7");
}
return Baud;
}

/// <summary>
/// Baud is always calculated dynamically from the clock and prescaler, using integer division.
/// </summary>
public int Baud
{
get
{
//
if (prescaler == 0)
return 0;
return Convert.ToInt32(Math.Truncate((Convert.ToDecimal(clock) / prescaler)));
}
}

/// <summary>
/// Convenience method to log the clock and calculated baud to the debug console, every time the video timing clock changes.
/// </summary>
/// <param name="LogBaud">
/// Optionally choose not to log the calculated baud, if you know the prescaler is about to be changed
/// and logged straight afterwareds.
/// </param>
private void LogClock(bool LogBaud = true)
{
if (port == null)
return;
Debug.WriteLine("Clock: " + clock);
if (LogBaud)
Debug.WriteLine("Baud: " + Baud);
}

/// <summary>
/// Convenience method to log the prescaler and calculated baud to the debug console, every time the prescaler changes.
/// </summary>
/// <param name="BitsChanged"></param>
private void LogPrescaler(string BitsChanged)
{
if (port == null)
return;
string bstr = Convert.ToString(prescaler, 2).PadLeft(17, '0');
Debug.WriteLine("Prescaler: " + bstr.Substring(0, 3) + " " + bstr.Substring(3, 7) + " " + bstr.Substring(10, 7)
+ " (" + prescaler + (string.IsNullOrWhiteSpace(BitsChanged) ? "" : ", changed bits " + BitsChanged) + ")");
Debug.WriteLine("Baud: " + Baud);
}

#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// Dispose managed state (managed objects).
if (port != null)
{
if (port.IsOpen)
port.Close();
port.Dispose();
port = null;
}
}

// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.

disposedValue = true;
}
}

// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~SerialPort() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }

// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
}
Loading

0 comments on commit 4a42f26

Please sign in to comment.