Skip to content

Instantly share code, notes, and snippets.

@baragona
Created December 16, 2014 02:53
Show Gist options
  • Save baragona/e5798d0f694fe1a9fe1b to your computer and use it in GitHub Desktop.
Save baragona/e5798d0f694fe1a9fe1b to your computer and use it in GitHub Desktop.
CNC machine control on bare metal - serial port communication...
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#define TMR0STEPS REGISTER(TIMERSBASE,4)
#define TMR0DESIRED REGISTER(TIMERSBASE,5)
#define TMR0QUAD REGISTER(TIMERSBASE,6)
#define TMR0MAXOVERSHOOT REGISTER(TIMERSBASE,7)
#define tim1off 64
#define tim2off 128
#define tim3off 192
#define TMR2CTL REGISTER(TIMERSBASE,tim2off+0)
#define TMR2CNT REGISTER(TIMERSBASE,tim2off+1)
#define TMR2CMP REGISTER(TIMERSBASE,tim2off+2)
#define TMR2STEPS REGISTER(TIMERSBASE,tim2off+4)
#define TMR2DESIRED REGISTER(TIMERSBASE,tim2off+5)
#define TMR2QUAD REGISTER(TIMERSBASE,tim2off+6)
#define TMR2MAXOVERSHOOT REGISTER(TIMERSBASE,tim2off+7)
#define TMR2PWMLOW(x) REGISTER(TIMERSBASE, tim2off+32+(4*x))
#define TMR2PWMHIGH(x) REGISTER(TIMERSBASE, tim2off+33+(4*x))
#define TMR2PWMCTL(x) REGISTER(TIMERSBASE, tim2off+34+(4*x))
#define TMR3CTL REGISTER(TIMERSBASE,tim3off+0)
#define TMR3CNT REGISTER(TIMERSBASE,tim3off+1)
#define TMR3CMP REGISTER(TIMERSBASE,tim3off+2)
#define TMR3STEPS REGISTER(TIMERSBASE,tim3off+4)
#define TMR3DESIRED REGISTER(TIMERSBASE,tim3off+5)
#define TMR3QUAD REGISTER(TIMERSBASE,tim3off+6)
#define TMR3MAXOVERSHOOT REGISTER(TIMERSBASE,tim3off+7)
#define TMR3PWMLOW(x) REGISTER(TIMERSBASE, tim3off+32+(4*x))
#define TMR3PWMHIGH(x) REGISTER(TIMERSBASE, tim3off+33+(4*x))
#define TMR3PWMCTL(x) REGISTER(TIMERSBASE, tim3off+34+(4*x))
struct frameCommand{
int desiredPos[3];
};
#include "wing_buffer.h"
const int TimerRingBufSize = 600;
struct frameCommand wing_buffer_data[TimerRingBufSize];
wing_buffer wingBuf1;
unsigned idum=0;
uint16_t lastPsc=1024;
uint16_t lastCmp=65535;//Assume worst possible initially
int curfreq=50;
int freqdir=1;
int desired=0;
int framerate;
double microsPerFrame=1;
double fudgeFactor = 1.1;
double microsPerFrameFudged=1;
int maxOvershoot[3]={800,800,800};
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
inline void store_u32(unsigned char *dest, uint32_t value)
{
*dest++=(value>>24);
*dest++=(value>>16);
*dest++=(value>>8);
*dest=value;
}
inline uint32_t read_u32(unsigned char *src){
uint32_t v1=src[0];
uint32_t v2=src[1];
uint32_t v3=src[2];
uint32_t v4=src[3];
return (v1<<24) | (v2<<16) | (v3<<8) | v4;
}
uint8_t digitalReadBool(int pin){
if(digitalRead(pin)>0){
return 1;
}
return 0;
}
void setFrameRate(int fr){
fr=max(fr,6);
fr=min(fr,10000);
framerate=fr;
int cmp = round(96000000.0/fr);
microsPerFrame=cmp/96.0;
microsPerFrameFudged=microsPerFrame*fudgeFactor;
TMR1CNT = 0;
TMR1CMP = cmp-1;
}
float sine(float x)
{
const float pi = 3.1415926535;
const float B = 4/pi;
const float C = -4/(pi*pi);
float y = B * x + C * x * abs(x);
return y;
}
struct stepperConstants {
volatile unsigned * ctl;
volatile unsigned * cnt;
volatile unsigned * steps;
volatile unsigned * desired;
volatile unsigned * cmp;
volatile unsigned * pwmh;
volatile unsigned * pwml;
volatile unsigned * pwmctl;
volatile unsigned * maxovershoot;
int steppps;
int dirpps;
int steppin;
int dirpin;
int sleeppin;
};
struct stepperVars{
uint16_t lastPsc;
};
struct stepperVars stepvars[3];
const struct stepperConstants steppers[3]={
{
&TMR0CTL,
&TMR0CNT,
&TMR0STEPS,
&TMR0DESIRED,
&TMR0CMP,
&TMR0PWMHIGH(0),
&TMR0PWMLOW(0),
&TMR0PWMCTL(0),
&TMR0MAXOVERSHOOT,
IOPIN_TIMER0_OC,
7,
WING_A_0,
WING_B_15,
WING_B_9
},
{
&TMR2CTL,
&TMR2CNT,
&TMR2STEPS,
&TMR2DESIRED,
&TMR2CMP,
&TMR2PWMHIGH(0),
&TMR2PWMLOW(0),
&TMR2PWMCTL(0),
&TMR2MAXOVERSHOOT,
10,
8,
WING_A_1,
WING_B_14,
WING_B_8
},
{
&TMR3CTL,
&TMR3CNT,
&TMR3STEPS,
&TMR3DESIRED,
&TMR3CMP,
&TMR3PWMHIGH(0),
&TMR3PWMLOW(0),
&TMR3PWMCTL(0),
&TMR3MAXOVERSHOOT,
11,
9,
WING_A_2,
WING_B_13,
WING_B_7
}
};
const int nSwitches = 3;
//int switchPins[nSwitches]={WING_A_3, WING_A_4, WING_A_5};//, WING_A_6, WING_B_12, WING_B_11, WING_B_10, WING_B_9}; //the real one
int switchPins[nSwitches]={WING_A_7, WING_A_8, WING_A_5};//, WING_A_6, WING_B_12, WING_B_11, WING_B_10, WING_B_9};//test one
char switchStates[nSwitches];
unsigned int switchTimeLastChanged[nSwitches];
int switchHasSettled[nSwitches];
void setup() {
Serial.begin(115200);
wb_init(&wingBuf1,TimerRingBufSize,wing_buffer_data);
unsigned frequency = 100000;
reset_integrator();
for(int i =0;i<3;i++){
*steppers[i].cnt = 0;
//TMR0CMP = (CLK_FREQ/frequency) - 1 ;
*steppers[i].ctl = _BV(TCTLENA)|_BV(TCTLCCM)|_BV(TCTLDIR)|_BV(TCTLCP0)|_BV(TCTLCP1)|_BV(TCTLCP2);
*steppers[i].pwml = 0;
*steppers[i].pwmh=10;
//*steppers[i].pwmctl=1;
//const int pin = WING_A_0;
//const int dirpin0 = WING_A_1;
pinMode(steppers[i].steppin, OUTPUT);
pinModePPS(steppers[i].steppin,HIGH);
outputPinForFunction(steppers[i].steppin,steppers[i].steppps);
pinMode(steppers[i].dirpin, OUTPUT);
pinModePPS(steppers[i].dirpin,HIGH);
outputPinForFunction(steppers[i].dirpin,steppers[i].dirpps);
pinMode(steppers[i].sleeppin, OUTPUT);
stepvars[i].lastPsc=1024;
}
setSteppersEnabled(1);
for(int i=0;i<nSwitches;i++){
int pin =switchPins[i];
pinMode(pin,INPUT);
//inputPinForFunction(pin,i);
switchStates[i]=0;
switchTimeLastChanged[i]=TIMERTSC;
}
pinMode(WING_A_7,INPUT);
pinMode(WING_A_8,INPUT);
pinMode(WING_A_9,INPUT);
pinMode(WING_A_10,INPUT);
pinMode(WING_A_11,INPUT);
pinMode(WING_A_12,INPUT);
TMR1CNT = 0;
//TMR1CMP = 4000000;//should be 24hz //Set in setFrameRate
setFrameRate(24);
TMR1CTL = _BV(TCTLENA)|_BV(TCTLCCM)|_BV(TCTLDIR)|_BV(TCTLIEN);
INTRMASK = _BV(INTRLINE_TIMER1);
INTRCTL = 1;//enable interrupts
}
const int debounceMicros = 1000000;
int checkSwitches(){
for(int i=0;i<nSwitches;i++){
//Serial.println(read);
if(switchHasSettled[i]||((TIMERTSC - switchTimeLastChanged[i]) > debounceMicros*96)){
int read =digitalReadBool(switchPins[i]);
if(switchStates[i] != read){
switchTimeLastChanged[i]=TIMERTSC;
switchHasSettled[i]=0;
switchStates[i]=read;
uint8_t buffer[8];
uint8_t * buf_ptr= buffer;
store_u32(buf_ptr ,i);buf_ptr+=4;//Which Switch
store_u32(buf_ptr, read);buf_ptr+=4;//New Value
send_message(2,buffer,8);
break;
}else{
switchHasSettled[i]=1;
}
}else{
//Nothing.
}
}
}
volatile unsigned cycles(){
return *(unsigned*) &TIMERTSC;
}
void setSteppersEnabled(int enabled){
for(int i =0;i<3;i++){
int old = *(steppers[i].pwmctl);
if(enabled){
old |= _BV(TPWMEN);
}else{
old &= ~_BV(TPWMEN);
}
*(steppers[i].pwmctl)=old;
}
}
int readStringWithTimeout(void * buf, int len, unsigned timeoutMicros){
//Serial.println("read");
unsigned start_t = TIMERTSC;
for(int i=0;i<len;i++){
if(TIMERTSC-start_t > timeoutMicros*96){
//read failed timeout.
return 0;
}
while(!Serial.available()){
if(TIMERTSC-start_t > timeoutMicros*96){
//read failed timeout.
return 0;
}
}
unsigned char read = Serial.read();
*(((unsigned char*)buf)+i)=read;
}
//purge buffer
//Serial.flush();
return 1;
}
unsigned char check_byte(unsigned char *buf, unsigned char n_bites){
unsigned sum = 0;
for (unsigned char i=1;i<=n_bites;i++){
sum+= i * buf[i-1];
}
unsigned char ck_bite = sum & 0xFF;
return ck_bite;
}
unsigned char check_sum (unsigned char *buf, unsigned char n_bites) {//Consider the last byte in the buffer to be the check byte.
return check_byte_is(buf,n_bites) == check_byte_shouldbe(buf,n_bites);
}
unsigned char check_byte_is(unsigned char *buf, unsigned char n_bites) {//Consider the last byte in the buffer to be the check byte.
return buf[n_bites-1];
}
unsigned char check_byte_shouldbe(unsigned char *buf, unsigned char n_bites) {//Consider the last byte in the buffer to be the check byte.
return check_byte(buf, n_bites-1);
}
inline int prescalerToRegValue(uint16_t psc){
if(psc ==1){
return 0;
}else if(psc==2){
return 1;
}else if(psc==4){
return 2;
}else if(psc==8){
return 3;
}else if(psc==16){
return 4;
}else if(psc==64){
return 5;
}else if(psc==256){
return 6;
}else if(psc==1024){
return 7;
}else{
return 0;
}
}
inline uint16_t regValueToPrescaler(int psc){
if(psc ==0){
return 1;
}else if(psc==1){
return 2;
}else if(psc==2){
return 4;
}else if(psc==3){
return 8;
}else if(psc==4){
return 16;
}else if(psc==5){
return 64;
}else if(psc==6){
return 256;
}else if(psc==7){
return 1024;
}else{
return 0;
}
}
inline void setPrescaler(volatile unsigned int * tctl, uint16_t psc){
int regvalue = prescalerToRegValue(psc);
int old = *tctl;
old &= ~ (7*_BV(TCTLCP0));
old |= regvalue*_BV(TCTLCP0);
*tctl = old;
}
inline uint16_t getPrescaler(volatile unsigned int * tctl){
int val = *tctl;
val &= (7*_BV(TCTLCP0));
val /= _BV(TCTLCP0);
return regValueToPrescaler(val);
}
inline void setTimerSyncImmediately(volatile unsigned int * tctl,int on){
int old = *tctl;
if(on){
old &= ~ TCTL_UPDATE_ZERO_SYNC;
}else{
old |= TCTL_UPDATE_ZERO_SYNC;
}
*tctl = old;
}
inline uint16_t calcPrescaler(double period){
// If[time < 1/1100, 0, Clip[Floor[72000000 time/(2^16)], {0, (2^16) - 1}]]
int ideal= 1+(int)(min(96*period/(65536.0),65534.0));
//1
//2
//4
//8
//16
//64
//256
//1024
if(ideal<3){
}else if(ideal==3){
ideal=4;
}else if(ideal >4 && ideal <=8){
ideal=8;
}else if(ideal >8 && ideal <= 16){
ideal=16;
}else if(ideal >16 && ideal <= 64){
ideal=64;
}else if(ideal >64 && ideal <= 256){
ideal=256;
}else if(ideal >256){
ideal=1024;
}
return ideal;
}
inline uint16_t calcDivGivenClk(double period, double clk){
//findBestDiv[desired_, clk_, range_] := Clip[Round[desired clk], {1, (2^16) - 1}];
return round(min(max(period * clk,1.0),65535.0));
}
inline uint16_t calcDivGivenPsc (double period, uint16_t psc){
// bestWithPrescaler[desired_, psc_] := Module[{clk = 72000000},
// findBestDiv[desired, clk/(psc + 1), 1]
return calcDivGivenClk(period,96.0/psc);
}
inline double periodGivenPscDiv(int psc, int div){
return psc*div/96.0;
}
inline struct frameCommand getNextPosition(){
if(curfreq==100 && freqdir==1){freqdir = (-1);}
if(curfreq==0 && freqdir==-1){freqdir= 1;}
curfreq+=freqdir*5;
desired+=(curfreq*50 -2500);
struct frameCommand cmd;
cmd.desiredPos[0]=desired;
return cmd;
}
unsigned timeToWaitBeforeResendingMicros = 2000*1000;
unsigned timeToShutUpForMicros = 2000*1000;
volatile unsigned lastFrameStartedAt=0;
unsigned waitingSince=0;
unsigned timeShutUp=0;
unsigned nextFrameIdToRecieve=0;
unsigned lastFrameIdProcessed=0;
int waiting=0;
int connected=0;
inline void setStepperMoving(int stepper,int onoff){
if(onoff){
*steppers[stepper].maxovershoot=maxOvershoot[stepper];
digitalWrite(steppers[stepper].sleeppin,0);
}else{
*steppers[stepper].maxovershoot=0;
digitalWrite(steppers[stepper].sleeppin,1);
}
}
void _zpu_interrupt(){
if(TMR1CTL & _BV(TCTLIF)){
idum = 1664525L*idum + 1013904223L;
unsigned frequency = idum >> 24;
double freq = idum >>26;
if(!wb_is_empty(&wingBuf1)){
struct frameCommand cmd = wb_remove(&wingBuf1);
lastFrameIdProcessed++;
for(int i =0;i<3;i++){
int desired = cmd.desiredPos[i];
int current = *steppers[i].steps;
int needed =current - desired;
needed=abs(needed);
freq = curfreq*500;
double perd = 1000000.0/freq;
if(needed){
setStepperMoving(i,1);
perd = microsPerFrameFudged/needed;
//perd /=2;
//perd *= fudgeFactor;
uint16_t psc = calcPrescaler(perd);
unsigned cmp = calcDivGivenPsc(perd,psc);
//if(cmp != lastCmp){
*steppers[i].cmp = cmp;
*steppers[i].pwmh = cmp/2;
lastCmp=cmp;
//}
if(psc != stepvars[i].lastPsc){
setPrescaler(steppers[i].ctl,psc);
stepvars[i].lastPsc=psc;
}
}else{
//no movement needed on this axis
setStepperMoving(i,0);
}
*steppers[i].desired=desired;
/*
Serial.print(desired);
Serial.print(" ");
Serial.print(needed);
Serial.print(" ");
Serial.print(lastPsc);
Serial.print(" ");
Serial.print(lastCmp);
Serial.print(" ");
Serial.println(current);
*/
}
}else{
//buffer empty
for(int i =0;i<3;i++){
setStepperMoving(i,0);
}
}
TMR1CTL &= ~_BV(TCTLIF);
}
}
inline int from_bits(int val, int bits){
int x=1;
x<<=(bits);
x = val - (x/2) + 1;
return x;
}
inline int read_bit_from_byte(unsigned char * bytes, int bit){
int bite=bit/8;
bit = bit % 8;
bit = 1<<(7-bit);
bite = bytes[bite];
bit = bite & bit;
if(bit){return 1 ;}
return 0;
}
inline int read_num_from_bytes(unsigned char * bytes, int index,int bits){
int num=0;
//for my $bit (1 .. $bits){
for(int bit=1;bit<=bits;bit++){
num |= read_bit_from_byte(bytes,index+bit-1)<<(bits-bit);
}
return num;
}
inline struct frameCommand add_frames(struct frameCommand f1, struct frameCommand f2){
struct frameCommand cmd;
for(int i =0;i<3;i++){
cmd.desiredPos[i]=f1.desiredPos[i]+f2.desiredPos[i];
}
return cmd;
}
const int nMaxIntFrames=8;
struct frameCommand previous_frames[nMaxIntFrames];
struct frameCommand startingPosition;
struct frameCommand acc_frame(struct frameCommand new_frame, int level){
previous_frames[0]=new_frame;
for(int i=1;i<=level;i++){
previous_frames[i]=add_frames(previous_frames[i-1],previous_frames[i]);
}
return add_frames(previous_frames[level],startingPosition);
}
void reset_integrator(){
for(int i=0;i<nMaxIntFrames;i++){
struct frameCommand empty;
empty.desiredPos[0]=0;
empty.desiredPos[1]=0;
empty.desiredPos[2]=0;
previous_frames[i]=empty;
}
}
void setStepperPositions(int * positions){
setSteppersEnabled(0);
struct frameCommand pretendFrame;
for(int i=0;i<3;i++){
*steppers[i].desired=positions[i];
*steppers[i].steps=positions[i];
pretendFrame.desiredPos[i]=positions[i];
}
setSteppersEnabled(1);
startingPosition = pretendFrame;
}
void sendStepperPositions(){
uint8_t output_buf[63];
uint8_t * buf_ptr= output_buf;
for(int i=0;i<3;i++){
store_u32(buf_ptr ,*steppers[i].desired);buf_ptr+=4;
}
send_message(4,output_buf,20); //4=readout positions
}
uint8_t msgid=0;
void send_message(uint8_t ctlCode, const uint8_t * data, int nBytes){
if(!waiting){
uint8_t output_buf [63];
uint8_t * buf_ptr= output_buf;
*buf_ptr = ctlCode;buf_ptr++;
*buf_ptr = msgid;buf_ptr++;msgid++;
int i=0;
for(;i<nBytes;i++){
*buf_ptr = data[i];buf_ptr++;
}
for(;i<=61;i++){
*buf_ptr = ' ';buf_ptr++;
}
output_buf[62]=check_byte((uint8_t*)output_buf,62);
int human=0;
if(human){
for(int j=0;j<=62;j++){
if(output_buf[j]<100)
Serial.print(' ');
if(output_buf[j]<10)
Serial.print(' ');
Serial.print(output_buf[j]);
Serial.print(' ');
}
Serial.print('\n');
}else{
Serial.write(output_buf,63);
}
waiting=1;
waitingSince=TIMERTSC;
}
}
void send_debug(const char* msg){
int len=0;
for(int i=0;i<62;i++){
if(msg[i]!=0){
len=i;
}else{
break;
}
}
send_message(3,(const uint8_t*)msg,len+1);
}
int iWasToldToShutUp=0;
struct frameCommand lastInsertedFrameCopy;
void loop() {
if( Serial.available()){
static unsigned char cmd_buf [255];
unsigned char * cmd_idx = cmd_buf;
if(readStringWithTimeout(cmd_buf,255,30*1000)){
//Serial.println(" good read");
waiting=0;
iWasToldToShutUp=0;
if(check_sum((unsigned char*)cmd_buf,255)){
//Serial.println("checksum passed");
unsigned char controlCode=*(unsigned char *) cmd_idx;
cmd_idx++;
switch(controlCode){
case 0: connected=0;break;//Got Nothing
case 1: //Connect Signal
connected=1;
send_debug("penetrated");
break;
case 2: //Reset Yourself
{
iWasToldToShutUp=0;
wb_reset(&wingBuf1);//Empty buffer
nextFrameIdToRecieve=0;
lastFrameIdProcessed=0;
reset_integrator();
//Dont set position to 0
//int positions[3]={0,0,0};
//setStepperPositions(positions);
//But do read out the current position.
sendStepperPositions();
}
break;
case 3: //Feed frames
{
int int_sent = read_u32( cmd_idx);cmd_idx += 4;
unsigned framesStartingFrom = read_u32( cmd_idx);cmd_idx += 4;
if(framesStartingFrom != nextFrameIdToRecieve){
//host sent us the wrong data or something
/*Serial.println("wrong data");*/
goto endcase;
}
int axisSizes[3];
for(int i =0;i<3;i++){
axisSizes[i]= read_num_from_bytes(cmd_idx,i*5,5);
}
cmd_idx += 2;
int bit_ptr=0;
for(int i=0;i<int_sent;i++){
if(!wb_is_full(&wingBuf1)){
struct frameCommand cmd;
/*
uint32_t * b = (uint32_t *) &cmd;
for(int j=0;j<sizeof(struct frameCommand);j+=4){
*b=read_u32(cmd_idx+j);
b++;
}
*/
//unsigned pos = read_u32(cmd_idx);
for(int j =0;j<3;j++){
//cmd.desiredPos[j]=pos/(j+1);
int length=axisSizes[j];
int data = read_num_from_bytes(cmd_idx,bit_ptr,length);
bit_ptr+=length;
data = from_bits(data,length);
cmd.desiredPos[j]=data;
}
cmd = acc_frame(cmd,3);
wb_insert(&wingBuf1, cmd);
lastInsertedFrameCopy=cmd;
nextFrameIdToRecieve++;
}else{
/*Serial.println("buffer full");*/
goto endcase;
}
//cmd_idx+=sizeof(struct frameCommand);
//cmd_idx += 4;
}
}
endcase:0;
break;
case 4: //Set Frame Rate, Fudge Factor
{
int new_rate = read_u32( cmd_idx);
cmd_idx+=4;
fudgeFactor = (double)read_u32( cmd_idx)/1000000.0;
cmd_idx+=4;
wb_reset(&wingBuf1);//Empty buffer
setFrameRate(new_rate);
}
break;
case 5: //Purge Buffer. (stop executing frames.)
{
wb_reset(&wingBuf1);//Empty buffer
}
break;
case 6: //Acknowledge.
break;
case 7: //I don't have any data for you, stop asking.
{
iWasToldToShutUp=1;
timeShutUp=TIMERTSC;
}
break;
case 8: //Define where you are currently at as an XYZ coordinate.
{
int positions[3];
for(int i=0;i<3;i++){
positions[i] =read_u32(cmd_idx);cmd_idx+=4;
}
setStepperPositions(positions);
}
break;
case 9: //sendStepperPositions
{
sendStepperPositions();
}break;
default:/*Serial.print("ControlCode");Serial.println(controlCode);*/ break;
}
}else{
send_debug((char *)cmd_buf);
//send_debug("checksum fail");
}
}else{
//send_debug("failed read");
}
}
if(!waiting){
checkSwitches();
}
if(!waiting && (wb_room_left(&wingBuf1) > 200) && !iWasToldToShutUp){
uint8_t output_buf[63];
uint8_t * buf_ptr= output_buf;
store_u32(buf_ptr ,nextFrameIdToRecieve);buf_ptr+=4;
store_u32(buf_ptr, lastFrameIdProcessed);buf_ptr+=4;
store_u32(buf_ptr, TMR0QUAD);buf_ptr+=4;
*buf_ptr=111;buf_ptr++;
*buf_ptr=digitalReadBool(WING_A_7);buf_ptr++;
*buf_ptr=digitalReadBool(WING_A_8);buf_ptr++;
send_message(1,output_buf,20);
}
if(waiting && (TIMERTSC-waitingSince) > (timeToWaitBeforeResendingMicros*96)){
waiting=0;
}
if(iWasToldToShutUp && (TIMERTSC-timeShutUp) > (timeToShutUpForMicros*96) ){
iWasToldToShutUp=0;//Decide that you have shut up for long enough. Time to beg again.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment