Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Managed LIN Master/Native Implementation
#include "LinController.h"
int Native_Begin_Impl(uint64_t baudRate, uint64_t timeout, int txPin, TinyCLR_Result &hr);
int Native_End_Impl(TinyCLR_Result& hr);
int Native_SendTo_Impl(uint8_t id, uint8_t *data, size_t length, uint8_t linVersion, TinyCLR_Result& hr);
int Native_ReceiveFrom_Impl(uint8_t id, int32_t length, uint8_t linVersion, uint8_t *outData, TinyCLR_Result& hr);
#define UART1_API_NAME "GHIElectronics.TinyCLR.NativeApis.AT91SAM9X35.UartController\5"
static int baudRate = 0;
static int txPin = 0;
static unsigned long timeout = 0;
static TinyCLR_Uart_Settings settings;
static const TinyCLR_Uart_Controller* uartController;
static const TinyCLR_Gpio_Controller* gpioController;
static const TinyCLR_NativeTime_Controller* timeController;
bool setControllers(const TinyCLR_Interop_MethodData md);
TinyCLR_Result Interop_LinController_LinController_LinMaster::Native_Begin___I4__U8__U8__I4(const TinyCLR_Interop_MethodData md) {
auto result = TinyCLR_Result::Success;
if (!setControllers(md)) {
return TinyCLR_Result::NotFound;
}
auto ip = md.InteropManager;
TinyCLR_Interop_ClrValue clrBaudRate;
ip->GetArgument(ip, md.Stack, 0, clrBaudRate);
uint64_t baudRate = clrBaudRate.Data.Numeric->U8;
TinyCLR_Interop_ClrValue clrTimeout;
ip->GetArgument(ip, md.Stack, 1, clrTimeout);
uint64_t timeout = clrTimeout.Data.Numeric->U8;
TinyCLR_Interop_ClrValue clrTxPin;
ip->GetArgument(ip, md.Stack, 2, clrTxPin);
int txPin = clrTxPin.Data.Numeric->I4;
int retVal = Native_Begin_Impl(baudRate, timeout, txPin, result);
TinyCLR_Interop_ClrValue clrRet;
ip->GetReturn(ip, md.Stack, clrRet);
clrRet.Data.Numeric->I4 = retVal;
return result;
}
TinyCLR_Result Interop_LinController_LinController_LinMaster::Native_End___I4(const TinyCLR_Interop_MethodData md) {
auto result = TinyCLR_Result::Success;
if (!setControllers(md)) {
return TinyCLR_Result::NotFound;
}
int retVal = Native_End_Impl(result);
auto ip = md.InteropManager;
TinyCLR_Interop_ClrValue clrRet;
ip->GetReturn(ip, md.Stack, clrRet);
clrRet.Data.Numeric->I4 = retVal;
return result;
}
TinyCLR_Result Interop_LinController_LinController_LinMaster::Native_SendTo___I4__U1__SZARRAY_U1__U1(const TinyCLR_Interop_MethodData md) {
auto result = TinyCLR_Result::Success;
if (!setControllers(md)) {
return TinyCLR_Result::NotFound;
}
auto ip = md.InteropManager;
TinyCLR_Interop_ClrValue clrID;
ip->GetArgument(ip, md.Stack, 0, clrID);
uint8_t id = clrID.Data.Numeric->U1;
TinyCLR_Interop_ClrValue clrData;
ip->GetArgument(ip, md.Stack, 1, clrData);
uint8_t *data = reinterpret_cast<uint8_t *>(clrData.Data.SzArray.Data);
size_t dataLength = clrData.Data.SzArray.Length;
TinyCLR_Interop_ClrValue clrLinVersion;
ip->GetArgument(ip, md.Stack, 2, clrLinVersion);
uint8_t linVersion = clrLinVersion.Data.Numeric->U1;
int retVal = Native_SendTo_Impl(id, data, dataLength, linVersion, result);
TinyCLR_Interop_ClrValue clrRet;
ip->GetReturn(ip, md.Stack, clrRet);
clrRet.Data.Numeric->I4 = retVal;
return result;
}
TinyCLR_Result Interop_LinController_LinController_LinMaster::Native_ReceiveFrom___I4__U1__I4__U1__SZARRAY_U1(const TinyCLR_Interop_MethodData md) {
auto result = TinyCLR_Result::Success;
if (!setControllers(md)) {
return TinyCLR_Result::NotFound;
}
auto ip = md.InteropManager;
TinyCLR_Interop_ClrValue clrID;
ip->GetArgument(ip, md.Stack, 0, clrID);
uint8_t id = clrID.Data.Numeric->U1;
TinyCLR_Interop_ClrValue clrLength;
ip->GetArgument(ip, md.Stack, 1, clrLength);
int32_t length = clrLength.Data.Numeric->I4;
TinyCLR_Interop_ClrValue clrLinVersion;
ip->GetArgument(ip, md.Stack, 2, clrLinVersion);
uint8_t linVersion = clrLinVersion.Data.Numeric->U1;
TinyCLR_Interop_ClrValue clrData;
ip->GetArgument(ip, md.Stack, 3, clrData);
uint8_t* data = reinterpret_cast<uint8_t*>(clrData.Data.SzArray.Data);
size_t dataLength = clrData.Data.SzArray.Length;
int retVal = Native_ReceiveFrom_Impl(id, length, linVersion, data, result);
TinyCLR_Interop_ClrValue clrRet;
ip->GetReturn(ip, md.Stack, clrRet);
clrRet.Data.Numeric->I4 = retVal;
return result;
}
bool setControllers(const TinyCLR_Interop_MethodData md) {
auto apiManager = md.ApiManager;
auto maybeUartController = reinterpret_cast<const TinyCLR_Uart_Controller*>(apiManager->Find(apiManager, UART1_API_NAME, TinyCLR_Api_Type::UartController));
if (maybeUartController == nullptr) {
return false;
}
auto maybeGpioController = reinterpret_cast<const TinyCLR_Gpio_Controller*>(apiManager->FindDefault(apiManager, TinyCLR_Api_Type::GpioController));
if (maybeGpioController == nullptr) {
return false;
}
auto maybeNativeTimeController = reinterpret_cast<const TinyCLR_NativeTime_Controller*>(apiManager->FindDefault(apiManager, TinyCLR_Api_Type::NativeTimeController));
if (maybeNativeTimeController == nullptr) {
return false;
}
uartController = maybeUartController;
gpioController = maybeGpioController;
timeController = maybeNativeTimeController;
}
const uint8_t LIN_BREAK_DURATION = 15; // Number of bits in the break.
const uint8_t LIN_TIMEOUT_IN_FRAMES = 2; // Wait this many max frame times before declaring a read timeout.
const uint8_t SYNC_BYTE = 0x55; // Sync byte (as per LIN standard)
const uint8_t ADDRESS_PARITY_BYTE_MASK = 0x3F; // Parity byte mask (0b00111111)
const uint8_t LIN_RECEIVE_SUCCESS = 0xFF; // Successfully received target number of bytes
const uint8_t LIN_WAIT_INTERVAL = 100; // Wait this many microseconds waiting for replies
const int MAXIMUM_DELAY_MICROSECONDS = 16383; // Timeout after this many microseconds
const int MICROSECONDS_PER_MILLISECOND = 1000; // Constant
void delayMicroseconds(uint64_t microseconds);
void delayMilliseconds(uint64_t milliseconds);
void generateSerialBreak();
int bitShift(int data, int shift);
uint8_t dataChecksum(const uint8_t* message, uint8_t numberOfBytes, uint16_t sum = 0);
uint8_t addressParity(uint8_t targetAddress);
unsigned long getAdjustedTimeout(unsigned long baudRate);
uint8_t calculateProtectedID(uint8_t targetAddress);
int Native_Begin_Impl(uint64_t inBaudRate, uint64_t inTimeout, int inTxPin, TinyCLR_Result& hr) {
baudRate = inBaudRate;
txPin = inTxPin;
timeout = inTimeout;
settings.BaudRate = baudRate;
settings.DataBits = 8;
settings.StopBits = TinyCLR_Uart_StopBitCount::One;
settings.Parity = TinyCLR_Uart_Parity::None;
settings.Handshaking = TinyCLR_Uart_Handshake::None;
uartController->Acquire(uartController);
uartController->Enable(uartController);
uartController->ClearReadBuffer(uartController);
uartController->ClearWriteBuffer(uartController);
uartController->SetActiveSettings(uartController, &settings);
return 0;
}
int Native_End_Impl(TinyCLR_Result& hr) {
uartController->Release(uartController);
return 0;
}
int Native_SendTo_Impl(uint8_t id, uint8_t* data, size_t length, uint8_t linVersion, TinyCLR_Result& hr) {
//uartController->Acquire(uartController);
uartController->Flush(uartController);
uartController->ClearReadBuffer(uartController);
uartController->ClearWriteBuffer(uartController);
size_t syncByteWriteLength = 1;
size_t idByteWriteLength = 1;
size_t dataWriteLength = length;
size_t checksumWriteLength = 1;
uint8_t idByte = calculateProtectedID(id);
uint8_t checksum = dataChecksum(data, length, (linVersion == 1) ? 0 : idByte);
generateSerialBreak(); // Generate the low signal that exceeds 1 char.
uartController->Write(uartController, &SYNC_BYTE, syncByteWriteLength); // Sync byte (as per the LIN standard)
uartController->Write(uartController, &idByte, idByteWriteLength); // ID byte (protected ID calculated from the address)
uartController->Write(uartController, data, dataWriteLength); // Write the data bytes in the message
uartController->Write(uartController, &checksum, checksumWriteLength); // Checksum over the data bytes, and part of the protected ID in the case of version 2.X
return length;
}
int Native_ReceiveFrom_Impl(uint8_t id, int32_t numberOfBytes, uint8_t linVersion, uint8_t* outData, TinyCLR_Result& hr) {
uint8_t bytesReceived = 0;
uint32_t timeoutCount = 0;
uint8_t idByte = calculateProtectedID(id);
uint64_t adjustedTimeout = getAdjustedTimeout(baudRate);
size_t syncByteWriteLength = 1;
size_t idByteWriteLength = 1;
generateSerialBreak(); // Generate the low signal that exceeds 1 char.
uartController->Flush(uartController); // Flush out any existing characters in the buffer
uartController->ClearReadBuffer(uartController); // Flush out any existing characters in the buffer
uartController->ClearWriteBuffer(uartController); // Flush out any existing characters in the buffer
uartController->Write(uartController, &SYNC_BYTE, syncByteWriteLength); // Sync byte, specified by LIN standard
uartController->Write(uartController, &idByte, idByteWriteLength); // ID byte (protected ID calculated from the address)
//setTxPinMode(INPUT); // Change the mode of the transmit pin to INPUT so we can write it low
//setTxPinState(LOW); // Write it low to keep the bus dominant (we have control of it)
uint8_t readByte = '\0';
size_t readLength = sizeof(readByte);
do {
readByte = '\0';
while (!uartController->GetBytesToRead(uartController)) {
delayMicroseconds(LIN_WAIT_INTERVAL);
timeoutCount += LIN_WAIT_INTERVAL;
if (timeoutCount >= adjustedTimeout) {
goto cleanup;
}
}
uartController->Read(uartController, &readByte, readLength);
} while (readByte != SYNC_BYTE);
do {
readByte = '\0';
while (!uartController->GetBytesToRead(uartController)) {
delayMicroseconds(LIN_WAIT_INTERVAL);
timeoutCount += LIN_WAIT_INTERVAL;
if (timeoutCount >= adjustedTimeout) {
goto cleanup;
}
}
uartController->Read(uartController, &readByte, readLength);
} while (readByte != idByte);
for (uint8_t i = 0; i < numberOfBytes; i++) {
// This while loop strategy does not take into account the added time for the logic.
// So the actual m_timeout will be slightly longer then written here.
readByte = '\0';
while (!uartController->GetBytesToRead(uartController)) {
delayMicroseconds(LIN_WAIT_INTERVAL);
timeoutCount += LIN_WAIT_INTERVAL;
if (timeoutCount >= adjustedTimeout) {
goto cleanup;
}
}
uartController->Read(uartController, &readByte, readLength);
outData[i] = readByte;
bytesReceived++;
}
while (!uartController->GetBytesToRead(uartController)) {
delayMicroseconds(LIN_WAIT_INTERVAL);
timeoutCount += LIN_WAIT_INTERVAL;
if (timeoutCount >= adjustedTimeout) {
goto cleanup;
}
}
if (uartController->GetBytesToRead(uartController)) {
uartController->Read(uartController, &readByte, readLength);
uint8_t receivedChecksum = readByte;
bytesReceived++;
if (linVersion == 1) {
idByte = 0;
}
if (dataChecksum(outData, numberOfBytes, idByte) == receivedChecksum) {
bytesReceived = LIN_RECEIVE_SUCCESS;
}
}
cleanup:
return bytesReceived;
}
void generateSerialBreak() {
uartController->Disable(uartController);
gpioController->Acquire(gpioController);
gpioController->OpenPin(gpioController, txPin);
gpioController->SetDriveMode(gpioController, txPin, TinyCLR_Gpio_PinDriveMode::Output);
gpioController->Write(gpioController, txPin, TinyCLR_Gpio_PinValue::Low);
unsigned long int endOfBreak = (1000000UL / baudRate);
unsigned long int beginningOfBreak = (endOfBreak * LIN_BREAK_DURATION);
if (beginningOfBreak > MAXIMUM_DELAY_MICROSECONDS) {
delayMilliseconds(beginningOfBreak / MICROSECONDS_PER_MILLISECOND); // delayMicroseconds unreliable above MAXIMUM_DELAY_MICROSECONDS see arduino man pages
}
else {
delayMicroseconds(beginningOfBreak);
}
gpioController->Write(gpioController, txPin, TinyCLR_Gpio_PinValue::High); // BREAK delimiter
if (endOfBreak > MAXIMUM_DELAY_MICROSECONDS) {
delayMilliseconds(endOfBreak / MICROSECONDS_PER_MILLISECOND); // delayMicroseconds unreliable above MAXIMUM_DELAY_MICROSECONDS see arduino man pages
}
else {
delayMicroseconds(endOfBreak);
}
gpioController->ClosePin(gpioController, txPin);
uartController->Enable(uartController);
uartController->SetActiveSettings(uartController, &settings);
uartController->Flush(uartController);
}
void delayMicroseconds(uint64_t microseconds) {
timeController->Wait(timeController, microseconds);
}
void delayMilliseconds(uint64_t milliseconds) {
delayMicroseconds(milliseconds * MICROSECONDS_PER_MILLISECOND);
}
//#define BIT(data,shift) ((data&(1<<shift))>>shift) // Check target bit, and move it into the digits (0b00100000 -> 0b00000001)
int bitShift(int data, int shift) {
return ((data & (1 << shift)) >> shift); // Check target bit, and move it into the digits (0b00100000 -> 0b00000001)
}
// For LIN 1.X "start" should = 0, for LIN 2.X "start" should be the addr byte.
uint8_t dataChecksum(const uint8_t* message, uint8_t numberOfBytes, uint16_t sum) {
uint16_t returnSum = sum;
while (numberOfBytes-- > 0) {
returnSum += *(message++);
}
// Add the carry
while (returnSum >> 8) { // In case adding the carry causes another carry
returnSum = (returnSum & 255) + (returnSum >> 8);
}
return (~returnSum);
}
//Calculate the address parity from a target address
uint8_t addressParity(uint8_t targetAddress) {
(void)targetAddress;
uint8_t p0 = static_cast<uint8_t>(bitShift(targetAddress, 0) ^ bitShift(targetAddress, 1) ^ bitShift(targetAddress, 2) ^ bitShift(targetAddress, 4));
uint8_t p1 = static_cast<uint8_t>(~(bitShift(targetAddress, 1) ^ bitShift(targetAddress, 3) ^ bitShift(targetAddress, 4) ^ bitShift(targetAddress, 5)));
return (p0 | (p1 << 1)) << 6;
}
unsigned long getAdjustedTimeout(unsigned long baudRate) {
unsigned long Tbit = (100000UL / baudRate ); // Not quite in uSec, I'm saving an extra 10 to change a 1.4 (40%) to 14 below...
unsigned long nominalFrameTime = ((34 * Tbit) + 90 * Tbit); // 90 = 10*max # payload bytes + checksum (9).
//return (LIN_TIMEOUT_IN_FRAMES * 140 * nominalFrameTime); // 14 is the specced addtl 40% space above normal*10 -- the extra 10 is just pulled out of the 1000000 needed to convert to uSec (so that there are no decimal #s).
return (LIN_TIMEOUT_IN_FRAMES * 14 * nominalFrameTime); // 14 is the specced addtl 40% space above normal*10 -- the extra 10 is just pulled out of the 1000000 needed to convert to uSec (so that there are no decimal #s).
}
uint8_t calculateProtectedID(uint8_t targetAddress) {
return static_cast<uint8_t>((targetAddress & ADDRESS_PARITY_BYTE_MASK) | addressParity(targetAddress));
}
#include "LinController.h"
static const TinyCLR_Interop_MethodHandler methods[] = {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
Interop_LinController_LinController_LinMaster::Native_Begin___I4__U8__U8__I4,
Interop_LinController_LinController_LinMaster::Native_End___I4,
Interop_LinController_LinController_LinMaster::Native_SendTo___I4__U1__SZARRAY_U1__U1,
Interop_LinController_LinController_LinMaster::Native_ReceiveFrom___I4__U1__I4__U1__SZARRAY_U1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
};
const TinyCLR_Interop_Assembly Interop_LinController = {
"LinController",
0xAC2D7A11,
methods
};
using System;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.Devices.Uart;
using System.Runtime.CompilerServices;
using GHIElectronics.TinyCLR.Native;
using System.Runtime.InteropServices;
using LinController.Properties;
namespace LinController {
public enum LinVersion : byte {
RevisionOne = 0x1,
RevisionTwo = 0x2
};
public class LinMaster {
#region Constants
const byte LIN_BREAK_DURATION = 15; // Number of bits in the break.
const byte LIN_TIMEOUT_IN_FRAMES = 2; // Wait this many max frame times before declaring a read timeout.
const byte SYNC_BYTE = 0x55; // Sync byte (as per LIN standard)
const byte ADDRESS_PARITY_BYTE_MASK = 0x3F; // Parity byte mask (0b00111111)
const byte LIN_RECEIVE_SUCCESS = 0xFF; // Successfully received target number of bytes
const byte LIN_WAIT_INTERVAL = 100; // Wait this many microseconds waiting for replies
const int MAXIMUM_DELAY_MICROSECONDS = 16383; // Timeout after this many microseconds
const int MICROSECONDS_PER_MILLISECOND = 1000; // Constant
const int NATIVE_RLI_START_ADDRESS = 0x26701000;
const int NATIVE_RLI_LIN_CONTROLLER_INTEROP_ADDRESS = 0x26701a90;
#endregion
#region Members
private readonly UartController m_uartController;
private ulong m_baudRate;
private ulong m_timeout;
#endregion
#region Properties
public ulong BaudRate {
get => this.m_baudRate;
set {
if (value == this.m_baudRate) {
return;
} else {
this.End();
this.m_baudRate = value;
this.Begin();
}
}
}
public ulong Timeout {
get => this.m_timeout;
set { }
}
#endregion
#region Constructors
public LinMaster(UartController uartController, ulong baudRate) {
/*Native method initialzation*/
var interop = Resources.GetBytes(Resources.BinaryResources.LinController);
Marshal.Copy(interop, 0, new IntPtr(NATIVE_RLI_START_ADDRESS), interop.Length);
Interop.Add(new IntPtr(NATIVE_RLI_LIN_CONTROLLER_INTEROP_ADDRESS)); //LinController
interop = null;
GC.Collect();
/*Native method initialization*/
this.m_baudRate = baudRate;
this.m_uartController = uartController;
}
#endregion
#region Helper Functions
private static int GetTxPinFromSerial(UartController serial) {
var usart0Ref = ((GHIElectronics.TinyCLR.Devices.Uart.Provider.UartControllerApiWrapper)UartController.FromName(G400D.UartPort.Usart0).Provider).Api.Name;
var usart1Ref = ((GHIElectronics.TinyCLR.Devices.Uart.Provider.UartControllerApiWrapper)UartController.FromName(G400D.UartPort.Usart1).Provider).Api.Name;
var usart2Ref = ((GHIElectronics.TinyCLR.Devices.Uart.Provider.UartControllerApiWrapper)UartController.FromName(G400D.UartPort.Usart2).Provider).Api.Name;
var uart0Ref = ((GHIElectronics.TinyCLR.Devices.Uart.Provider.UartControllerApiWrapper)UartController.FromName(G400D.UartPort.Uart0).Provider).Api.Name;
var uart1Ref = ((GHIElectronics.TinyCLR.Devices.Uart.Provider.UartControllerApiWrapper)UartController.FromName(G400D.UartPort.Uart1).Provider).Api.Name;
var serialName = ((GHIElectronics.TinyCLR.Devices.Uart.Provider.UartControllerApiWrapper)serial.Provider).Api.Name;
if (serialName == usart0Ref) {
return G400D.GpioPin.PA0; //COM2
} else if (serialName == usart1Ref) {
return G400D.GpioPin.PA5; //COM3
} else if (serialName == usart2Ref) {
return G400D.GpioPin.PA7; //COM4
} else if (serialName == uart0Ref) {
return G400D.GpioPin.PC8; //COM5
} else if (serialName == uart1Ref) {
return G400D.GpioPin.PC16; //COM6
} else {
throw new Exception("Invalid UART controller");
}
}
private static ulong GetAdjustedTimeout(ulong baudRate) {
var Tbit = 100000UL / baudRate; // Not quite in uSec, I'm saving an extra 10 to change a 1.4 (40%) to 14 below...
var nominalFrameTime = ((34 * Tbit) + 90 * Tbit); // 90 = 10*max # payload bytes + checksum (9).
//return (LIN_TIMEOUT_IN_FRAMES * 140 * nominalFrameTime); // 14 is the specced addtl 40% space above normal*10 -- the extra 10 is just pulled out of the 1000000 needed to convert to uSec (so that there are no decimal #s).
return (LIN_TIMEOUT_IN_FRAMES * 14 * nominalFrameTime); // 14 is the specced addtl 40% space above normal*10 -- the extra 10 is just pulled out of the 1000000 needed to convert to uSec (so that there are no decimal #s).
}
public static bool IsValidLinBaudRate(ulong baudRate) {
return ((baudRate == 9600) || (baudRate == 115200));
}
#endregion
#region Public Methods
public int Begin(ulong baudRate) {
if (!LinMaster.IsValidLinBaudRate(baudRate)) {
throw new Exception("Invalid baud rate: " + baudRate.ToString());
}
if (this.m_baudRate != baudRate) {
this.m_baudRate = baudRate;
}
this.m_timeout = LinMaster.GetAdjustedTimeout(this.m_baudRate);
var result = this.Native_Begin(this.m_baudRate, this.m_timeout, LinMaster.GetTxPinFromSerial(this.m_uartController));
return result;
}
public int Begin() {
return this.Begin(this.m_baudRate);
}
public void End() {
this.Native_End();
}
public bool IsFaulted() {
return false;
}
//Write out a Lin message on the bus, to the target address
public void SendTo(LinMessage linMessage, LinVersion linVersion) {
this.SendTo(linMessage.Address, linMessage.Data, linVersion);
}
private void SendTo(byte targetAddress, byte[] message, LinVersion linVersion) {
var result = this.Native_SendTo(targetAddress, message, (byte)linVersion);
if (result != 0) {
throw new Exception("SendTo failed: error code " + result.ToString());
}
}
//Write out a SYNC byte and protected ID and read a slave response.
//Returns 0xFF if good checksum, # bytes received (including checksum) if checksum is bad.
LinMessage ReceiveFrom(byte targetAddress, byte numberOfBytes, byte version, out byte status) {
var tempBuffer = new byte[LinMessage.LIN_MESSAGE_MAX_SIZE];
var receivedSize = this.Native_ReceiveFrom(targetAddress, numberOfBytes, version, tempBuffer);
var linMessage = new LinMessage(targetAddress, numberOfBytes);
if (receivedSize == LIN_RECEIVE_SUCCESS) {
status = LIN_RECEIVE_SUCCESS;
linMessage.SetData(tempBuffer, numberOfBytes);
} else {
status = (byte)receivedSize;
linMessage.Length = (receivedSize - 1);
linMessage.SetData(tempBuffer, receivedSize - 1);
}
return linMessage;
}
LinMessage ReceiveFrom(byte targetAddress, byte numberOfBytes, LinVersion linVersion, out byte status) {
return this.ReceiveFrom(targetAddress, numberOfBytes, (byte)linVersion, out status);
}
#endregion
#region Native Methods
[MethodImpl(MethodImplOptions.InternalCall)]
private extern int Native_Begin(ulong baudRate, ulong timeout, int txPin);
[MethodImpl(MethodImplOptions.InternalCall)]
private extern int Native_End();
[MethodImpl(MethodImplOptions.InternalCall)]
private extern int Native_SendTo(byte id, byte[] data, byte linVersion);
[MethodImpl(MethodImplOptions.InternalCall)]
private extern int Native_ReceiveFrom(byte id, int length, byte linVersion, byte[] outData);
#endregion
}
}
#pragma once
#include <TinyCLR.h>
struct Interop_LinController_LinController_LinMaster {
static const size_t FIELD___m_uartController___GHIElectronicsTinyCLRDevicesUartGHIElectronicsTinyCLRDevicesUartUartController = 1;
static const size_t FIELD___m_baudRate___U8 = 2;
static const size_t FIELD___m_timeout___U8 = 3;
static TinyCLR_Result Native_Begin___I4__U8__U8__I4(const TinyCLR_Interop_MethodData md);
static TinyCLR_Result Native_End___I4(const TinyCLR_Interop_MethodData md);
static TinyCLR_Result Native_SendTo___I4__U1__SZARRAY_U1__U1(const TinyCLR_Interop_MethodData md);
static TinyCLR_Result Native_ReceiveFrom___I4__U1__I4__U1__SZARRAY_U1(const TinyCLR_Interop_MethodData md);
};
struct Interop_LinController_LinController_LinMessage {
static const size_t FIELD___m_data___SZARRAY_U1 = 1;
static const size_t FIELD___m_address___U1 = 2;
static const size_t FIELD___m_length___I4 = 3;
};
extern const TinyCLR_Interop_Assembly Interop_LinController;
using System;
using System.Collections;
using System.Text;
using System.Threading;
namespace LinController {
public class LinMessage {
#region Constants
public const int LIN_MESSAGE_MAX_SIZE = 8;
#endregion
#region Members
private byte[] m_data;
private byte m_address;
private int m_length;
#endregion
#region Properties
public byte[] Data {
get => this.m_data;
set {
if (value.Length > LIN_MESSAGE_MAX_SIZE) {
throw new Exception("Message length cannot be greater than " + LIN_MESSAGE_MAX_SIZE.ToString());
}
this.m_data = (byte[])value.Clone();
this.m_length = this.m_data.Length;
}
}
public byte Address {
get => this.m_address;
set => this.m_address = value;
}
public int Length {
get => this.m_length;
set {
if (value > LIN_MESSAGE_MAX_SIZE) {
throw new Exception("Message length cannot be greater than " + LIN_MESSAGE_MAX_SIZE.ToString());
}
if (this.m_data.Length == value) {
return;
}
var tempBuffer = (byte[])this.m_data.Clone();
this.m_data = new byte[value];
for (var i = 0; i < value; i++) {
this.m_data[i] = tempBuffer[i];
}
}
}
public void SetData(byte[] data, int length) {
this.Length = length;
for (var i = 0; i < length; i++) {
this.m_data[i] = data[i];
}
}
#endregion
public LinMessage(byte address, byte[] data) {
this.m_address = address;
this.Data = data;
}
public LinMessage(byte address, byte[] data, int length) {
this.m_address = address;
this.m_data = new byte[LIN_MESSAGE_MAX_SIZE];
this.Length = length;
for (var i = 0; i < length; i++) {
this.m_data[i] = data[i];
}
}
public LinMessage(byte address, byte length) {
this.m_address = address;
if (length > LIN_MESSAGE_MAX_SIZE) {
throw new Exception("Message length cannot be greater than " + LIN_MESSAGE_MAX_SIZE.ToString());
}
this.m_data = new byte[length];
this.m_length = length;
}
}
}
OUTPUT_NAME = LinController
LINKERSCRIPT_NAME = scatterfile
MCU_FLAGS = -mcpu=arm9 -mthumb
INC_DIRS = -I.
CC = arm-none-eabi-g++.exe
LD = arm-none-eabi-g++.exe
OC = arm-none-eabi-objcopy.exe
CC_FLAGS = $(INC_DIRS) $(MCU_FLAGS) -Os -std=c++11 -xc++ -Wall -Wabi -w -mabi=aapcs -fPIC -fno-exceptions -fno-rtti -fno-use-cxa-atexit -fno-threadsafe-statics
LD_FLAGS = $(MCU_FLAGS) -nostartfiles -lc -lgcc -T $(LINKERSCRIPT_NAME) -Wl,-Map,$(OUTPUT_NAME).map -Wl,--oformat -Wl,elf32-littlearm
OC_FLAGS = -S -O binary
SRC_FILES = $(wildcard *.cpp)
OBJ_FILES = $(patsubst %.cpp, %.obj, $(SRC_FILES))
rebuild: clean build
clean:
del $(OBJ_FILES) $(OUTPUT_NAME).bin $(OUTPUT_NAME).elf $(OUTPUT_NAME).map
build: $(OBJ_FILES)
$(LD) $(LD_FLAGS) -o $(OUTPUT_NAME).elf $^
$(OC) $(OC_FLAGS) $(OUTPUT_NAME).elf $(OUTPUT_NAME).bin
%.obj: %.cpp
$(CC) -c $(CC_FLAGS) -o $@ $^
MEMORY {
SDRAM (wx) : ORIGIN = 0x26700000, LENGTH = 0x16FFFF8
}
SECTIONS {
. = ALIGN(4);
.text : {
*(.text)
}
.rodata ALIGN(4): {
*(.rodata)
}
.data ALIGN(4): {
*(.data)
}
.bss ALIGN(4): {
*(.bss)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.