SignalGenerator.Write failed

A strange behavior when the buffer is filled with CopyTo and this is output with SignalGenerator.Write.
The board hangs and only a complete reset with Erase All and so on helps.
When debugging it can be seen that the buffer is filled the same as if I do it with the alternative of transferring every single element …

TimeSpan[] buffer = new TimeSpan[ tapeDataByte.Count ];

/// FAILED with SignalGenerator.Write
/// 
tapeDataByte.CopyTo( buffer );

/// SUCCEEDED with SignalGenerator.Write
///
ushort idx = 0;
foreach( TimeSpan timeSpan in tapeDataByte )
	buffer[ idx++ ] = timeSpan;

tapeWritePin = GpioController.GetDefault().OpenPin( FEZDuino.GpioPin.PD0 );

tapeWriteSignal = new SignalGenerator( tapeWritePin )
{
	DisableInterrupts = false,
	IdleValue = GpioPinValue.Low
};

tapeWriteSignal.Write( buffer );

what type of “tapeDataByte” please?

ArrayList with TimeSpan objects …

double[] time = { 1 / higherTone, 1 / lowerTone };

ushort[] loSig = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
ushort[] hiSig = { 0, 0, 0, 0, 1, 1, 1, 1 };

ArrayList loBit = new();
ArrayList hiBit = new();

foreach( ushort sig in loSig )
{
	loBit.Add( TimeSpan.FromSeconds( time[ sig ] ) );
	loBit.Add( TimeSpan.FromSeconds( time[ sig ] ) );
}

foreach( ushort sig in hiSig )
{
	hiBit.Add( TimeSpan.FromSeconds( time[ sig ] ) );
	hiBit.Add( TimeSpan.FromSeconds( time[ sig ] ) );
}

ArrayList tapeDataByte = new();

tapeDataByte.AddRange( loBit );		// Start bit

byte dataByte = 0xAA;				// Test byte

for( byte i = 0; i < 8; i++ )
{
	byte flag = ( byte )( ( dataByte & ( byte )Math.Pow( 2, i ) ) >> i );

	tapeDataByte.AddRange( ( flag == 1 ) ? hiBit : loBit );
}

tapeDataByte.AddRange( hiBit );		// Stop bit

This is a hobby project to build for a 40 years old Z80 experiment system, which stored the programs on cassette recorder and loaded from it, now so a kind of MemoryTape without changing the system, but the code should not just be sounds, but interpreted to edit them on the PC with a macro assembler.
So, a byte looks and for this your signal generator and SignalCapture are excellent suitable …

I am not sure this does what you are expecting.

I am not sure exactly what I am saying, but I believe it the issue has to do with references versus objects.

Sorry, but I don’t understand you, what you mean with references. :point_down:
ICollection.CopyTo(Array, Int32) Method (System.Collections) | Microsoft Docs
The copied objects, not their pointers, are in a perfect copied state.
This also in a normal console project.
Only with the application of the method Write of SignalGenerator it bangs …

I investigated your assumption by re-creating the TimeSpan instances before transferring them individually, i.e. simulating a CopyTo:

foreach( TimeSpan timeSpan in tapeDataByte )
	bufferSucceeded[ idx++ ] = new TimeSpan( timeSpan.Ticks );

instead of the previous code :point_down:

foreach( TimeSpan timeSpan in tapeDataByte )
	bufferSucceeded[ idx++ ] = timeSpan;

Both variants work with identically good result …

Unfortunately, the effort to transfer objects from an ArrayList is necessary because the method for SignalGenerator.Write only accepts a native array of TimeSpan structures.
It would be better if there is still an overload for the Write method that also accept objects that implement ICollection …

A mystery.
Both Collections absolutely identical, from all contents, all properties, with identical values … :man_shrugging:

Can you please provide a simple project that we can reproduce?

If datatype are same, values are same then I don’t see why signal generate different value.
We need full example and value with it. Example 1/2 may not happened but 1/3 may.

My playground: Implicate-X/MemoryTape (github.com)
Above I showed how the pulse sequence looks like with:

SignalGenerator.Write( bufferSucceeded );

And this is what it looks like when

SignalGenerator.Write( bufferFailed );

is called, and then the controller remains frozen … :point_down:

Instead of CopyTo, I tried the following statement, which again creates a properly filled array, but doesn’t work in the same way.

TimeSpan[] bufferFailed2 = tapeDataByte.ToArray( typeof( TimeSpan ) ) as TimeSpan[];

So, after that again RESET + LDR, Erase all and so on …

Those buffers are different, use for loop for now!

No need Erase all. there is APP button on FEZ Duino, hold that button, hit reset, release APP button then you can deploy again.

Strange, because above the values 2500 and 5000 are to be seen, only the deep copy probably does not work.
I had tested the three variants in a simple console project under .NET 6 and all work identically.
Is it then probably a deeper problem of TinyCLR?
Well, I have a workaround with the single copying of the array elements … :wink:

We added: ArrayList.Copyto does not work on some DataType fully. · Issue #1163 · ghi-electronics/TinyCLR-Libraries (github.com)

You found a simple workaround, so we are not going to fix this issue for now :)).