TinyCLR Native Interop Confusion

Good morning,

I generated some native stubs for a class, and the auto generated .cpp file had generated code for retrieving the parameters and calling a different class in a different .cpp file. Is this a new feature? Some of the generated code was wrong and the order of the parameters passed to the second .cpp file static methods were wrong, but I fixed the glaring issues and have a different problem.

The second generated .h file includes autogenerated methods for getting managed field, and they look something like:
#pragma once
namespace ManagedNamespaceName
{
struct ManagedClassName
{
// Helper Functions to access fields of managed object
static int32_t& Get_mManagedField( CLR_RT_HeapBlock* pMngObj ) { return Interop_Marshal_GetField_int32_t( pMngObj, Interop_ACAN2517FD_ACAN2517FD_CanController::FIELD___mCSPin ); }
}
}

However, I don’t know where the definition of CLR_RT_HeapBlock* is and the autogenerated interop functions pass a TinyCLR_Interop_ClrObject* instead of a CLR_RT_HeapBlock). I can’t find any documentation on this new native stub format and I am confused moving forward. Can anyone help shed some light here?

You’ll want to make sure to check the generate bare stubs box. The stuff you’re seeing is an unfinished version that makes working with parameters easier.

John,

Thanks for your quick reply! That makes a lot more sense.

Regards,
-Tyler

John,

I’ve implemented my native code and compiled it, and it’s segfaulting almost immediately. Can someone take a quick look over the following and see if there’s anything immediately out of the ordinary? Thanks!
CanControler.map

Memory Configuration

Name             Origin             Length             Attributes
SDRAM            0x26700000         0x016ffff8         xw
*default*        0x00000000         0xffffffff

Linker script and memory map

LOAD c:/program files (x86)/microsoft visual studio/2019/community/linux/gcc_arm/bin/../lib/gcc/arm-none-eabi/8.2.1/thumb/nofp\libgcc.a
LOAD ACAN2517FD_ACAN2517FD_CanController.obj
LOAD ACAN2517FD.obj
LOAD c:/program files (x86)/microsoft visual studio/2019/community/linux/gcc_arm/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/lib/thumb/nofp\libstdc++.a
LOAD c:/program files (x86)/microsoft visual studio/2019/community/linux/gcc_arm/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/lib/thumb/nofp\libm.a
LOAD c:/program files (x86)/microsoft visual studio/2019/community/linux/gcc_arm/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/lib/thumb/nofp\libc.a
START GROUP
LOAD c:/program files (x86)/microsoft visual studio/2019/community/linux/gcc_arm/bin/../lib/gcc/arm-none-eabi/8.2.1/thumb/nofp\libgcc.a
LOAD c:/program files (x86)/microsoft visual studio/2019/community/linux/gcc_arm/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/lib/thumb/nofp\libc.a
END GROUP
                0x00000000                . = ALIGN (0x4)

.text           0x26700000      0xc84
 *(.text)
 .text          0x26700000      0xc84 ACAN2517FD_ACAN2517FD_CanController.obj
                0x26700000                Native_SetCSPin_Impl(long, TinyCLR_Result&)
                0x2670000c                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_SetCSPin___VOID__I4(TinyCLR_Interop_MethodData)
                0x2670005c                writeCSPin(TinyCLR_Gpio_Controller const*, bool)
                0x267000c8                assertCS(TinyCLR_Gpio_Controller const*)
                0x267000ec                Native_AssertCS_Impl(TinyCLR_Gpio_Controller const*, TinyCLR_Result&)
                0x267000f8                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_AssertCS___VOID(TinyCLR_Interop_MethodData)
                0x26700128                deassertCS(TinyCLR_Gpio_Controller const*)
                0x2670014c                Native_ReadCommandSPI_Impl(unsigned short, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x267001ba                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_ReadCommandSPI___VOID__U2(TinyCLR_Interop_MethodData)
                0x26700234                Native_WriteCommandSPI_Impl(unsigned short, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x2670029a                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_WriteCommandSPI___VOID__U2(TinyCLR_Interop_MethodData)
                0x26700314                Native_ReadWordSPI_Impl(TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x267003e2                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_ReadWordSPI___U4(TinyCLR_Interop_MethodData)
                0x26700450                Native_WriteWordSPI_Impl(unsigned long, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x26700510                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_WriteWordSPI___VOID__U4(TinyCLR_Interop_MethodData)
                0x26700588                Native_WriteRegisterSPI_Impl(unsigned short, unsigned long, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&)
                0x267005c6                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_WriteRegisterSPI___VOID__U2__U4(TinyCLR_Interop_MethodData)
                0x26700658                Native_ReadRegisterSPI_Impl(unsigned short, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&)
                0x26700698                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_ReadRegisterSPI___U4__U2(TinyCLR_Interop_MethodData)
                0x2670071c                Native_RawReadSPI8_Impl(TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x2670076a                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_RawReadSPI8___U1(TinyCLR_Interop_MethodData)
                0x267007d8                Native_ReadByteRegisterSPI_Impl(unsigned short, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&)
                0x26700818                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_ReadByteRegisterSPI___U1__U2(TinyCLR_Interop_MethodData)
                0x2670089c                Native_RawReadSPI16_Impl(TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x26700928                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_RawReadSPI16___U2(TinyCLR_Interop_MethodData)
                0x26700994                Native_RawWriteSPI8_Impl(unsigned char, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x267009f8                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_RawWriteSPI8___VOID__U1(TinyCLR_Interop_MethodData)
                0x26700a70                Native_WriteByteRegisterSPI_Impl(unsigned short, unsigned char, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&)
                0x26700aae                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_WriteByteRegisterSPI___VOID__U2__U1(TinyCLR_Interop_MethodData)
                0x26700b3c                Native_RawWriteSPI16_Impl(unsigned short, TinyCLR_Gpio_Controller const*, TinyCLR_Spi_Controller const*, TinyCLR_Result&, bool)
                0x26700bc2                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_RawWriteSPI16___VOID__U2(TinyCLR_Interop_MethodData)
                0x26700c3c                Native_DeassertCS_Impl(TinyCLR_Gpio_Controller const*, TinyCLR_Result&)
                0x26700c48                Interop_ACAN2517FD_ACAN2517FD_CanController::Native_DeassertCS___VOID(TinyCLR_Interop_MethodData)
 .text          0x26700c84        0x0 ACAN2517FD.obj

.glue_7         0x26700c84        0x0
 .glue_7        0x26700c84        0x0 linker stubs

.glue_7t        0x26700c84        0x0
 .glue_7t       0x26700c84        0x0 linker stubs

.vfp11_veneer   0x26700c84        0x0
 .vfp11_veneer  0x26700c84        0x0 linker stubs

.v4_bx          0x26700c84        0x0
 .v4_bx         0x26700c84        0x0 linker stubs

.iplt           0x26700c84        0x0
 .iplt          0x26700c84        0x0 ACAN2517FD_ACAN2517FD_CanController.obj

.rodata
 *(.rodata)

.rodata.str1.1  0x26700c84       0x49
 .rodata.str1.1
                0x26700c84       0x3e ACAN2517FD_ACAN2517FD_CanController.obj
 .rodata.str1.1
                0x26700cc2        0xb ACAN2517FD.obj

.rel.dyn        0x00000000        0x0
 .rel.iplt      0x00000000        0x0 ACAN2517FD_ACAN2517FD_CanController.obj

.data           0x26700cd0        0x0
 *(.data)
 .data          0x26700cd0        0x0 ACAN2517FD_ACAN2517FD_CanController.obj
 .data          0x26700cd0        0x0 ACAN2517FD.obj

.igot.plt       0x26700cd0        0x0
 .igot.plt      0x26700cd0        0x0 ACAN2517FD_ACAN2517FD_CanController.obj

.data.rel.ro    0x26700cd0      0x1cc
 .data.rel.ro   0x26700cd0      0x1cc ACAN2517FD.obj

.data.rel.ro.local
                0x26700e9c        0xc
 .data.rel.ro.local
                0x26700e9c        0xc ACAN2517FD.obj
                0x26700e9c                Interop_ACAN2517FD

.bss            0x26700ea8        0x9
 *(.bss)
 .bss           0x26700ea8        0x9 ACAN2517FD_ACAN2517FD_CanController.obj
 .bss           0x26700eb1        0x0 ACAN2517FD.obj
OUTPUT(CanController.elf elf32-littlearm)

.comment        0x00000000       0x75
 .comment       0x00000000       0x75 ACAN2517FD_ACAN2517FD_CanController.obj
                                 0x76 (size before relaxing)
 .comment       0x00000075       0x76 ACAN2517FD.obj

.ARM.attributes
                0x00000000       0x2a
 .ARM.attributes
                0x00000000       0x2a ACAN2517FD_ACAN2517FD_CanController.obj
 .ARM.attributes
                0x0000002a       0x2c ACAN2517FD.obj

Initialization code:

    var interop = Resources.GetBytes(Resources.BinaryResources.CanController);
    Marshal.Copy(interop, 0, new IntPtr(0x26700000), interop.Length);
    Interop.Add(new IntPtr(0x26700e9c));
    interop = null;
    GC.Collect();

Managed function that crashes:

[MethodImpl(MethodImplOptions.InternalCall)]
private extern void Native_WriteByteRegisterSPI(UInt16 address, byte value);

Native code for functions:

TinyCLR_Result Interop_ACAN2517FD_ACAN2517FD_CanController::Native_WriteByteRegisterSPI___VOID__U2__U1(const TinyCLR_Interop_MethodData md) {
    auto result = TinyCLR_Result::Success;

    auto apiManager = md.ApiManager;
    auto spiController = reinterpret_cast<const TinyCLR_Spi_Controller*>(apiManager->Find(apiManager, SPI1_API_NAME, TinyCLR_Api_Type::SpiController));
    if (spiController == nullptr) {
        return TinyCLR_Result::NotFound;
    }
    auto gpioController = reinterpret_cast<const TinyCLR_Gpio_Controller*>(apiManager->FindDefault(apiManager, TinyCLR_Api_Type::GpioController));
    if (gpioController == nullptr) {
        return TinyCLR_Result::NotFound;
    }
    TinyCLR_Interop_ClrValue clrParam0;
    md.InteropManager->GetArgument(md.InteropManager, md.Stack, 0, clrParam0);
    uint16_t param0 = clrParam0.Data.Numeric->U2;

    TinyCLR_Interop_ClrValue clrParam1;
    md.InteropManager->GetArgument(md.InteropManager, md.Stack, 1, clrParam1);
    uint8_t param1 = clrParam1.Data.Numeric->U1;

    Native_WriteByteRegisterSPI_Impl(param0, param1, gpioController, spiController, result);
    return result;
}

void Native_WriteByteRegisterSPI_Impl(uint16_t inRegisterAddress, uint8_t inValue, const TinyCLR_Gpio_Controller* gpioController, const TinyCLR_Spi_Controller* spiController, TinyCLR_Result& hr) {
 	assertCS(gpioController);
	Native_WriteCommandSPI_Impl(inRegisterAddress, gpioController, spiController, hr, false); // Command
	Native_RawWriteSPI8_Impl(inValue, gpioController, spiController, hr, false); // Data
	deassertCS(gpioController);
}


//Internal helper methods implementation
void assertCS(const TinyCLR_Gpio_Controller* gpioController) {
	if (csPin == NOT_A_PIN) {
		return;
	}
	writeCSPin(gpioController, false);
}

void deassertCS(const TinyCLR_Gpio_Controller* gpioController) {
	if (csPin == NOT_A_PIN) {
		return;
	}
	writeCSPin(gpioController, true);
}


void writeCSPin(const TinyCLR_Gpio_Controller* gpioController, bool state) {
	gpioController->Acquire(gpioController);
	if (csPin != lastCSPin) {
		lastCSPin = csPin;
        csPinInitialized = false;
	}
	if (!csPinInitialized) {
		gpioController->OpenPin(gpioController, csPin);
		gpioController->SetDriveMode(gpioController, csPin, TinyCLR_Gpio_PinDriveMode::Output);
		csPinInitialized = true;
	}

	gpioController->Write(gpioController, csPin, (state ? TinyCLR_Gpio_PinValue::High : TinyCLR_Gpio_PinValue::Low));
	//gpioController->ClosePin(gpioController, pinNumber);
	gpioController->Release(gpioController);
}
int32_t Native_WriteCommandSPI_Impl(uint16_t inRegisterAddress, const TinyCLR_Gpio_Controller* gpioController, const TinyCLR_Spi_Controller* spiController, TinyCLR_Result& hr, bool deassertAfter) {
    const uint16_t readCommand = (inRegisterAddress & 0x0FFF) | (0b0010 << 12);

    const auto writeLength = sizeof(readCommand);
    uint8_t writeBuffer[writeLength]{};
    uint8_t readBuffer[writeLength]{};
    
    memcpy(writeBuffer, reinterpret_cast<const uint8_t *>(&readCommand), writeLength);
    memcpy(readBuffer, reinterpret_cast<const uint8_t *>(&readCommand), writeLength);

    size_t writeLengthRef = writeLength;
    size_t readLengthRef = writeLength;
	spiController->Acquire(spiController);
    assertCS(gpioController);
    spiController->WriteRead(spiController, writeBuffer, writeLengthRef, readBuffer, readLengthRef, false);
    if (deassertAfter) {
        deassertCS(gpioController);
    }
    spiController->Release(spiController);
}
void Native_RawWriteSPI8_Impl(uint8_t inValue, const TinyCLR_Gpio_Controller* gpioController, const TinyCLR_Spi_Controller* spiController, TinyCLR_Result& hr, bool deassertAfter) {
    uint8_t writeByte = inValue;
    uint8_t readByte = 0;
    size_t writeLengthRef = sizeof(writeByte);
    size_t readLengthRef = sizeof(writeByte);
    
    spiController->Acquire(spiController);
    assertCS(gpioController);

    spiController->WriteRead(spiController, &writeByte, writeLengthRef, &readByte, readLengthRef, false);
    if (deassertAfter) {
        deassertCS(gpioController);
    }
    spiController->Release(spiController);
}