一个选项可能是使用聚合来实现您正在寻找的东西。
例如,您可以创建一个名为 SevenSegmentDisplay 的类,它公开方法/属性以与 7 段 LED 模块交互并包装一个私有 SPI 实例。在内部,这些方法调用私有 SPI 实例以实际与物理设备通信。
对于模拟器,这是我为具有 SPI 接口的闪存芯片编写的代码 + 配置。这用于在等待物理设备时进行内部测试。
using System;
using Microsoft.SPOT.Emulator;
using Microsoft.SPOT.Emulator.Spi;
using System.Diagnostics;
namespace dotnetwarrior.Emulator.Hardware
{
class MX25l3206FlashMemory : SpiDevice
{
private byte[] _memory;
public int MemorySize { get; set; }
public int SectorSize { get; set; }
public int PageSize { get; set; }
private Status _status;
[Flags]
enum Status
{
Wip = 1,
Wel = 2,
Bp0 = 4,
Bp1 = 8,
Bp2 = 16,
E_Err = 32,
P_Err = 64,
SRWD = 128
}
public MX25l3206FlashMemory()
{
}
public byte GetByte(int address)
{
return _memory[address];
}
public override void SetupComponent()
{
base.SetupComponent();
_memory = new byte[MemorySize];
}
protected override byte[] Write(byte[] data)
{
switch (data[0])
{
case 0x03: return Read(data);
case 0x9f: return ReadIdentification(data);
case 0x90: return ReadManufacturer(data);
case 0x06: return WriteEnable(data);
case 0x04: return WriteDisable(data);
case 0x20: return Erase4K(data);
case 0x40: return Erase8K(data);
case 0xd8: return EraseSector(data);
case 0x60:
case 0xC7: return EraseDevice(data);
case 0x02: return PagePrograme(data);
case 0x05: return ReadStatus(data);
case 0x01: return WriteStatus(data);
case 0x35: return ReadConfig(data);
}
throw new NotImplementedException("Unexpected Flash command : " + data[0].ToString());
}
private int GetAddress(byte[] data)
{
byte[] address = new byte[4];
Buffer.BlockCopy(data, 1, address, 1, 3);
Array.Reverse(address);
return (BitConverter.ToInt32(address, 0) % MemorySize);
}
private byte[] Read(byte[] data)
{
int address = GetAddress(data);
Buffer.BlockCopy(_memory, address, data, 4, data.Length - 4);
return data;
}
private byte[] ReadIdentification(byte[] data)
{
return new byte[]{0x01, 0x02, 0x15, 0x4d};
}
private byte[] ReadManufacturer(byte[] data)
{
return new byte[]{0x01, 0x02};
}
private byte[] WriteEnable(byte[] data)
{
_status |= Status.Wel;
return new byte[]{};
}
private byte[] WriteDisable(byte[] data)
{
_status &= ~Status.Wel;
return new byte[]{};
}
private byte[] ReadStatus(byte[] data)
{
return new byte[] { (byte)_status, (byte)_status };
}
private byte[] WriteStatus(byte[] data)
{
_status = (Status)data[1];
return new byte[] { };
}
private byte[] Erase4K(byte[] data)
{
if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
try
{
_status |= Status.Wip;
}
finally
{
_status &= ~(Status.Wel | Status.Wip);
}
return new byte[] { };
}
private byte[] Erase8K(byte[] data)
{
if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
_status |= Status.Wip;
try
{
}
finally
{
_status &= ~(Status.Wel | Status.Wip);
}
return new byte[] { };
}
private byte[] EraseSector(byte[] data)
{
if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
_status |= Status.Wip;
try
{
int address = GetAddress(data);
int sector = address / SectorSize;
int sectorStartAddress = sector * SectorSize;
for (int i = 0; i < SectorSize; i++)
{
_memory[sectorStartAddress + i] = 0xff;
}
}
finally
{
_status &= ~(Status.Wel | Status.Wip);
}
return new byte[] { };
}
private byte[] EraseDevice(byte[] data)
{
if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
_status |= Status.Wip;
try
{
for (int i = 0; i < MemorySize; i++)
{
_memory[i] = 0xff;
}
}
finally
{
_status &= ~(Status.Wel | Status.Wip);
}
return new byte[] { };
}
private byte[] PagePrograme(byte[] data)
{
if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
_status |= Status.Wip;
try
{
int address = GetAddress(data);
int offset = address % PageSize;
for (int i = 0; i < data.Length - 4; i++)
{
_memory[address + ((offset + i) % PageSize)] &= (byte)data[i + 4];
}
}
finally
{
_status &= ~(Status.Wel | Status.Wip);
}
return new byte[] { };
}
private byte[] ReadConfig(byte[] data)
{
return new byte[] { };
}
}
}
将闪存配置到模拟器中的相应配置如下(注意这是在自定义模拟器中使用的)。
<Types>
<MX25l3206>dotnetwarrior.Emulator.Hardware.MX25l3206FlashMemory, dotnetwarrior.Emulator</MX25l3206>
<AccessIndicator>dotnetwarrior.Emulator.Hardware.AccessIndicator, dotnetwarrior.Emulator</AccessIndicator>
</Types>
<EmulatorComponents>
<MX25l3206 id="myFlash">
<MemorySize>4194304</MemorySize>
<SectorSize>65536</SectorSize>
<PageSize>256</PageSize>
<ChipSelectPin>10</ChipSelectPin>
<!--SPI-->
<ChipSelectActiveState>false</ChipSelectActiveState>
<ChipSelectSetupTime>1</ChipSelectSetupTime>
<ChipSelectHoldTime>1</ChipSelectHoldTime>
<ClockRateKHz>36000</ClockRateKHz>
<ClockIdleState>false</ClockIdleState>
<ClockEdge>false</ClockEdge>
<SpiModule>Spi1</SpiModule>
<!--Hardware Provider-->
<Mask>1</Mask>
<Mosi>2</Mosi>
<Miso>3</Miso>
</MX25l3206>