Project: SPI_MSTransfer

Mike, it's a very clean and efficient remove:

Code:
template<typename T, uint16_t _size, uint16_t multi>
bool Circular_Buffer<T,_size,multi>::remove(uint16_t pos) {
  if ( multi ) {
    if ( pos >= _size ) return 0;

    uint16_t find_area = 0;

    for ( uint16_t i = 0; i < _size; i++ ) {
      if ( ((head+i)&(_size-1)) == pos ) {
        find_area = i;
        break;
      }
    }

    while ( ((head+find_area)&(_size-1)) != ((head)&(_size-1)) ) {
      memmove(_cabuf[_cbuf[((head+find_area)&(_size-1))]]+2,_cabuf[_cbuf[((head+find_area-1)&(_size-1))]]+2,((int)((int)_cabuf[(int)_cbuf[(head+find_area-1)&(_size-1)]][0] << 8*sizeof(T)) | (int)_cabuf[(int)_cbuf[(head+find_area-1)&(_size-1)]][1])+1);
      find_area--;
    }

    head = ((head + 1)&(2*_size-1));
    _available--;
    return 1;
  }
  return 0;
}

it memmoves the data 1 bank over until the original head is reached, then the head is incremented, available decreases, and exits :)
 
I would need a prototype idea for a find to make one, I can actually have the function return you a pointer to the dataset, and possibly modify it "live", just like iterating edits

T *find(etc.... ) // library method


then...


uint16_t* test = ca.find(........etc);


then:

test[5] = 0x55;
:eek:

BTW, the indice removal was a prototype to help debug it against the list() while being created

Typically a user wont manually do it unless he's issueing Serial response data or touchscreen uses (i guess)

Ideally, we can add a remove method for a matching buffer indice matching, just like replace() method

it wouldn't be too hard to make an automatic remove feature based on buffer input, all it would have to do is locate the indice if it exists a match and just feed the remove(indice) method after
 
Last edited:
Yeah seen that, but I'm not sure c++ iterators work over custom templates, besides, we don't want to search for single values in our system, i think it's better to search for matching headers in the arrays
 
Got it, now I understand :) I know in "R" it has a nice find function, will have to go searching for it again. Haven't used that one for awhile
 
i had issues at 30 at first, but it was due to bad ground, see #1431, its running with the 3.2 slave fix running on t3.5 @ 30mhz
 
Have to play around with some more - put double grounds on it but still couldn't gut up to 30. I was running the 24 with events at 500 and 10ms loop. Will keep playing with it. I tend to never give up.
 
i only ran ground from t3.6 pin next to pin13, and jumpered it to 3.5 slave besides pin0

and pin below 13 of t3.5 to common ground
 
ideally, for a find function, it must be something kind of easy to handle. think about this for a minute
the library already knows the size, but what if the user doesnt? we could return a pointer to the array, but user wouldnt know the size of the dataset.

things to keep track of for a find function:
we need to return the size
we need to return the buffer
optionally return the indice

this i think could be handled by more than one method, where the find locates the object and returns a bool on success or not. if successful, the class could setup the returns for the other methods with the data positions in hand

you could find(....args..), if bool true, you can then call ca.length, and ca.array could return the pointer for the dataset, which you could modify as necessary (changing a value rather than replacing the whole array..), and maybe a remove() without overload (nullptr) which deduces that if an iterator is set, to remove that entry from the queue and nullptr the internal iterator.

or if not edit you can find and remove that way as well:
if (ca.find(..args...)) ca.remove();

we can have different find methods as well
should we do like replace? except without feeding a buffer, were finding, something like:

ca.find(indice1,value,indice2,value,indice3,value); ?

we could also add a find for “char” arrays

ca.find(“text here”); // find queue containing “text here”
ca.remove(); // remove it from the queue
 
Last edited:
There is another possibility for the find function - probably will add complexity, so if too much let me know:
Code:
ca.find(>x), ca.find(<x), ca.find(== x), or even find all values "between"
what could be returned is an array of indices (if more than 1) that meet this criteria. Then the user can use those indices to do what he wants with the data.
 
Further Improvement To Slave Handling

Hey all,

The improvements are fantastic!

In my use case I want to be able to have multiple "types" of slaves that can hot-swap and identify using a universal handshake packet. To make it easy to program each type individually I am writing a wrapper class that performs the handshake and then attaches the appropriate handler object in the callback. I ran into an issue with the callback needing to be a static function and therefore being unable to interact with my (non-static) wrapper objects. The solution adds an overload to the callback code and another variable in AsyncMST that makes it this use case work. The change is to add a "parent" pointer in AsyncMST to reference an object from within the static callback function. All previous code still works with no changes. I hope that my solution will be useful for others who want to have a non-static callback. Example of using a wrapper object with the changes:

Code:
class Wrapper {
public:
	Wrapper(SPIClass * bus, uint32_t speed, uint8_t cs)
	{
		spi = SPI_MSTransfer("Serial", cs, bus, speed);
		spi.onTransfer(this->callback, this);
	}

	void parse(uint16_t *buffer, uint16_t length, AsyncMST info)
	{
		//non-static handling of callback here
	}
private:
	static void callback(uint16_t *buffer, uint16_t length, AsyncMST info)
	{
		Wrapper* obj = static_cast<Wrapper*>(info.parent);
		obj->parse(buffer, length, info);
	}
	SPI_MSTransfer spi = SPI_MSTransfer("NULL", "NULL");
};



If you think that this is a good feature to add to the library, the complete list of changes are as follows:


In SPI_MSTransfer.h:

New variable in AsyncMST:
Code:
struct AsyncMST {
  uint16_t packetID = 0;
  uint8_t error = 0;
  uint8_t cs = -1;
  void* parent = nullptr;
};

New overload to callback function in public definitions
Code:
  virtual void            onTransfer(_slave_handler_ptr handler);
  virtual void            onTransfer(_slave_handler_ptr handler, void* Parent);

New pointer in private definitions:
Code:
  private:
    void* parent = nullptr;

In SPI_MSTransfer.cpp:

The actual overloaded function:
Code:
void SPI_MSTransfer::onTransfer(_slave_handler_ptr handler, void* Parent)
{
  parent = Parent;
  this->onTransfer(handler);
}


And two new lines in .events() for both slave and master code after a AsyncMST struct is created:
Code:
  info.parent = parent;


P.S. I hope I'll finish the "type" hot-swap and handshake example soon. Maybe there are more easy features that to add!
 
Last edited:
sounds good, i didnt check if the callback was static or not, if you suggest we do that thats fine too
theres also the onDetect lambda function available for hotplugging (well it detects slave was reset status, not really hotplugging), but its a start :) (at least its good for restoring pinModes, pin states, port settings, etc)
 
Mike, couldnt we just do a custom find function thats specific to users needs, using a cstring match like the constructor does?

example:
to find and remove a matching array by indice:

ca.remove(val) removes an indice, so lets prefer an indice return:

ca.remove(ca.find(“indice”,1,2,3,0x33,px44,0x55));

obviously it would be nice to figure out what values to search for, searching for strings would be easier, the find above would feed the indice to the remove method, or return -1 if nothing found, and remove wont process it if its -1.

then for a pointer to the array we would need to pass a reference to find:
uint16_t *myArray, length = 0;
myArray = ca.find(length, 1,2,3,0x33,0x44,0x55);

length would be updated and the pointer would be set to the dataset

or we should just go with multiple calls like before when the iterator is set
ca.find(1,2,3,0x33,0x44,0x55);
uint16_t = ca.length();
uint16_t *myDataset = ca.data();
myDataset[1] = 0x66;
ca.list();
ca.remove();
 
Last edited:
Believe it or not I am still here. Got side tracked on another project for a little while. I was spinning with all the changes. Sorry I missed you last post.

As for the find function. Think it would be better with the custom version. How difficult would be to implement it that way.
 
Difficulty of implementation? 4? Difficulty of where to start? 10 :p

I already stripped the Circular_Buffer library of reading value of cbuf for cabuf array system, and just follow the head&tail, this now does less lookups as it doesnt need to read an unused array :)
 
Isn't that always the way - where to start is the hardest.

I just read the change you made to the CB library. Always looking for improvements, eh. :)

I have to start playing with examples again, before I forget, but I got a new toy in that got involved with. Almost done. Just got to get one more thing working.

For me examples are good for two reasons when I write them: (1) I learn how it really works and (2) I have to remember how they work :)
 
The SERIAL block is complete! we have working SERIAL, F&F, GPIOS! Still progressing! :) I did a test println() from master to slave and it is indeed working as it should ! :)

EDIT, EEPROM block adapted
EDIT, ANALOG ADAPTED
EDIT, WIRE DONE, 23 methods adapted, added ifdefs to enable Wire1 on TeensyLC
EDIT, SPI SECTION DONE! 12 methods adapted. added ifdefs to enable SPI1 on TeensyLC
 
Last edited:
Alright, here it is! (Slave conversion only for now), this adaptation is based off the lastest github copy, it should compile and run properly on all LC,3.2,3.5, and 3.6's ! :)
Let some results fly! :)

Code:
[ATTACH]13755._xfImport[/ATTACH]

Enjoy :)

Wait a minute, I must be crazy! It's the same library, so if it compiles as is on LC, master should be working! hahahaah :D

For LC, play with the buffers! I lowered them while testing to make it "fit" :)
 
Back
Top