Can RLP call native framework functions?

Can I call the native function CPU_SPI_nWrite8_nRead8 from within RLP? Just like in this native function


HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_SPI::InternalWriteRead___VOID__SZARRAY_U1__I4__I4__SZARRAY_U1__I4__I4__I4( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_HARDWARE();
    TINYCLR_HEADER();
    {
        CLR_RT_HeapBlock*       pThis           = stack.This();                    FAULT_ON_NULL(pThis);
        CLR_RT_HeapBlock_Array* writeBuffer     = stack.Arg1().DereferenceArray(); FAULT_ON_NULL(writeBuffer);
        CLR_INT32               writeOffset     = stack.Arg2().NumericByRef().s4;
        CLR_INT32               writeCount      = stack.Arg3().NumericByRef().s4;
        CLR_RT_HeapBlock_Array* readBuffer      = stack.Arg4().DereferenceArray(); 
        CLR_INT32               readOffset      = stack.Arg5().NumericByRef().s4;
        CLR_INT32               readCount       = stack.Arg6().NumericByRef().s4;
        CLR_UINT32              startReadOffset = stack.Arg7().NumericByRef().s4;
        
        SPI_CONFIGURATION       config;
        TINYCLR_CHECK_HRESULT(Library_spot_hardware_native_Microsoft_SPOT_Hardware_SPI__Configuration::GetInitialConfig( pThis[ FIELD__m_config ], config ));

        config.MD_16bits = FALSE;

        CPU_SPI_Initialize();

        if(!::CPU_SPI_nWrite8_nRead8(
                                  config,
                                  writeBuffer->GetElement(writeOffset), 
                                  writeCount,
                                  readBuffer == NULL ? NULL : readBuffer ->GetElement(readOffset), 
                                  readBuffer == NULL ? 0    : readCount,
                                  startReadOffset
                                ))
        {
            TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION);
        }
    }
    TINYCLR_NOCLEANUP();
}

@ Mr. John Smith - Not easily. You don’t have anything to link against and the framework isn’t a dynamic library. The only possible way is to find the address of the function in memory and create a function pointer to it. The address is different between devices and firmware versions.

@ John - So thats NxN in terms of the number of possible device and firmware combinations; assuming I could even find the addresses which would be impractical unless I had all the source code. Since I don’t have GHI’s source code, such an endevour is effectively pointless.

@ Mr. John Smith - That is correct.

Ok, so let’s say i wanted to send data over the SPI bus from RLP, how would you begin to do that?

@ Mr. John Smith - Your only options are to write your own SPI driver using the chip’s registers or marshal the data back to the managed side.

Oh wow :frowning: yea, it gets depressed.

“if I would” == “When I did” :wink:

@ Mr John Smith, can you tell us what in your app is actually in need of a speed boost from an SPI perspective ? I do somehow find it hard to imagine something already in the firmware code with a significant speed issue that you would significantly improve …

@ Brett - I want to speed up c# loops like this


internal void Write(int startIndex, byte[] values) {
            int _valueIndex = 0;
            for (int i = startIndex; i < startIndex + (values.Length * 4); i += 4) {
                socketRegister[i] = 0xF0;
                socketRegister[i + 1] = (byte)(SocketIndex + 4);
                socketRegister[i + 3] = values[_valueIndex];
                global.wiznetWriteRead(socketRegister, i, 4, socketRegister, i + 3, 0, 3);
                _valueIndex++;
            }
        }

…by using RLP.

But since RLP cant’ call this


HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_SPI::InternalWriteRead___VOID__SZARRAY_U1__I4__I4__SZARRAY_U1__I4__I4__I4( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_HARDWARE();
    TINYCLR_HEADER();
    {
        CLR_RT_HeapBlock*       pThis           = stack.This();                    FAULT_ON_NULL(pThis);
        CLR_RT_HeapBlock_Array* writeBuffer     = stack.Arg1().DereferenceArray(); FAULT_ON_NULL(writeBuffer);
        CLR_INT32               writeOffset     = stack.Arg2().NumericByRef().s4;
        CLR_INT32               writeCount      = stack.Arg3().NumericByRef().s4;
        CLR_RT_HeapBlock_Array* readBuffer      = stack.Arg4().DereferenceArray(); 
        CLR_INT32               readOffset      = stack.Arg5().NumericByRef().s4;
        CLR_INT32               readCount       = stack.Arg6().NumericByRef().s4;
        CLR_UINT32              startReadOffset = stack.Arg7().NumericByRef().s4;
        
        SPI_CONFIGURATION       config;
        TINYCLR_CHECK_HRESULT(Library_spot_hardware_native_Microsoft_SPOT_Hardware_SPI__Configuration::GetInitialConfig( pThis[ FIELD__m_config ], config ));

        config.MD_16bits = FALSE;

        CPU_SPI_Initialize();

        if(!::CPU_SPI_nWrite8_nRead8(
                                  config,
                                  writeBuffer->GetElement(writeOffset), 
                                  writeCount,
                                  readBuffer == NULL ? NULL : readBuffer ->GetElement(readOffset), 
                                  readBuffer == NULL ? 0    : readCount,
                                  startReadOffset
                                ))
        {
            TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION);
        }
    }
    TINYCLR_NOCLEANUP();
}

Then that means I have to bit bang it. Which means the RLP c++ will be more complex. Which means it will take a long time to write and debug (months even). Not that I care anymore.

I’m sure I could save a few clock cycles with a function like this


HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_SPI::CoolNewWriteRead___VOID__SZARRAY_U1__I4__I4__SZARRAY_U1__I4__I4__I4( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_HARDWARE();
    TINYCLR_HEADER();
    {
        CLR_RT_HeapBlock*       pThis           = stack.This();                    FAULT_ON_NULL(pThis);
        CLR_RT_HeapBlock_Array* writeBuffer     = stack.Arg1().DereferenceArray(); FAULT_ON_NULL(writeBuffer);
        CLR_INT32               writeOffset     = stack.Arg2().NumericByRef().s4;
        CLR_INT32               writeCount      = stack.Arg3().NumericByRef().s4;
        CLR_RT_HeapBlock_Array* readBuffer      = stack.Arg4().DereferenceArray(); 
        CLR_INT32               readOffset      = stack.Arg5().NumericByRef().s4;
        CLR_INT32               readCount       = stack.Arg6().NumericByRef().s4;
        CLR_UINT32              startReadOffset = stack.Arg7().NumericByRef().s4;

		
		/* crazy new argument!*/
		CLR_UINT32				chipSelectEvery = stack.Arg8().NumericByRef().s4
        
        SPI_CONFIGURATION       config;
        TINYCLR_CHECK_HRESULT(Library_spot_hardware_native_Microsoft_SPOT_Hardware_SPI__Configuration::GetInitialConfig( pThis[ FIELD__m_config ], config ));

        config.MD_16bits = FALSE;

        CPU_SPI_Initialize();

		/*loop to call CPU_SPI_nWrite8_nRead8 multiple times toggling chipselect each time */
		/*because doing this loop in managed c# is slow as all hell*/

        if(!::CPU_SPI_nWrite8_nRead8(
                                  config,
                                  writeBuffer->GetElement(writeOffset), 
                                  writeCount,
                                  readBuffer == NULL ? NULL : readBuffer ->GetElement(readOffset), 
                                  readBuffer == NULL ? 0    : readCount,
                                  startReadOffset
                                ))
        {
            TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION);
        }

		/* end loop */
    }
    TINYCLR_NOCLEANUP();
}

Why do you hate parentheses? What did they ever do to you?

They stole my cake! Caaaaakkkkkeeeee