using System; using System.IO.Ports; using System.Runtime.CompilerServices; using System.Text; using Microsoft.SPOT.Hardware; namespace HWModules { public class I2CUartBridge : I2CPortBase { // create write buffer (we need one byte) private byte[] RegisterNum = new byte[1] {0x12}; // create read buffer to read the register private byte[] RegisterValue = new byte[1] {0x00}; private byte[] str = new byte[256]; private StringBuilder strLine = new StringBuilder(128); //number of bytes in read Fifo private int nb; public int UartBaud { get { return UartBaud; } protected set { switch (value) { case 1200: _baudIndex = 0; break; case 2400: _baudIndex = 1; break; case 4800: _baudIndex = 2; break; case 9600: _baudIndex = 3; break; case 19200: _baudIndex = 4; break; case 28800: _baudIndex = 5; break; case 38400: _baudIndex = 6; break; case 57600: _baudIndex = 7; break; case 115200: _baudIndex = 8; break; default: _baudIndex = 4; //19200 break; } } } private int _baudIndex; public System.IO.Ports.Parity UartParity { get; protected set; } public int UartDataBits { get; protected set; } public System.IO.Ports.StopBits UartStopBits { get; protected set; } public I2CUartBridge(I2CDevice.Configuration config, int slotnumber = 3, int baudrate = 19200, System.IO.Ports.Parity parity = Parity.None, int dataBits = 8, System.IO.Ports.StopBits stopBits = StopBits.One ) : base(config, slotnumber) { UartBaud = baudrate; UartParity = parity; UartDataBits = dataBits; UartStopBits = stopBits; TimeOut = 50; Init(); } //************************************************************************************************************************************ private int Init() { //initialiaze an EXAR1280 I2C to UART device ONLY. sets up registers in the proper order. //TODO P2 hook up error checking and return value int ret = 0; RegisterNum[0] = LCR; RegisterValue[0] = 0xBF; //LCR=BF enables access to enhanced reg RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = FCTR; RegisterValue[0] = (byte) (RegFCTR.ScratchpadSwap); //FCTR=0x41 enables SPR as fifo counter FCTR[6]=1). FCTR[0] = no sleeping! //RegisterValue[0] = 0x41; //FCTR=0x41 enables SPR as fifo counter FCTR[6]=1). FCTR[0] = no sleeping! RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = EFR; RegisterValue[0] = (byte) RegEFR.EnhFuncEn; //EFR[4] = 1 enables shaded bits, access to DLD and flow control RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = LCR; RegisterValue[0] = (byte) RegLCR.BrDivLatch; //LCR[7] = 1 enables access to divisors. LCR[1,2] = 0 selects 8N1 RegWrite(RegisterNum, RegisterValue); SetBrgValues(); SetLcrRegister(); RegisterNum[0] = MCR; RegisterValue[0] = 0x00; //MCR RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = FCR; RegisterValue[0] = (byte) RegFCR.FifoEnable; //FCR RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = SFR; RegisterValue[0] = 0x00; //SFR RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = EMSR; RegisterValue[0] = 0x00; //EMSR[0] makes spr FIFO rx count RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = IER; RegisterValue[0] = (byte) RegIER.RHRInterrupt; //IER, only if LCR[7]=0 RegWrite(RegisterNum, RegisterValue); //clear read fifo FifoRead(str); //clear interrupt ClearIRQ(); return (ret); //TODO P2 hook this up } private void SetLcrRegister() { RegisterNum[0] = LCR; RegLCR lcrFlags = 0; switch (UartDataBits) { case 5: lcrFlags |= RegLCR.WordLen5; break; case 6: lcrFlags |= RegLCR.WordLen6; break; case 7: lcrFlags |= RegLCR.WordLen7; break; case 8: lcrFlags |= RegLCR.WordLen8; break; default: throw new ArgumentOutOfRangeException("I2CUartBridge.DataBits", "Databits must be 5-8 for EXAR"); } switch (UartStopBits) { case StopBits.OnePointFive: lcrFlags |= RegLCR.Stop1p5; break; case StopBits.Two: lcrFlags |= RegLCR.Stop2; break; case StopBits.None: throw new ArgumentException("No stop bit configurations are not supported by the EXAR specification."); case StopBits.One: lcrFlags |= RegLCR.Stop1; break; default: throw new ArgumentOutOfRangeException(); } switch (UartParity) { case Parity.None: lcrFlags |= RegLCR.ParityNone; break; case Parity.Even: lcrFlags |= RegLCR.ParityEven; break; case Parity.Odd: lcrFlags |= RegLCR.ParityOdd; break; case Parity.Mark: lcrFlags |= RegLCR.ParityForceMark; break; case Parity.Space: lcrFlags |= RegLCR.ParityForceSpace; break; default: throw new ArgumentOutOfRangeException(); } RegisterValue[0] = (byte) lcrFlags; RegWrite(RegisterNum, RegisterValue); } //end Init() private bool SetBrgValues() { RegisterNum[0] = DLD; RegisterValue[0] = DldBytes[_baudIndex]; //DLD RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = DLM; RegisterValue[0] = DlmBytes[_baudIndex]; //DLM RegWrite(RegisterNum, RegisterValue); RegisterNum[0] = DLL; RegisterValue[0] = DllBytes[_baudIndex]; //DLL RegWrite(RegisterNum, RegisterValue); //-------------------------------------------------- return true; } //************************************************************************************************************************************ //CRITICAL, ADDING A DEBUG MESSAGE HERE DERAILS THE OPERATION AND LEADS TO SYSTEM //INSTABILITY, DO NOT TOUCH!! [MethodImpl(MethodImplOptions.Synchronized)] public int FifoRead(byte[] rtstr) { //reads all characters in read fifo and returns in rtstr. //TODO P2 hook up error int bytes_read = 0; int j = 0; int nb; do { RegisterNum[0] = SPR; nb = RegRead(RegisterNum); //bounds checking if (nb < 1) nb = 0; if (nb > 128) nb = 128; //get nb bytes for (int i = 0; i < nb; i++) { RegisterNum[0] = (byte)0; if (bytes_read + 1 == rtstr.Length) { RegRead(RegisterNum); } else { rtstr[bytes_read] = (byte) RegRead(RegisterNum); bytes_read++; } } if (nb <=0) j++; } while ((nb > 0) && (j < 3)) ; return bytes_read; } //end fiforead() //************************************************************************************************************************************ public int i2cprint(byte[] sndstr, int nb, int offset = 0) { //TODO P2 hook up error condition for (int i = 0; i < nb; i++) { RegisterNum[0] = 0; RegisterValue[0] = sndstr[i+offset]; RegWrite(RegisterNum, RegisterValue); } return nb; //send something reasonable back. just using nb so //the damn compiler stops complaining. } //end i2cprint //************************************************************************************************************************************ [MethodImpl(MethodImplOptions.Synchronized)] public ushort RegRead(byte[] RegNum) { //TODO P2 hook up error condition I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[2]; RegNum[0] = (byte) ((int) RegNum[0] & 0x0F); RegNum[0] = (byte) ((int) RegNum[0] << 3); //RegNum[0] = (byte)((int)RegNum[0] | 0x01); xActions[0] = I2CDevice.CreateWriteTransaction(RegNum); xActions[1] = I2CDevice.CreateReadTransaction(RegNum); // Now we access the I2C bus using a timeout of one second // if the execute command returns zero, the transaction failed (this // is a good check to make sure that you are communicating with the device correctly // and don’t have a wiring issue or other problem with the I2C device) if (Execute(xActions, TimeOut) == 0) { //EngrLogger.Comment("RegRead: Write Fail 1: " + RegNum[0].ToString()); if (Execute(xActions, TimeOut) == 0) { //EngrLogger.Comment("RegRead: Write Fail 2: " + RegNum[0].ToString()); } } return RegNum[0]; } //end RegRead() //************************************************************************************************************************************ public ushort RegWrite(byte[] RegNum, byte[] RegVal) { //to do, hook up error condition ushort ret = 0; I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[1]; RegNum[0] = (byte) ((int) RegNum[0] & 0x0F); RegNum[0] = (byte) ((int) RegNum[0] << 3); //RegNum[0] = (byte)((int)RegNum[0] | 0x01); byte[] snd = new byte[2] {RegNum[0], RegVal[0]}; //Debug.Print("RegWrite: Writing " + snd[1].ToString() + "to reg num " // + snd[0].ToString()); xActions[0] = I2CDevice.CreateWriteTransaction(snd); if (Execute(xActions, TimeOut) == 0) { //EngrLogger.Comment("RegWrite: Write Fail 1: " + RegNum[0].ToString()); if (Execute(xActions, TimeOut) == 0) { //EngrLogger.Comment("RegWrite: Write Fail 2: " + RegNum[0].ToString()); ret = 1; } } return (ret); } //end RegWrite //************************************************************************************************************************************ public void ClearIRQ() { RegisterNum[0] = 2; RegRead(RegisterNum); } //end ClearIRQ() //************************************************************************************************************************************ public StringBuilder get_i2c_buffer() { //StringBuilder returnField; int i = 0; nb = FifoRead(str); if (nb > 0) { //returnField.Append(System.Text.Encoding.UTF8.GetChars(str, 0, nb)); for (i = 0; i < nb; i++) //non printable chars crash program { if (str[i] > 126) str[i] = 0; } strLine.Clear(); strLine.Append(System.Text.Encoding.UTF8.GetChars(str, 0, nb)); if (strLine.Length > 0) { //Debug.Print(strLine.ToString()); } } return (strLine); } //end //************************************************************************************************************************************ public void clear_i2c_buffer(int x) { //Debug.Print("clear_buffer " + x.ToString()); //Debug.Print("i2c_flag=" + i2c_flg.ToString()); //Program.I2CBridge.Config = con; nb = FifoRead(str); //I2CInstrument.ClearIRQ(I2CBridge); //i2c_flg &= ~(1 << (x - 1)); //clear the bit //Debug.Print("i2c_flag=" + i2c_flg.ToString()); //Debug.Print("Clearing B" + x.ToString() + ":" + nb.ToString()); } //end //************************************************************************************************************************************ /// /// Internal Register Addresses /// LCR != 0xBF /// const byte RHR = 0x0; const byte THR = 0x0; const byte IER = 0x1; const byte FCR = 0x2; const byte ISR = 0x2; const byte LCR = 0x3; const byte MCR = 0x4; const byte LSR = 0x5; const byte SHR = 0x5; // requires EFR bit-4 = 1 const byte MSR = 0x6; const byte SFR = 0x6; // requires EFR bit-4 = 1 const byte TCR = 0x6; const byte SPR = 0x7; // requires SFR bit-0 = 0, FCTR bit-6 = 0 const byte GPIOLVL = 0x7; // requires SFR bit-0 = 1, FCTR bit-6 = 0 const byte EMSR = 0x7; // requires SFR bit-0 = 0, FCTR bit-6 = 1 const byte FC = 0x7; // requires SFR bit-0 = 0, FCTR bit-6 = 1 const byte DREV = 0x0; //LCR[7] = 1 DLL = 0x00, DLM = 0x00 const byte DLL = 0x0; const byte DLM = 0x1; const byte DLD = 0x2; /// /// Enhanced Registers, LCR must be 0xBF /// const byte TRIG = 0x0; const byte FCTR = 0x1; const byte EFR = 0x2; const byte XON1 = 0x4; const byte XON2 = 0x5; const byte XOFF1 = 0x6; const byte XOFF2 = 0x7; const byte GPIOINT = 0x4; // requires SFR bit-0 = 1 const byte GPIO3T = 0x5; // requires SFR bit-0 = 1 const byte GPIOINV = 0x6; // requires SFR bit-0 = 1 const byte GPIOSEL = 0x7; // requires SFR bit-0 = 1 /// /// Interrupt Enable Register - R/W /// [Flags] private enum RegIER { RHRInterrupt = 0x01, //IER[0]: RHR interrupt enable THRInterrupt = 0x02, //IER[1]: THR interrupt enable RxLineInterrupt = 0x04, //IER[2]: Receive Line Status Interrupt Enable ModemStatRegInterrupt = 0x08, //IER[3]: Modem Status Interrupt Enable SleepMode = 0x10, //IER[4]: Sleep Mode enable (requires EFR[4] == 1) SoftwareFlowControl = 0x20, //IER[5]: Xoff Interrupt Enable (requires EFR[4] == 1) RtsInterrupt = 0x40, //IER[6]: RTS# Output Interrupt Enable (requires EFR[4] == 1) CtsInterrupt = 0x80 //IER[7]: CTS# Input Interrupt Enable (requires EFR[4] == 1) } /// /// Interrupt Status Register - Read Only /// [Flags] private enum RegISR { IntStatus = 0x01, //ISR[0:5]: Interrupt Source MaskIntSrc = 0x1F, IntSrcLSR = 0x06, IntSrcRxTimeout = 0x0C, IntSrcRxDataRdy = 0x04, IntSrcTxReady = 0x02, IntSrcMsr = 0x00, IntSrcXonXoff = 0x10, IntSrcCtsRts = 0x20, IntSrcNone = 0x01, //ISR[6]: GPIO interrupt status (when there is an interrupt, it will be the inverse of ISR[7] GpioIntStatus = 0x40, //ISR[7]: FIFO enable status FifoEnableStatus = 0x80 } /// /// FIFO Control Register - Write Only /// [Flags] private enum RegFCR { FifoEnable = 0x01, //FCR[0]: Tx and Rx Fifo Enable RxFifoReset = 0x02, //FCR[1]: RX Fifo Reset TxFifoReset = 0x04, //FCR[2]: Tx Fifo Reset WakeUpIntEn = 0x08, //FCR[3]: Enable Wake Up interrupt MaskTxFifoTrig = 0x30, //FCR[5:4]: Tx Fifo Trigger select mask (requires EFR[4] == 1) TxFifoLvlOpt0 = 0x00, TxFifoLvlOpt1 = 0x10, TxFifoLvlOpt2 = 0x20, TxFifoLvlOpt3 = 0x30, MaskRxFifoTrig = 0xC0, //FCR[6:7]: Rx Fifo Trigger select mask RxFifoLvlOpt0 = 0x00, RxFifoLvlOpt1 = 0x40, RxFifoLvlOpt2 = 0x80, RxFifoLvlOpt3 = 0xC0, } /// /// Line Control Register - Read/Write /// [Flags] private enum RegLCR { MaskWordLen = 0x03, WordLen5 = 0x00, WordLen6 = 0x01, WordLen7 = 0x02, WordLen8 = 0x03, //LCR[2] MaskStop = 0x01 << 2, Stop1 = 0x00 << 2, //for all word lengths Stop1p5 = 0x01 << 2, //for word length 5 Stop2 = 0x01 << 2, //for word lengths 6,7,8 //LCR[3:5]: Parity Select MaskParity = 0x07 << 3, //mask for parity ParityNone = 0x00 << 3, //no parity ParityOdd = 0x01 << 3, //odd parity ParityEven = 0x03 << 3, //even parity ParityForceMark = 0x05 << 3, //Force parity to mark, HIGH ParityForceSpace = 0x07 << 3, //Force partiy to space, LOW //LCR[6]: Transmit Break Enable TxBreakNone = 0x00 << 6, TxBreakSpace = 0x01 << 6, //LCR[7]: Baud Rate Divisors Enable BrDivData = 0x00 << 7, //data registers are selected. BrDivLatch = 0x01 << 7 //divisor latch registers selected. } /// /// Modem Control Register - Read/Write /// [Flags] private enum RegMCR { DtrOutputLow = 0x01, //MCR[0]: Force Dtr# output low. RtsOutputLow = 0x02, //MCR[1]: Force Rts# output low, required to start Auto RTS Flow Control ModemIoPins = 0x04, //MCR[2]: GPIO[3:0] behcable at RI#, CD#, DTR#, DSR# OP2OutputLow = 0x08, //MCR[3]: OP2# output set LOW LoopBackEn = 0x10, //MCR[4]: Enable local loopback mode. XonAnyEn = 0x20, //MCR[5]: Enable Xon-Any Function (requires EFR[4] == 1) IrdaEn = 0x40, //MCR[6]: Enable the IrDA rx and tx IO. (requires EFR[4] == 1) ClockDiv4 = 0x80, //MCR[7]: Clock Prescalar Divied by 4 (requires EFR[4] == 1) default div by 1 } /// /// Line Status Register - Read Only /// [Flags] private enum RegLSR { RxDataReady = 0x01, //LSR[0]: Data received and in the holding registor or FIFO OverrunError = 0x02, //LSR[1]: Overrun error ParityError = 0x04, //LSR[2]: Parity error FramingError = 0x08, //LSR[3]: Framing error BreakRx = 0x10, //LSR[4]: Receiver received a break signal TxHoldingRegEmpty = 0x20, //LSR[5]: Transmit Holding Register Empty Flag ThrTsrEmpty = 0x40, //LSR[6]: Transmitter idle RxFifoError = 0x80, //LSR[7]: Sum of all error bits in the RX FIFO } /// /// Setup/Hysteresis Register - Write Only /// [Flags] private enum RegSHR { Tad00 = 0x00, Tad04 = 0x01, Tad06 = 0x02, Tad08 = 0x03, Tad08b = 0x04, Tad16 = 0x05, Tad24 = 0x06, Tad32 = 0x07, Tad40 = 0x08, Tad44 = 0x09, Tad48 = 0x0A, Tad52 = 0x0B, Tad12 = 0x0C, Tad20 = 0x0D, Tad28 = 0x0E, Tad36 = 0x0F, RtsBitLen0 = 0x00, RtsBitLen1 = 0x10, RtsBitLen2 = 0x20, RtsBitLen3 = 0x30, RtsBitLen4 = 0x40, RtsBitLen5 = 0x50, RtsBitLen6 = 0x60, RtsBitLen7 = 0x70, RtsBitLen8 = 0x80, RtsBitLen9 = 0x90, RtsBitLen10 = 0xA0, RtsBitLen11 = 0xB0, RtsBitLen12 = 0xC0, RtsBitLen13 = 0xD0, RtsBitLen14 = 0xE0, RtsBitLen15 = 0xF0 } /// /// Modem Status Register - Read Only /// [Flags] private enum RegMSR { CtsChanged = 0x01, //MSR[0]: Delta CTS# Input Flag DsrChanged = 0x02, //MSR[1]: Delta DSR# Input Flag RiChanged = 0x04, //MSR[2]: Delt RI# Input from LOW to HIGH ending of the ringing signal CdChanged = 0x08, //MSR[3]: Delta CD# Input Flag CtsStatus = 0x10, //MSR[4]: CTS# Input Status DsrStatus = 0x20, //MSR[5]: DSR# Input Status RiStatus = 0x40, //MSR[6]: RI# Input Status CdStatus = 0x80, //MSR[7]: CD# Inputer Status } /// /// Special Function Register - Write Only /// [Flags] private enum RegSFR { //ALL FLAGS REQUIRE EFR[4] == 1 GpioEnable = 0x01, //SFR[0]: Enable GPIO Registers GpioSelectHigh = 0x02, //SFR[1]: GPIOLVL, GPIOINT, GPIO3T, GPIOINV and GPIOSEL // registers will control and report GPIO[15:8] (default GPIO[7:0]) GpioIntEnable = 0x04, //SFR[2]: GPIO interrupt enabled FastIrEnable = 0x08, //SFR[3]: IrDA version 1.1 TxDisable = 0x10, //SFR[4]: Disable the Transmitter RxDisable = 0x20, //SFR[5]: Disable the Receiver NineBitEnable = 0x40, //SFR[6]: Enable the 9-bit or Multidrop Mode TxAddrBit = 0x80, //SFR[7]: Value of the 9th bit will be '1' } /// /// Enhanced Mode Select Register - Write Only /// /// This register replaces SPR (during a write) /// and is accessible only when FCTR[6] = 1 /// [Flags] private enum RegESMR { MaskFifoLevel = 0x03, //EMSR[1:0]: Rx/Tx FIFO Level Count FifoLvlRx = 0x00, //RX fifoe level counter mode FifoLvlTx = 0x01, //TX fifo level counter mode FifoLvlAlt = 0x03, //Alternate RX/TX Fifo counter mode SendTxImmediately = 0x04, //ESMR[2]: Send TX immediately InvertRtsIn485 = 0x08, //ESMR[3]: Invert RTS in RS485 Mode ModemThreeState = 0x10, //ESMR[4]: TX, RTS# and DTR# are in three state mode LsrIntImmediate = 0x40, //ESMR[6]: LSR interrupts immediately XoffIntClrIsr = 0x80, //ESMR[7]: Xoff/Special Character interrupt can on be cleared by reading the ISR register. } /// /// Baud Rate Generator Divisor Register - Read / Write /// [Flags] private enum RegDLD { MaskValue = 0x0F, //DLD[3:0] Program value of the baud rate (fraction BR * 16) MaskSamp = 0x30, //DLD[5:4] Sample rate select Samp16x = 0x00, Samp8x = 0x10, Samp4x = 0x30, MaskBrgSelect = 0xC0, //DLD[6] Enable independent baud rate generators. //DLD[7] Cofigures tx or rx BrgTxRxSame = 0x00, BrgDiffCfgTx = 0x40, BrgDiffCfgRx = 0xC0, BrgDiffCfgNone = 0x80, } /// /// Feature Control Register (FCTR) - Read / Write /// [Flags] private enum RegFCTR { PwrdnEn = 0x01, //FCTR[0]: Sleep/Pwrdn# Function ctl. logic 1 output is enable on pwrdn# pin. Reserved = 0x02, IrDaRxInvert = 0x04, //FCTR[2]: selects rx nput as invertede encoded irda data. AutoRs485En = 0x08, //FCTR[3]: Auto RS-485 Direction contrl enabled. MaskTxRxTable = 0x30, //FCTR[5:4] Transmit receive trigger table select. TxRxTableA = 0x00, TxRxTableB = 0x10, TxRxTableC = 0x20, TxRxTableD = 0x30, ScratchpadSwap = 0x40, //FCTR[6]: ScratchpadSwap TxTrigReg = 0x80, //FCTR[7]: Programmable trigger register select (1 registers TRG and FC for Tx, 0 for Rx) } /// /// Enhanced Feature Register - Read / Write /// [Flags] private enum RegEFR { MaskSoftFlowCtl = 0x0F, //EFR[3:0]: Software flow control select NoTxRxFlowCtl = 0x00, //No Tx and Rx flow control (default and reset) //TODO P3 Do we need software flow control support??? EnhFuncEn = 0x10, //EFR[4]: Enhance Function Bits Enable SpecCharDet = 0x20, //EFR[5]: Special Character Detect Enable AutoRtsEn = 0x40, //EFR[6]: Auto Rts Flow Control Enable AutoCtsEn = 0x80, //EFR[7]: Auto Cts Flow Control Enable } private enum BaudRate { B1200 = 0, B2400, B4800, B9600, B19200, B28800, B38400, B57600, B115200 } private static readonly byte[] DlmBytes = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; private static readonly byte[] DllBytes = new byte[] { 0x5F, 0x2F, 0x17, 0x0B, 0x05, 0x03, 0x01, 0x01 }; private static readonly byte[] DldBytes = new byte[] { 0x0D, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; public int TimeOut { get; set; } } }