I found some old, still working 3½ floppy drives using the 34-pin IDC interface, that will take a 1.44 MB disk. I had a project in mind, using these floppy disk as an "access key" for a door. In order to do this in a simple manner, my thoughts were to write a sequence of 1's and 0's on specific tracks. This sequence will eventually make up a "lock code".
I am using an Arduino Duemilanove clocked at 16 MHz. I managed to get everything working, except for the reading/writing. I know that the clock speed is too low in order to read/write anything from the actual track themselves, so I started to read about MFM encoding with the hope that instead of writing data to the floppy as it was intended (keeping the clock synced with the spinning drive, caring about sectors and data layout,etc), i could simply write 0's to one track, 1's to the next, and so on.
My issue is that I do not fully understand how MFM works in order to achieve this, so now my goal is figuring out a way of writing 0's and 1's to the tracks.
The tracks would look (in theory) like this:
- Track 0: 00000...
- Track 1: 11111...
- Track 2: 11111...
- Track 3: 00000...
If this is not possible (because of the way writing works), another possibility would be writing data to the tracks in such a manner that reading it back would return a 30% count of 1's, 70% count of 0's, so by considering the number of 0's is higher, that track would be considered as being full of 0's.
As far as I know, this is just a matter of switching the data pin to HIGH and then to LOW in a specified sequenced, delayed by a number of microseconds. Yet, I cannot figure these out on my own.
This is my current code (minus the commented out section, original on here):
int motorPin = 2;
int directionPin = 4;
int stepPin = 5;
int trackZeroPin = 8;
int indexPin = 1;
int driveSelPin = 3;
int writeDataPin = 6;
int writeEnablePin = 7;
int writeProtectPin = 9;
int headSelectPin = 11;
int readDataPin = 10;
int diskReadyPin = 12;
////////////////////////
int currentTrack = 0;
int trackContor = 0;
int tmpVec[500];
int vecCont = 0;
int onThisTrack = 0;
int zeros = 0;
int ones = 0;
int onesArray[30];
int zerosArray[30];
////////////////////////
void setup()
{
pinMode(motorPin,OUTPUT);
pinMode(directionPin,OUTPUT);
pinMode(stepPin,OUTPUT);
pinMode(driveSelPin,OUTPUT);
pinMode(writeEnablePin,OUTPUT);
pinMode(writeDataPin,OUTPUT);
pinMode(trackZeroPin,INPUT_PULLUP);
pinMode(indexPin,INPUT_PULLUP);
pinMode(readDataPin,INPUT_PULLUP);
pinMode(writeProtectPin,INPUT_PULLUP);
pinMode(diskReadyPin,INPUT_PULLUP);
Serial.begin(9600);
driveEnable();
motorDisable();
jiggle();
jumpOutermost();
motorEnable();
execute();
writeDisable();
}
int data = 1;
void loop()
{
Serial.print(readDataRaw());
}
void execute()
{
}
////////////////////////////////////////////////
int jumpToTrack(int track)
{
if (track<84)
{
if (track>currentTrack)
{
int steps = track-currentTrack;
for (int i=1;i<=steps;i++)
{
stepIn();
}
}
else if (track<currentTrack)
{
int steps = currentTrack-track;
for (int i=1;i<=steps;i++)
{
stepOut();
}
}
}
}
int stepOut()
{
digitalWrite(directionPin,HIGH);
digitalWrite(stepPin,LOW);
delayMicroseconds(1);
digitalWrite(stepPin,HIGH);
delayMicroseconds(3000);
currentTrack-=1;
}
int stepIn()
{
digitalWrite(directionPin,LOW);
digitalWrite(stepPin,LOW);
delayMicroseconds(1);
digitalWrite(stepPin,HIGH);
delayMicroseconds(3000);
currentTrack+=1;
}
int readTrackZero()
{
return digitalRead(trackZeroPin);
}
int readIndex()
{
return digitalRead(indexPin);
}
int readDataRaw()
{
return digitalRead(readDataPin);
}
int lastData = LOW;
int readData()
{
int curData = readDataRaw();
if (curData == LOW && lastData == HIGH)
{
lastData = curData;
return 1;
}
else
{
lastData = curData;
return 0;
}
}
int readDiskReady()
{
return digitalRead(diskReadyPin);
}
int motorEnable()
{
digitalWrite(motorPin,LOW);
}
int motorDisable()
{
digitalWrite(motorPin,HIGH);
}
int jumpOutermost()
{
while (readTrackZero()==HIGH)
{
stepOut();
}
}
int jiggle()
{
stepIn();
stepOut();
}
int driveEnable()
{
digitalWrite(driveSelPin,LOW);
}
int driveDisable()
{
digitalWrite(driveSelPin,HIGH);
}
int lastIndex = LOW;
int hasIndexPulsed()
{
int curIndex = readIndex();
if (curIndex == LOW && lastIndex == HIGH)
{
lastIndex = curIndex;
return 1;
}
else
{
lastIndex = curIndex;
return 0;
}
}
int isWriteProtected()
{
if (digitalRead(writeProtectPin)==LOW)
{
return 1;
}
else
{
return 0;
}
}
int writeEnable()
{
digitalWrite(writeEnablePin,HIGH);
}
int writeDisable()
{
digitalWrite(writeEnablePin,LOW);
}
int setWriteData(int data)
{
digitalWrite(writeDataPin,data);
}
UPDATE I finally managed to get it done using an ATMEGA328. Here is the full code, if anyone is interested:
#define portOfPin(P)\
(((P)>=0&&(P)<8)?&PORTD:(((P)>7&&(P)<14)?&PORTB:&PORTC))
#define ddrOfPin(P)\
(((P)>=0&&(P)<8)?&DDRD:(((P)>7&&(P)<14)?&DDRB:&DDRC))
#define pinOfPin(P)\
(((P)>=0&&(P)<8)?&PIND:(((P)>7&&(P)<14)?&PINB:&PINC))
#define pinIndex(P)((uint8_t)(P>13?P-14:P&7))
#define pinMask(P)((uint8_t)(1<<pinIndex(P)))
#define pinAsInput(P) *(ddrOfPin(P))&=~pinMask(P)
#define pinAsInputPullUp(P) *(ddrOfPin(P))&=~pinMask(P);digitalHigh(P)
#define pinAsOutput(P) *(ddrOfPin(P))|=pinMask(P)
#define digitalLow(P) *(portOfPin(P))&=~pinMask(P)
#define digitalHigh(P) *(portOfPin(P))|=pinMask(P)
#define isHigh(P)((*(pinOfPin(P))& pinMask(P))>0)
#define isLow(P)((*(pinOfPin(P))& pinMask(P))==0)
#define digitalState(P)((uint8_t)isHigh(P))
#include <EEPROM.h>
int motorPin = 10;
int directionPin = 11;
int stepPin = 12;
int trackZeroPin = A1;
int indexPin = 8;
int driveSelPin = 9;
int writeDataPin = 13;
int writeEnablePin = A0;
int writeProtectPin = A2;
int headSelectPin = A4;
int readDataPin = A3;
int diskReadyPin = A5;
int redLedPin = 7;
int greenLedPin = 4;
int mot1Pin = 2; //2 high - 3 low = closed;
int mot2Pin = 3; //2 low - 3 high = open;
int redLedButton = 5;
int greenLedButton = 6;
////////////////////////
int currentTrack = 0;
int trackContor = 0;
int arrayTest[100];
bool locked=true;
bool pwCorrect = false;
int codeLength = 1;
////////////////////////
void setup()
{
pinAsOutput(motorPin);
pinAsOutput(directionPin);
pinAsOutput(stepPin);
pinAsOutput(driveSelPin);
pinAsOutput(writeEnablePin);
pinAsOutput(writeDataPin);
pinAsOutput(headSelectPin);
pinAsInputPullUp(trackZeroPin);
pinAsInputPullUp(indexPin);
pinAsInputPullUp(readDataPin);
pinAsInputPullUp(writeProtectPin);
pinAsInputPullUp(diskReadyPin);
pinAsOutput(mot1Pin);
pinAsOutput(mot2Pin);
pinAsOutput(redLedPin);
pinAsOutput(greenLedPin);
pinAsInput(redLedButton);
pinAsInput(greenLedButton);
///////INITIALIZATION/////////
doorClose();
for (int i=1;i<=5;i++)
{
digitalHigh(redLedPin);
digitalLow(greenLedPin);
delay(50);
digitalLow(redLedPin);
digitalHigh(greenLedPin);
delay(50);
}
digitalLow(redLedPin);
digitalLow(greenLedPin);
driveEnable();
motorDisable();
writeDisable();
motorDisable();
floppyInit();
driveDisable();
///////INITIALIZATION END/////////
Serial.begin(9600);
}
void loop()
{
if (isGreenButtonPressed() && !isRedButtonPressed())
{
blinkLed(2,100,greenLedPin);
codeLength=1;
for (int i=1;i<=4;i++)
{
blinkLed(1,500,greenLedPin);
if (isGreenButtonPressed())
{
blinkLed(i,500,redLedPin);
codeLength=i;
}
else
{
break;
}
}
if (pwCorrect==false)
{
driveEnable();
if (isDiskReady())
{
digitalHigh(greenLedPin);
String num = readPassCode();
digitalLow(greenLedPin);
Serial.println(readCodeFromEEPROM());
Serial.println(num);
if (num.equals(readCodeFromEEPROM()) || num.equals("help"))
{
locked = false;
doorOpen();
pwCorrect = true;
digitalHigh(greenLedPin);
delay(2000);
digitalLow(greenLedPin);
}
else
{
locked = true;
doorClose();
pwCorrect = false;
digitalHigh(redLedPin);
delay(2000);
digitalLow(redLedPin);
}
}
else
{
blinkLed(5,100,redLedPin);
}
driveDisable();
}
else
{
blinkLed(5,100,redLedPin);
}
}
else if (isRedButtonPressed() && !isGreenButtonPressed()) // and if unlocked
{
blinkLed(2,100,redLedPin);
delay(1000);
if (isRedButtonPressed())//daca e apasat dupa 1 s
{
codeLength=1;
for (int i=1;i<=4;i++)
{
blinkLed(1,500,redLedPin);
if (isRedButtonPressed())
{
blinkLed(i,500,greenLedPin);
codeLength=i;
}
else
{
break;
}
}
if (pwCorrect == true)
{
driveEnable();
if (isDiskReady())
{
if (isWriteProtected())
{
blinkLed(5,100,redLedPin);
}
else
{
doorClose();
String num = getRandomString();
digitalHigh(redLedPin);
writePassCode(num);
digitalLow(redLedPin);
locked = true;
writeCodeToEEPROM(num);
pwCorrect = false;
}
}
else
{
blinkLed(5,100,redLedPin);
}
driveDisable();
}
else
{
blinkLed(5,100,greenLedPin);
}
}
else
{
if (pwCorrect)
{
if (locked)
{
locked = !locked;
doorOpen();
digitalHigh(greenLedPin);
delay(500);
digitalLow(greenLedPin);
}
else
{
locked = !locked;
doorClose();
digitalHigh(redLedPin);
delay(500);
digitalLow(redLedPin);
}
}
else
{
blinkLed(2,100,redLedPin);
blinkLed(2,100,greenLedPin);
}
}
}
}
void blinkLed(int times,int del,int led)
{
for (int i=1;i<=times;i++)
{
digitalHigh(led);
delay(del);
digitalLow(led);
delay(del);
}
}
//////////////////
String getRandomString()
{
String toReturn = "";
randomSeed(millis());
for (int i=1;i<=codeLength;i++)
{
toReturn += (char)random(65,90+1);
}
return toReturn;
}
//////////////////
boolean validateCode(String s)
{
if (s.length()>codeLength)
{
return false;
}
for (int i=0;i<s.length();i++)
{
if ((int)s.charAt(i)<=128 && (int)s.charAt(i)>=10)
{
;
}
else
{
return false;
}
}
return true;
}
void writePassCode(String s)
{
motorDisable();
jiggle();
jumpOutermost();
motorEnable();
writeDisable();
delay(500);
int destTrack=0;
setHead(0);
if (!validateCode(s))
{
Serial.println("INVALID CODE!!");
}
else
{
for (int k=0;k<s.length();k++)
{
if (destTrack>79)
{
destTrack = 0;
setHead(1);
}
String toWrite = String((int)s.charAt(k),2);
if (toWrite.length()<8)
{
String dif="";
for (int sp=1;sp<=(8-toWrite.length());sp++)
{
dif+="0";
}
toWrite = dif + toWrite;
}
for (int j=0;j<toWrite.length();j++)
{
int toWriteVal = toWrite.charAt(j)=='1'?HIGH:LOW;
Serial.println(toWriteVal);
for (int i=1;i<=3;i++)
{
jumpToTrack(destTrack);
digitalHigh(greenLedPin);
delay(20);
digitalLow(greenLedPin);
delay(20);
writeTrack(toWriteVal);
destTrack++;
}
destTrack++;
destTrack++;
}
}
motorDisable();
jumpOutermost();
}
}
String readPassCode()
{
motorDisable();
jumpOutermost();
motorEnable();
writeDisable();
delay(1000);
int destTrack = 0;
setHead(0);
unsigned long macs = 0;
unsigned long minn = 4294967294;
unsigned long matrix[32+1];
for (int i=0;i<codeLength*8;i++)
{
Serial.println(i);
if (destTrack>79)
{
destTrack = 0;
setHead(1);
}
unsigned long total = 0;
for (int j=1;j<=3;j++)
{
jumpToTrack(destTrack);
digitalHigh(redLedPin);
delay(20);
digitalLow(redLedPin);
delay(20);
unsigned long trck = readTrack();
total+=trck;
destTrack++;
}
unsigned long med = total/3;
matrix[i] = med;
if (med>macs)
{
macs = med;
}
if (med < minn)
{
minn = med;
}
destTrack++;
destTrack++;
}
String pass = "";
for (int j=0;j<codeLength;j++)
{
float result = 0.5;
for (int i=0;i<8;i++)
{
long abs1 = matrix[8*j+i] - minn;
long abs2 = matrix[8*j+i] - macs;
if (abs(abs1)<abs(abs2))
{
result=result+(pow(2,(8-i-1))*0);
//0
}
else
{
result=result+(pow(2,(8-i-1))*1);
}
}
pass+=char(int(result));
}
motorDisable();
jumpOutermost();
return pass;
}
/////////////////////////////////////////
void writeTrack(int val)
{
delay(50);
unsigned long currentMillis = millis();
int lastDataBit = 0;
//int count = 1;
writeEnable();
while(millis()-currentMillis<=500)//1.82 uS
{
setWriteData(val);
delayMicroseconds(4);
setWriteData(0);
delayMicroseconds(2);
}
writeDisable();
delay(50);
}
unsigned long readTrack()
{
delay(50);
unsigned long ones = 0;
unsigned long currentMillis = millis();
int lastState = 0;
while(millis()-currentMillis<=500)//1.82 uS
{
if (digitalState(readDataPin)!=lastState)
{
lastState = !lastState;
ones++;
}
}
delay(50);
return ones;
}
int jumpToTrack(int track)
{
if (track<84)
{
if (track>currentTrack)
{
int steps = track-currentTrack;
for (int i=1;i<=steps;i++)
{
stepIn();
}
}
else if (track<currentTrack)
{
int steps = currentTrack-track;
for (int i=1;i<=steps;i++)
{
stepOut();
}
}
}
}
int stepOut()
{
digitalHigh(directionPin);
delay(10);
digitalLow(stepPin);
delay(10);
digitalHigh(stepPin);
delay(20);
currentTrack-=1;
}
int stepIn()
{
digitalLow(directionPin);
delay(10);
digitalLow(stepPin);
delay(10);
digitalHigh(stepPin);
delay(20);
currentTrack+=1;
}
int readTrackZero()
{
return digitalState(trackZeroPin);
}
int readIndex()
{
return digitalState(indexPin);
}
int readDataRaw()
{
return digitalState(readDataPin);
}
int lastData = LOW;
int readData()
{
int curData = readDataRaw();
if (curData == LOW && lastData == HIGH)
{
lastData = curData;
return 1;
}
else
{
lastData = curData;
return 0;
}
}
int isDiskReady()
{
motorEnable();
writeDisable();
unsigned long mil = millis();
int indexes = 0;
int lastIndex = HIGH; //false
while (millis()-mil<=1000 && indexes != 2)
{
if (readIndex()==LOW && lastIndex!=LOW)
{
lastIndex = LOW;
indexes++;
}
else
{
lastIndex = HIGH;
}
}
motorDisable();
if (indexes==0)
{
return 0;
}
else
{
return 1;
}
}
int motorEnable()
{
digitalLow(motorPin);
}
int motorDisable()
{
digitalHigh(motorPin);
}
int jumpOutermost()
{
while (readTrackZero()==HIGH)
{
stepOut();
}
currentTrack=0;
}
int jiggle()
{
stepIn();
stepOut();
}
int driveEnable()
{
digitalLow(driveSelPin);
}
int driveDisable()
{
digitalHigh(driveSelPin);
}
int lastIndex = LOW;
int hasIndexPulsed()
{
int curIndex = readIndex();
if (curIndex == LOW && lastIndex == HIGH)
{
lastIndex = curIndex;
return 1;
}
else
{
lastIndex = curIndex;
return 0;
}
}
int isWriteProtected()
{
if (digitalState(writeProtectPin)==LOW)
{
return 1;
}
else
{
return 0;
}
}
int writeEnable()
{
digitalLow(writeEnablePin);
}
int writeDisable()
{
digitalHigh(writeEnablePin);
}
int setWriteData(int data)
{
if (data==0)
{
digitalLow(writeDataPin);
}
else
{
digitalHigh(writeDataPin);
}
}
void setHead(int val)
{
if (val==0)
{
digitalLow(headSelectPin);
}
else
{
digitalHigh(headSelectPin);
}
}
bool isRedButtonPressed()
{
return isLow(redLedButton);
}
bool isGreenButtonPressed()
{
return isLow(greenLedButton);
}
void doorOpen()
{
digitalHigh(2);
digitalLow(3);
delay(500);
digitalLow(2);
digitalLow(3);
}
void doorClose()
{
digitalHigh(3);
digitalLow(2);
delay(500);
digitalLow(2);
digitalLow(3);
}
void writeCodeToEEPROM(String code)
{
EEPROM.put(0,(byte)codeLength);
for (int i=1;i<=codeLength;i++)
{
EEPROM.put( i, code.charAt(i-1));
}
}
String readCodeFromEEPROM()
{
byte len;
EEPROM.get(0,len);
if (len!=codeLength)
{
return "";
}
else
{
String toReturn = "";
char ch;
for (int i=1;i<=codeLength;i++)
{
EEPROM.get(i,ch);
toReturn+=ch;
}
return toReturn;
}
}
void floppyInit()
{
jumpOutermost();
digitalLow(directionPin);
for (int i=1;i<=10;i++)
{
digitalLow(stepPin);
delay(20);
digitalHigh(stepPin);
delay(20);
}
delay(100);
for (int i=1;i<=10;i++)
{
digitalLow(stepPin);
delay(10);
digitalHigh(stepPin);
delay(10);
}
delay(100);
for (int i=1;i<=10;i++)
{
digitalLow(stepPin);
delay(5);
digitalHigh(stepPin);
delay(5);
}
delay(500);
digitalHigh(redLedPin);
jumpOutermost();
digitalLow(redLedPin);
}