hi so im making a hierarchy sort of structure for a robotic walker to make the number of servos manageable and im trying to create a Limb class that contains a number of servo classes (yes im using the built in servo Library but i want to also tweak the offset,scale ect. of the value for calibration purposes) anyway hear is my code.
the problem is the Limb Class initiator (bottom 4 lines) i usually dont like just straight up asking for the correct line of code and prefer to figure it out but iv tried everything i can think of
PS i apolagise for any crap spelling and thanks
class ServoConfig{
public :
float Offset;
float Scale;
bool Inversed;
Servo ServoV;
ServoConfig (float InOffset, float InScale, bool InInversed,int Pin){
float Offset = InOffset;
float Scale = InScale;
bool Inversed = InInversed;
ServoV.attach(Pin);
}
void WriteToServo(float Angle){
if (Inversed){
ServoV.write((180-Angle)/Scale + Offset);
}
else{
ServoV.write(Angle/Scale + Offset);
}
}
};
class Limb{
ServoConfig Servos[];
Limb (ServoConfig InServos[]){
ServoConfig Servos[] = InServos;
}
};
It's not so easy in C++ and on Arduino it's even harder.
But first you have loads of mistakes in code. For example shadowing class attibutes by local variables:
ServoConfig (float InOffset, float InScale, bool InInversed,int Pin) {
float Offset = InOffset; // this will create new local variable and hides that one in class with the same name
float Scale = InScale; // this too
bool Inversed = InInversed; // and this too
The same is in Limb constructor, but it doesn't work anyways.
And how it can be working? You can use something like this:
#include <Servo.h>
class ServoConfig {
public :
float Offset;
float Scale;
bool Inversed;
Servo ServoV;
ServoConfig (float InOffset, float InScale, bool InInversed,int Pin)
: Offset { InOffset }
, Scale { InScale }
, Inversed { InInversed }
{
ServoV.attach(Pin); // it might have to be attached in setup() as constructors are called before main()
}
void WriteToServo(float Angle){
if (Inversed) {
ServoV.write((180-Angle)/Scale + Offset);
} else {
ServoV.write(Angle/Scale + Offset);
}
}
};
ServoConfig servos[] = {{10,10,0,9},{0,1,0,10}}; // this makes servos of size two and calls constructors
class Limb {
public:
ServoConfig * servos_begin;
ServoConfig * servos_end;
Limb(ServoConfig * beg, ServoConfig * end)
: servos_begin { beg }
, servos_end { end }
{;}
ServoConfig * begin() { return servos_begin; }
ServoConfig * end() { return servos_end; }
size_t size() { return servos_end - servos_begin; }
};
// much better than using sizeof(array)/sizeof(array[0]):
template <class T, size_t size> size_t arraySize(T(&)[size]) { return size; }
// create and construct Limb instance:
Limb limb { servos, servos + arraySize(servos)};
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.println("starting...");
for (ServoConfig & servo : limb) { // this uses begin() and end() methods
servo.WriteToServo(90);
}
// or directly with array[]
for (ServoConfig & servo : servos) {
servo.WriteToServo(40);
}
}
Related
TL;DR What should the type of x be if x = x(); is valid in C?
The whole story:
I am working on a simple game with multiple scenes. At first my code looked like this:
enum {kSCENE_A, kSCENE_B} ecene = kSCENE_A;
int main() {
while(1) {
switch(scene) {
case kSCENE_A:
// Renders scene a
// And possibly modifies `scene`
break;
case kSCENE_B:
// Renders scene b
// And possibly modifies `scene`
break;
}
}
}
However the main function is too verbose. I extracted the rendering part into different functions, but the switch still makes the code ugly. I defined a scene_map for this:
typedef enum {
kSCENE_A,
kSCENE_B,
kN_SCENES
} Scene;
Scene RenderSceneA();
Scene RenderSceneB();
int main() {
Scene scene = kSCENE_A;
Scene (*scene_map[kN_SCENES])();
scene_map[kSCENE_A] = SceneA;
scene_map[kSCENE_B] = SceneB;
while(1) scene = scene_map[scene]();
}
But I wonder if it would be possible in C that I write the code in this, or some similar way:
SomeType RenderSceneA();
SomeType RenderSceneB();
int main() {
SomeType scene = RenderSceneA;
while(1) scene = scene();
}
So what type should SomeType be, or can I only use void * for it? If the latter is true, how can I write this code in a clear manner than demonstrated in the second code block?
Here's a solution that will solve the problem. Note that it uses void (*)(void) as a generic function pointer type, as opposed to void * which isn't guaranteed to work for function pointers:
#include <stdio.h>
void (*f(void))(void);
void (*g(void))(void);
void (*f(void))(void)
{
printf("This is f.\n");
return (void (*)(void)) g;
}
void (*g(void))(void)
{
printf("This is g.\n");
return (void (*)(void)) f;
}
#define SRCALL(p) ((void (*(*)(void))(void)) p())
int main(void)
{
void (*(*p)(void))(void);
p = f;
p = SRCALL(p);
p = SRCALL(p);
p = SRCALL(p);
return 0;
}
The function pointer casts are ugly, so I encapsulated them in the macro SRCALL (self-ref-call). The output is:
This is f.
This is g.
This is f.
I am trying to create a small fixed size list of string, int tuples. A fixed size array of structs seemed like the way to go, but when manipulating the array entries, I constantly run into memory errors. What I've tried so far:
public struct S {
public string a;
public int b;
public S (string a, int b) {
this.a = a;
this.b = b;
}
}
public class Test {
public S arr[5];
public static void main () {
var test = new Test ();
test.arr[0].a = "hi";
test.arr[0].b = 5;
/* alternatively: */
//test.arr[0] = S ("hi", 5);
}
}
I have looked into the compiled C code, but I am not really familiar with C.
I read everything I found about vala structs and arrays of structs, but the little bit that's out there didn't enlighten me either.
The fixed size array seems to get initialized with "empty" structs, do I need to initialize it beyond that, somehow?
What am I misunderstanding about arrays of structs here?
Is there an alternative way to implement a fixed size list of string, int tuples? Are arrays of structs not suited for that?
Any help is greatly appreciated! It seems like such a simple task, but I've been struggling with it for days now :/ ...
First, you can make the C code quite a bit simpler by specific "Compact" on the class and disabling the type on the struct:
[CCode(has_type_id = false)]
public struct S {
public string a;
public int b;
public S (string a, int b) {
this.a = a;
this.b = b;
}
}
[Compact]
public class Test {
public S arr[5];
public static void main () {
var test = new Test ();
test.arr[0].a = "hi";
test.arr[0].b = 5;
/* alternatively: */
//test.arr[0] = S ("hi", 5);
}
}
Not a full answer, but it seems like there is a problem in the compiler generated destruction code:
void test_free (Test* self) {
_vala_array_destroy (self->arr, 5, (GDestroyNotify) s_destroy);
g_slice_free (Test, self);
}
static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func) {
if ((array != NULL) && (destroy_func != NULL)) {
int i;
for (i = 0; i < array_length; i = i + 1) {
if (((gpointer*) array)[i] != NULL) {
destroy_func (((gpointer*) array)[i]);
}
}
}
}
Note how the array parameter (which is of type gpointer, but was casted from an S[], namely arr) is casted to a gpointer* before the destroy_func () is called on it.
That would be fine if arr were a dynamic array, but it isn't.
If I modify the compiler output by hand everything works fine:
static void _vala_array_destroy (S* array, gint array_length, GDestroyNotify destroy_func) {
if ((array != NULL) && (destroy_func != NULL)) {
int i;
for (i = 0; i < array_length; i = i + 1) {
if (&array[i] != NULL) {
destroy_func (&array[i]);
}
}
}
}
The destroy function (destroy_func aka s_destroy) is now called on a valid S* (the address of the struct inside the array).
So it seems to me that you have discovered a compiler bug.
PS: Using a dynamic array works just fine, I would either do that or use some higher level data type like a Gee.ArrayList instead of a static array.
I have declared the one static member inside the static method. like as follws:
static void temp1(param..){
static gint x,y ;
#TODO what you needed
values get changed here for x,y;
}
And I want to access this Two in other static method within the same file.
static void temp2 ( param .......){
accessing the x,y
}
How should I do it..? I don't want to declare public member and also don't want to change the method param's .
This might almost be what you want:
static gint x,y ;
static void temp1(param..){
/* TODO what you needed */
values get changed here for x,y;
}
static void temp2 ( param .......){
/* accessing the x,y */
}
x and y are globally accessible, but only within the file, just like your static procedures. I think this is as close as you can get to what you want.
You need to understand these 2 things:
Scope
and
Lifetime
the scope of your static variables is only inside the function they are declared. they cannot be accessed outside.
but the lifetime of your variables is throughout your program, that is they will retain the values until the program is running.
So maybe you would like to declare your variables outside of your function. so instead of
static void temp1(param..){
static gint x,y ;
#TODO what you needed
values get changed here for x,y;
}
you can have
static gint x,y ;
static void temp1(param..){
#TODO what you needed
values get changed here for x,y;
}
The exact use case you have, i think it would not be possible without changing the second function's arguments.
static int getInnerStatic(int* _x, int* _y, int ignore);
static void temp1(param..){
static int x,y ;
////////////////
if (getInnerStatic(&x,&y,1))
return;
////////////////
#TODO what you needed
values get changed here for x,y;
}
static int getInnerStatic(int* _x, int* _y, int ignore){
static int innerInvok = 0;
static int x, y;
if (innerInvok == 1){
x = *_x;
y = *_y;
return innerInvok;//1
}
if (ignore)
return innerInvok;//0
innerInvok = 1;
temp1(/*anything as param...*/);
innerInvok = 0;
*_x = x;
*_y = y;
return innerInvok;//0
}
//get static x y :
static void temp2 ( param .......){
int getX, getY;
getInnerStatic(&getX, &getY, 0); // <- accessing the x,y
}
Here is an example of what you are trying to do:
#include <iostream>
using namespace std;
static void temp1() {
static int x,y ;
x = 5;
y = 8;
}
static void temp2 (){
cout << temp1::x << endl;
}
int main() {
temp2()
return 0;
}
Error message
error: ‘temp1’ is not a class or namespace
Note the error that occurs when you try to access x in temp1 by using the scope resolution operator ::. Here is how to solve this
#include <iostream>
using namespace std;
namespace temp {
class temp1 {
public:
static int x,y;
};
int temp1::x = 5;
int temp1::y = 7;
}
static void temp2 (){
cout << temp::temp1::x << endl;
}
int main() {
temp2();
return 0;
}
Note the namespace is not necessary, but I used it to keep related data together
You cant do that with your existing code you need to modify your code to make x and y as static instance variables so that you can access them in all the static methods.
I have a 2D node scene graph that I'm trying to 'nest' stencil clipping in.
I was thinking what I could do is when drawing the stencil, increment any pixel it writes to by 1, and keep track of what the current 'layer' is that I'm on.
Then when drawing, only write pixel data to the color buffer if the value of the stencil at that pixel is >= the current layer #.
This is the code I have now. It doesn't quite work. Where am I messing up?
First I call SetupStencilForMask().
Then draw stencil primitives.
Next, call SetupStencilForDraw().
Now draw actual imagery
When done with a layer, call DisableStencil().
Edit: Updated with solution. It doesn't work for individual items on the same layer, but otherwise is fine.
Found a great article on how to actually pull this off, although it's fairly limited.
http://cranialburnout.blogspot.com/2014/03/nesting-and-overlapping-translucent.html
// glClear(GL_STENICL_BIT) at start of each draw frame
static int stencilLayer = 0;
void SetupStencilForMask(void)
{
if (stencilLayer == 0)
glEnable(GL_STENCIL_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilFunc(GL_LESS, stencilLayer, 0xff);
glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
glStencilMask(0xff);
if (stencilLayer == 0)
glClear(GL_STENCIL_BUFFER_BIT);
stencilLayer++;
}
void SetupStencilForDraw()
{
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, stencilLayer, 0xff);
glStencilMask(0x00);
}
void DisableStencil(void)
{
if (--stencilLayer == 0)
glDisable(GL_STENCIL_TEST);
}
I have figured out the way to do this in libgdx. I'm not sure you still need this, but for future reference here is the code:
/**
* Start cropping
*
* #param cropMask
* Mask plane
*/
public void startCropping(Plane cropMask) {
// Check if there is active masking group
if (activeCropMaskGroup == null) {
// Create new one
activeCropMaskGroup = new CropMaskingGroupDescriptor(cropMask);
} else {
// Increase hierarchy level
activeCropMaskGroup.increaseHierachy(cropMask);
}
}
/** End cropping */
public void endCropping() throws IllegalStateException {
// Check if there is active group mask
if (activeCropMaskGroup == null) {
throw new IllegalStateException("Call start cropping before this!");
}
if (activeCropMaskGroup.getHierachy() > 0) {
activeCropMaskGroup.decreaseHierachy();
} else {
// Finish setup of crop data
cropMaskGroups.add(activeCropMaskGroup);
activeCropMaskGroup = null;
}
}
/** Crop registered planes for cropping */
private void cropRender(CropMaskingGroupDescriptor cropMaskGroupDescriptor) {
// Draw mask to stencil buffer
Gdx.gl.glClear(GL20.GL_STENCIL_BUFFER_BIT);
// setup drawing to stencil buffer
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
// Number of registered hierarchy levels
int hierarchyLevels = cropMaskGroupDescriptor.getRegisteredBatch().size();
// Loop trough hierarchy
for (int hierarchyLevel = 0; hierarchyLevel < hierarchyLevels; hierarchyLevel++) {
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
Gdx.gl20.glStencilOp(GL20.GL_INCR, GL20.GL_INCR, GL20.GL_INCR);
Gdx.gl20.glColorMask(false, false, false, false);
Gdx.gl20.glDepthMask(false);
// Draw mask with decal batch
cropMaskBatch.add(((NativePlane) cropMaskGroupDescriptor.getCroppingMasks().get(hierarchyLevel)).getPlane());
cropMaskBatch.flush();
// fix stencil buffer, enable color buffer
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glDepthMask(true);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
// draw where pattern has been drawn
Gdx.gl20.glStencilFunc(GL20.GL_LEQUAL, hierarchyLevel + 1, 0xffffffff);
// Loop trough registered masked layers and found which one belongs
// to
// current hierarchy level
for (int i = 0; i < cropMaskGroupDescriptor.getMaskedLayers().size(); i++) {
if (cropMaskGroupDescriptor.getMaskedLayers().get(i).getHierarchyId() == hierarchyLevel) {
Plane plane = cropMaskGroupDescriptor.getMaskedLayers().get(i).getMaskedPlane();
cropMaskGroupDescriptor.getRegisteredBatch().get(hierarchyLevel).add(((NativePlane) plane).getPlane());
}
}
cropMaskGroupDescriptor.getRegisteredBatch().get(hierarchyLevel).flush();
}
Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);
}
And inner class inside renderer module.
/**
* Cropped layer descriptor
*
* #author Veljko Ilkic
*
*/
private class CropMaskLayerDescriptor {
/** Layer that needs to be masked */
private Plane maskedPlane;
/** Hierarchy level in which belongs */
private int hierarchyId = 0;
/** Constructor 1 */
public CropMaskLayerDescriptor(Plane maskedPlane, int hierarchyId) {
this.maskedPlane = maskedPlane;
this.hierarchyId = hierarchyId;
}
public Plane getMaskedPlane() {
return maskedPlane;
}
public int getHierarchyId() {
return hierarchyId;
}
}
/**
* Crop masking group descriptor class
*
* #author Veljko Ilkic
*
*/
private class CropMaskingGroupDescriptor {
/** Crop mask */
private ArrayList<Plane> croppingMasks = new ArrayList<Plane>();
/** Planes that will be masked by crop mask */
private ArrayList<CropMaskLayerDescriptor> maskedLayers = new ArrayList<Renderer.CropMaskLayerDescriptor>();
/** Batch for drawing masked planes */
private ArrayList<DecalBatch> hierarchyBatches = new ArrayList<DecalBatch>();
private int activeHierarchyLayerId = 0;
/** Constructor 1 */
public CropMaskingGroupDescriptor(Plane topLevelCropMask) {
// Create batch for top level hierarchy
hierarchyBatches.add(new DecalBatch(new CameraGroupStrategy(perspectiveCamera)));
// Register top level crop mask
croppingMasks.add(topLevelCropMask);
}
/** Increase hierarchy level of the group */
public void increaseHierachy(Plane hierarchyCropMask) {
activeHierarchyLayerId++;
// Create individual batch for hierarchy level
hierarchyBatches.add(new DecalBatch(new CameraGroupStrategy(perspectiveCamera)));
// Register crop mask for current hierarchy level
croppingMasks.add(hierarchyCropMask);
}
/** Decrease hierarchy group */
public void decreaseHierachy() {
activeHierarchyLayerId--;
}
/** Get current hierarchy level */
public int getHierachy() {
return activeHierarchyLayerId;
}
/** Register plane for masking */
public void registerLayer(Plane maskedPlane) {
hierarchyBatches.get(activeHierarchyLayerId).add(((NativePlane) maskedPlane).getPlane());
maskedLayers.add(new CropMaskLayerDescriptor(maskedPlane, activeHierarchyLayerId));
}
/** Get all registered batched */
public ArrayList<DecalBatch> getRegisteredBatch() {
return hierarchyBatches;
}
/** Get registered cropping masks */
public ArrayList<Plane> getCroppingMasks() {
return croppingMasks;
}
/** Get layer that should be masked */
public ArrayList<CropMaskLayerDescriptor> getMaskedLayers() {
return maskedLayers;
}
/** Dispose */
public void dispose() {
for (int i = 0; i < hierarchyBatches.size(); i++) {
hierarchyBatches.get(i).dispose();
hierarchyBatches.set(i, null);
}
hierarchyBatches.clear();
}
}
Hope this helps.
Am I complicating things?
I'm architecting my code to talk from a 8051 micro to a peripheral device over UART. The peripheral responds to commands from the host and can only respond to one command at a time. It's a simple send and receive protocol. (tx1, rx1, tx2, rx2, tx3, rx3) Each TX message is terminated with a CR, each response is terminated with a >. I can't send a new message until I receive the response to the last one. Responses can also echo print the original TX message in the beginning if I enable that option (but this causes more traffic)
An example message would be:
TX: Hello
RX: World!>
Or with echo option...
TX: Hello
RX: Hello\rWorld!>
Option A
A function such as getHello would consist of both the send and receive. A parallel ISR routine would gather the incoming bytes and throw a flag when the '>' character is received.
char* getHello(char * buf){
sendMsg("Hello\r");
delay(10ms); //wait a little bit
//wait for receive to come in or timeout to occur
while(!receiveFlag || !timeoutFlag); //thrown by ISR
receiveMsg(buf);
//parse the message and do some other stuff
return buf;
}
Pros:
Everything is contained within one function.
Easier to debug
Cons:
This function is blocking and could hang if the peripheral never responds so a timeout must be implemented.
Messages can't be received out of order, must be in series (ie, tx1, rx1, tx2, rx2, tx3, rx3)
Option B
A parallel approach is taken. Two separate functions would created. one to send the message, and one that would vertexed upon receiving a response from the ISR.
void sendHello(){
sendMsg("Hello\r");
//do some other stuff if needed
}
char* receiveMsg(char * buf){
//figure out from echo print what the tx message was
//use a switch statement to decide which response parser to call
switch(txMessage){ //pseudo code
case "Hello":
receiveMsg(buf);
//parse the message and do some other stuff
break;
}
return buf;
}
Pros:
Can handle parallel messages coming back out of order because it relies on the echo printing of the tx message to figure out how to parse it. (ie, tx1, tx2, tx3, rx1,rx2,rx3)
Cons:
quite difficult to debug
spawns multiple threads
lots of extra code
not worth it since messages will definitely come back in order
Right now, I'm doing Option B, but as I continue on with the project, I begin to feel like this is getting overly complex. I'm curious what you guys think.
Thanks!
I tend to do this kind of stuff, though, Id tend to have a separate serial port "class" ( struct + functions ) and a protocol class that lives over the top of serial port. I used these all the time in my embedded systems. This gives you the best of both worlds, a blocking synchronous call and an async call so you can pseudo multitask.
typedef struct serial_port_s serial_port;
typedef void (*serial_on_recived_proc)(serial_port* p);
typedef struct serial_port_s{
bool timeoutFlag;
bool receiveFlag;
void* context;
serial_on_recived_proc response_handler;
};
void send_serial(serial_port* p, char* message)
{
//SendMsg?
}
void receive_serial(serial_port* p, char* response)
{
//receiveMsg?
}
bool has_data(serial_port* p)
{
return p->receiveFlag;
}
bool has_timed_out(serial_port* p)
{
return p->timeoutFlag;
}
bool is_serial_finished(serial_port* p)
{
return has_data(p) || has_timed_out(p);
}
bool serial_check(serial_port* p)
{
if(is_serial_finished(p) && p->response_handler != NULL)
{
p->response_handler(p)
p-> response_handler = NULL;
return true;
}
return false;
}
void send(serial_port* p, char* message, char* response)
{
p->response_handler=NULL;
send_serial(p, message);
while(!is_serial_finished(p));
receive_serial(p, response);
}
void sendAsync(serial_port* p, char* message, serial_on_recived_proc handler, void* context)
{
p->response_handler = handler;
p->context = context;
send_serial(p, message);
}
void pow_response(serial_port* p)
{
// could pass a pointer to a struct, or anything depending on what you want to do
char* r = (char*)p->context;
receive_serial(p, r);
// do stuff with the pow response
}
typedef struct
{
char text[100];
int x;
bool has_result;
} bang_t;
void bang_parse(bang_t* bang)
{
bang->x = atoi(bang->text);
}
void bang_response(serial_port* p)
{
bang_t* bang = (bang_t*)p->context;
receive_serial(p, bang->text);
bang_parse(bang);
bang->has_result=true;
}
void myFunc();
{
char response[100];
char pow[100];
bang_t bang1;
bang_t bang2;
serial_port p; //
int state = 1;
// whatever you need to do to set the serial port
// sends and blocks till a response/timeout
send(&p, "Hello", response);
// do what you like with the response
// alternately, lets do an async send...
sendAsync(&p, "Pow", pow_response, pow);
while(true)
{
// non block check, will process the response when it arrives
if(serial_check(p))
{
// it has responded to something, we can send something else...
// using a very simple state machine, work out what to send next.
// in practice I'd use enum for states, and functions for managing state
// transitions, but for this example I'm just using an int which
// I just increment to move to the next state
switch(state)
{
case 1:
// bang1 is the context, and will receive the data
sendAsync(&p, "Bang1", bang_response, &bang1);
state++;
break;
case 2:
// now bang2 is the context and will get the data...
sendAsync(&p, "Bang2", bang_response, &bang2);
state++;
break;
default:
//nothing more to send....
break;
}
}
// do other stuff you want to do in parallel
}
};
Take things simple. An ISR routine must be very fast so for me the best approch is to have a global RXBuffer like this:
#include <cstdint>
#include <deque>
#include <algorithm>
class RXBuffer {
public:
friend class ISR;
typedef std::deque<uint8_t>::const_iterator const_iterator;
RXBuffer();
size_t size() const { m_buffer.size(); }
// read from the buffer in a container in the range [first, last)
template <typename Iterator>
void read(Iterator first, Iterator last, Iterator to)
{
// how many bytes do you want to read?
size_t bytes_to_read = std::distance(first, last);
if (bytes_to_read >= size())
{
// read the whole buffer
std::copy(begin(), end(), first);
// empty the buffer
m_buffer.clear();
return size();
}
else
{
// copy the data
copy(begin(), begin() + bytes_to_read, firt);
// now enque the element
m_buffer.erase(begin(), begon() + bytes_to_read);
return bytes_to_read;
}
}
private:
void put(uint8_t data)
{
// check buffer overflow
m_buffer.push_back(data);
}
const_iterator begin() const { return m_buffer.begin(); }
const_iterator end() const { return m_buffer.end(); }
private:
std::deque<uint8_t> m_buffer; // buffer where store data
size_t m_size; // effective size of the container
};
class ISR {
public:
ISR(RXBuffer& buffer) : m_buffer(buffer) {}
// ISR Routine
void operator () (uint8_t data)
{
m_buffer.put(data);
}
private:
RXBuffer& m_buffer;
};
RXBuffer g_uart1_rx_buffer;
Now you have the ISR and a RXBuffer where search data, so you need something to wrap the UART functions. You can implement as follow:
class UART {
public:
UART(unsigned int uart_device, RXBuffer& rx_buffer) :
m_uart(uart_device), m_buffer(rx_buffer)
{
}
unsigned int uart_device() const { return m_uart; }
// set the timeout during a read operation
void timeout(unsigned ms) { m_timer.countdown(ms); }
template <typename InputIterator>
void read(InputIterator first, InputIterator last)
{
// start the timer
m_timer.start();
size_t size = std::distance(first, last);
size_t read_bytes = 0;
while (read_bytes != size && !m_timer.is_expired())
{
read_bytes += m_buffer.read(first + read_bytes, last);
}
if (read_bytes != size) throw std::exception("timeout");
}
template <typename OutputIterator>
void send(OutputIterator first, OutputIterator last)
{
size_t size = std::distance(first, last);
uart_send(m_uart, &(*first), size);
}
private:
unsigned int m_uart;
RXBuffer& m_buffer;
timer m_timer;
};