Skip to content

Instantly share code, notes, and snippets.

@jschoch
Created September 4, 2019 04:26
Show Gist options
  • Save jschoch/d465d0a8737681ebd8cdd4c6a6043667 to your computer and use it in GitHub Desktop.
Save jschoch/d465d0a8737681ebd8cdd4c6a6043667 to your computer and use it in GitHub Desktop.
/*
timetwister.nxc
http://tiltedtwister.com
Hans Andersson 2012
Connections:
A Minute motor
B Ten minute motor
*/
#include "timetwistlib.nxc"
int minuteTurns[][]={
{0,-3,0,0,4,-1}, // 9 -> 0
{5,-7,5,-3,1,0}, // 0 -> 1
{0,-5,0,0,6,-2}, // 1 -> 2
{4,-6,4,-2,0,0}, // 2 -> 3
{5,-7,0,0,3,-2}, // 3 -> 4
{0,-3,8,-6,2,0}, // 4 -> 5
{0,-3,5,-4,2,0}, // 5 -> 6
{5,-7,5,-3,0,0}, // 6 -> 7
{0,-4,7,-5,3,-1}, // 7 -> 8
{0,0,4,-6,3,-1,}}; // 8 -> 9
int tenMinuteTurns[][]={
{-3,4,0,0,-1,0}, // 5 -> 0
{0,5,-7,5,-3,1}, // 0 -> 1
{-5,0,0,6,-2,0}, // 1 -> 2
{0,4,-6,4,-2,0}, // 2 -> 3
{0,5,-7,3,-2,0}, // 3 -> 4
{-3,8,-6,0,0,2}}; // 4 -> 5
int hourTurns[][]={
{0,-3,0,0,4,-1}, // 9 -> 0 and 3 -> 0
{5,-7,5,-3,1,0}, // 0 -> 1 and 2 -> 1
{0,-5,0,0,6,-2}, // 1 -> 2
{4,-6,4,-2,0,0}, // 2 -> 3
{5,-7,0,0,3,-2}, // 3 -> 4
{0,-3,8,-6,2,0}, // 4 -> 5
{0,-3,5,-4,2,0}, // 5 -> 6
{5,-7,5,-3,0,0}, // 6 -> 7
{0,-4,7,-5,3,-1}, // 7 -> 8
{0,0,4,-6,3,-1,}}; // 8 -> 9
int tenHourTurns[][]={
{0,3,-6,4,-1,0}, // 2 -> 0
{0,5,-7,5,-3,1}, // 0 -> 1
{-5,0,0,6,-2,0}, // 1 -> 2
{-5,7,-6,4,-1,0}}; // 1 -> 0
int L[]={0,0,-5,4,-2,0}; // 1 -> L
int E[]={0,-4,6,-4,2,0}; // 0 -> E
int G[]={0,2,-4,2,0,0}; // 0 -> G
int O[]={8,-7,4,-1,0,0}; // 0 -> O
int minute=0;
int hour=0;
bool amPm;
void RemoteTwistDigits(int aTurns, int bTurns)
{
SendRemoteNumber(1,MAILBOX1,aTurns)
Wait(100);
SendRemoteNumber(1,MAILBOX1,bTurns)
Wait(100);
}
void RemoteGetAck()
{
string text;
while(ReceiveMessage(MAILBOX2, true, text) !=NO_ERR);
}
void ShowTime()
{
NumOut(30,LCD_LINE4,hour/10);
NumOut(38,LCD_LINE4,hour%10);
TextOut(47,LCD_LINE4,":");
NumOut(55,LCD_LINE4,minute/10);
NumOut(63,LCD_LINE4,minute%10);
}
task Time()
{
int hourIndex,tenHourIndex;
unsigned long tick=CurrentTick();
ResetAllTachoCounts(OUT_AB);
while(true)
{
tick+=MIN_1;
while (CurrentTick()<tick) //wait a minute
Wait(SEC_1);
// if(hour==10 && minute==0)
// break;
minute=(++minute)%60;
if(!minute)
{
hour++;
if(amPm)
{
if(hour==10)
tenHourIndex=1;
else if(hour>12)
{
hour=1;
tenHourIndex=3;
}
else
tenHourIndex=-1;
hourIndex=hour%10;
}
else
{
hour=hour%24;
if(hour==0)
hourIndex=0;
else
hourIndex=hour%10;
if(hour%10 == 0)
tenHourIndex=hour/10;
else
tenHourIndex=-1;
}
}
ShowTime();
for(int level = 0; level < 6;level++)
{
if(!minute)
RemoteTwistDigits(hourTurns[hourIndex][level],tenHourIndex < 0 ? 0 : tenHourTurns[tenHourIndex][level]);
TwistDigits(minuteTurns[minute%10][level],minute%10 > 0 ? 0 : tenMinuteTurns[minute/10][level]);
if(!minute)
RemoteGetAck();
}
Wait(1000);
Coast(OUT_AB);
}
for(int level = 0; level < 6;level++)
{
RemoteTwistDigits(E[level],L[level]);
TwistDigits(O[level],G[level]);
}
Wait(1000);
Coast(OUT_AB);
}
void SetTime()
{
int handle;
int dummy;
TextOut(10,LCD_LINE3,"Select 12/24");
TextOut(10,LCD_LINE4,"hour display");
TextOut(5,LCD_LINE8,"12");
TextOut(80,LCD_LINE8,"24");
while(true)
{
if(ButtonPressed(BTNLEFT,false))
{
amPm=true;
break;
}
if(ButtonPressed(BTNRIGHT,false))
{
amPm=false;
break;
}
}
PlayFile("! Click.rso");
TextOut(2,LCD_LINE1,"Set time using",DRAW_OPT_CLEAR_WHOLE_SCREEN);
TextOut(2,LCD_LINE2,"arrow buttons");
TextOut(2,LCD_LINE7,"Press center btn");
TextOut(2,LCD_LINE8,"to start clock");
Wait(1000);
if(OpenFileRead("timetwister.dat",dummy,handle)==0)
{
Read(handle,hour);
Read(handle,minute);
CloseFile(handle);
}
ShowTime();
while(!ButtonPressed(BTNCENTER, false))
{
int delay=400;
while(ButtonPressed(BTNRIGHT, false))
{
PlayFile("! Click.rso");
Wait(delay);
minute=(++minute)%60;
ShowTime();
delay=100;
}
while(ButtonPressed(BTNLEFT, false))
{
PlayFile("! Click.rso");
Wait(delay);
if(amPm)
{
if(++hour>12)
hour=1;
}
else
hour=(++hour)%24;
ShowTime();
delay=100;
}
}
PlayFile("! Click.rso");
ClearScreen();
ShowTime();
DeleteFile("timetwister.dat")
CreateFile("timetwister.dat",4,handle);
Write(handle,hour);
Write(handle,minute);
CloseFile(handle);
}
task main()
{
SetSleepTime(0); //Disable automatic shutdown
if(BluetoothStatus(1)!=NO_ERR)
{
TextOut(5,LCD_LINE4,"Bluetooth error");
while(true);
}
SetTime();
RemoteStartProgram(1, "timeslave.rxe")
Wait(2000);
StartTask(Time);
}
#define QUARTERTURN 90*3 //3=gear ratio
#define LOWSPEED 20
#define HIGHSPEED 80
#define MEDIUMSPEED 40
#define RAMPDOWN 270
#define SLOW 50
int motor1, motor2;
int aRotationCount,bRotationCount;
int direction1,direction2;
int speed1,speed2;
int goal1,goal2;
int rampdown1goal,rampdown2goal;
mutex motorMutex;
task Motor2()
{
bool rampdownStarted=false;
Acquire(motorMutex);
OnFwd(motor2,speed2*direction2);
Yield();
while((direction2 > 0 && MotorRotationCount(motor2) < goal2) || (direction2 < 0 && MotorRotationCount(motor2) > goal2))
{
if(!rampdownStarted && ((direction2 > 0 && MotorRotationCount(motor2)>rampdown2goal)) ||(direction2 < 0 && MotorRotationCount(motor2)<rampdown2goal))
{
rampdownStarted=true;
SetOutput(motor2,RunState,OUT_RUNSTATE_RAMPDOWN,Power,LOWSPEED*direction2,TachoLimit,RAMPDOWN,UpdateFlags,UF_UPDATE_SPEED+UF_UPDATE_TACHO_LIMIT);
Yield();
}
else if(MotorRunState(motor2)==OUT_RUNSTATE_IDLE)
OnFwd(motor2,LOWSPEED*direction2);
}
Off(motor2);
Release(motorMutex);
}
void TwistDigits(int aTurns, int bTurns)
{
int startMotor2;
if(aTurns==0 && bTurns==0)
return;
if(abs(aTurns) < abs(bTurns))
{
motor1 = OUT_B;
motor2 = OUT_A;
direction1 = bTurns > 0 ? 1 : -1;
direction2 = -1 * direction1;
goal1 = bRotationCount + bTurns * QUARTERTURN;
goal2 = aRotationCount + aTurns * QUARTERTURN;
rampdown1goal = goal1 - (RAMPDOWN+SLOW) * direction1;
rampdown2goal = goal2 - (RAMPDOWN+SLOW) * direction2;
startMotor2 = bRotationCount + (QUARTERTURN/2 + abs(aTurns+bTurns)*QUARTERTURN) * direction1;
speed1 = abs(bTurns)==1 ? MEDIUMSPEED : HIGHSPEED;
speed2 = abs(aTurns)==1 ? MEDIUMSPEED : HIGHSPEED;
}
else
{
motor1 = OUT_A;
motor2 = OUT_B;
direction1 = aTurns > 0 ? 1 : -1;
direction2 = -1 * direction1;
goal1 = aRotationCount + aTurns * QUARTERTURN;
goal2 = bRotationCount + bTurns * QUARTERTURN;
rampdown1goal = goal1 - (RAMPDOWN+SLOW) * direction1;
rampdown2goal = goal2 - (RAMPDOWN+SLOW) * direction2;
startMotor2 = aRotationCount + (QUARTERTURN/2 + abs(aTurns+bTurns)*QUARTERTURN) * direction1;
speed1 = abs(aTurns)==1 ? MEDIUMSPEED : HIGHSPEED;
speed2 = abs(bTurns)==1 ? MEDIUMSPEED : HIGHSPEED;
}
bool rampdownStarted = false;
bool motor2Started = false;
OnFwd(motor1,speed1*direction1);
Yield();
while((direction1 > 0 && MotorRotationCount(motor1) < goal1) || (direction1 < 0 && MotorRotationCount(motor1) > goal1))
{
if((aTurns != 0) && (bTurns != 0) && !motor2Started && ((direction1 > 0 && MotorRotationCount(motor1) > startMotor2) ||(direction1 < 0 && MotorRotationCount(motor1) < startMotor2)))
{
motor2Started=true;
start Motor2;
}
if(!rampdownStarted && ((direction1 > 0 && MotorRotationCount(motor1)>rampdown1goal) ||(direction1 < 0 && MotorRotationCount(motor1)<rampdown1goal)))
{
rampdownStarted=true;
SetOutput(motor1,RunState,OUT_RUNSTATE_RAMPDOWN,Power,LOWSPEED*direction1,TachoLimit,RAMPDOWN,UpdateFlags,UF_UPDATE_SPEED+UF_UPDATE_TACHO_LIMIT);
Yield();
}
else if(MotorRunState(motor1)==OUT_RUNSTATE_IDLE)
OnFwd(motor1,LOWSPEED*direction1);
}
Off(motor1);
Acquire(motorMutex);
Release(motorMutex);
Wait(50);
aRotationCount += aTurns * QUARTERTURN;
bRotationCount += bTurns * QUARTERTURN;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment