Coder Social home page Coder Social logo

acemielektron / fddemu Goto Github PK

View Code? Open in Web Editor NEW
139.0 5.0 22.0 38.84 MB

AVR (atmega328p) based floppy drive emulator for PC

Home Page: https://acemielektronikci.blogspot.com/2021/10/fddemu-disket-surucu-emulatoru.html

License: GNU General Public License v3.0

Makefile 1.79% C 63.50% C++ 34.71%
floppy drive emulator arduino atmega328p diy atmega32u4

fddemu's People

Contributors

acemielektron avatar hachi avatar ikonko avatar racesoft avatar skokcam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fddemu's Issues

Can this be adapted to CDROM

Myself and a friend of mine is desperately trying to emulate an iomega zip drive, I stumbled on this project and it made me wonder if it could be a starting point for emulating ide zip drives, any thoughts on the subject?

Portability thoughts? Build instructions?

So, I was hoping to build this - I don't have a 328p handy, maybe a 2560 but was planning trying a 32u4 as that's what I had handy, or maybe a Teensy 4.1 - (onboard sd even) - 2560 would be the most similar to a 328p though

In trying to build it with platformIO, it always complains about u8g.h - even though it's installed and recognized, for some odd reason. For example, when the lib isn't installed, the include for it is underlined squiggly; once it's installed and recognized, this goes away along with some errors but still comes back on build for some reason - I wonder if this is due to other errors.

Anyhow, all the other errors come from specific registers that are used not being found. It looks like these are for UART communication. I haven't dug - is this needed to keep timing up?

Other registers that are used are for pin change interrupts; is there also a reason for using these directly instead of something mroe portable like attachInterrupt?

Again - I haven't dug, so I'm not saying your choices weren't needed; I've built an EEPROM emulator with a teensy before and I only barely hit my target for timing and USB UART broke that (although hardware UART with the arduino lib worked fine without any effects on timing), just curious as I'd like to make use of this project for a project of my own as getting 5.25" floppies isn't the easiest for me.

Support Opus Discovery Disks

I have an Opus Discovery drive.
It has 2 formats:
single sided 40 tracks, 18 sectors, 256 sector size, index 0 (sectors 0-17)
double sided 80 tracks, 18 sectors, 256 sector size, index 0 (sectors 0-17)

The double sided version overlaps size with other 720k disks.
Would it be an option to use the extension (OP1/OP2) to specify disk options?

In FloppyDisk.cpp I expect to add something like:
case (uint16_t) (40118/2): //40 track 1 sided Opus image 180k
numTrack = 40;
numSec = 18;
bitLength = BIT_LENGTH_DD;
flags.seclen = 1; //256b sectors
break;

How can I set the number of heads?
Do you know where the sector number is set?

Modification for 256 bytes sectors

Hi,

Would it be possible to modify the code (primarily avrFlux I assume) to accommodate DD disk format with 40 or 80 tracks 2 sides and 16 sectors 256 bytes in length? More about the format here: https://sinclair.wiki.zxnet.co.uk/wiki/TRD_format

TR-DOS uses 256 BPS and 16 SPT for disks, so a

  • 40 track 1 sided image length is 163840 byte (1×40×16×256)
  • 40 track 2 sided image length is 327680 byte
  • 80 track 1 sided image length is 327680 byte
  • 80 track 2 sided image length is 655360 byte

Due to current code length (~23 out of 32k) this may require a separate branch?

Running on arduino.cc

Hi,

I love this project and it's exactly what I was looking for several days!

I'm a newbie in this kind of thing and I'm trying to compile using Arduino.cc application using these files but I can't.

Can explain in more detail how do I can run it in windows? If is not possible to run on Arduino.cc, where do I can run?

Thank you so much!

Writes to emulated image failing on SM609R (clone of Intel 8272A)

Hello, OK, with RPM on HD floppy is my mistake. Sorry. But when I increased waiting to /WRGATE to 45, program enter at least to "WRITE" function and freeze on reading data from system. I wait for new FW version.
I maked log file with drive B:. When I run any program from drive B:, head position change and stay on last position - in LOG on track 13. After RESET of system I will command DIR B: and in log is visible read from last head position without return to track 0. I tested FDC (second working PCB with connectors for 5 1/4" FDD 360kB - I will add foto to Google gallery). In records from logical analyzer I found diference betwen real FDD and fddEMU - signal TRK00 still active without regardless of the state /DS0. When /DS1 actived, FDC read /TRK00=0 (track 0 is set) and do not move with head (reset internal track position/counter).
In new log is small mistake - instead number sector 1 is write number sector 10. In cycle /WRGATE I thought info about individual called parts - generate sector head, read data from system, write data do SD...
Attachments: EMU_BOOT - boot system with fddEMU, FDD_BOOT - boot systm with real FDDs
Petr

-------- Původní zpráva -------
Od: Acemi Elektronikci @.>
Komu: acemielektron/fddEMU @.
>
Předmět: Re: [acemielektron/fddEMU] Update build-firmware.yml (PR #21)
Datum: 08.05.2022 07:17

|  
| Hello @RaceSoft [https://github.com/RaceSoft], thank you for the fast response.
|
| | Hello, many thanks for update. Booting working correctly, system is OK. But writing data to image still not working When I experimented with Your source program, I magnified time to detect edge of signal /WRGATE to 45 instead 40, but 48 it would be even better. HD floppy have 360 RPM, high density data and waiting 20 cycles. DD floppy have 300 RPM, double density data (half of HD), and shoult therefore wait max 48 cycles ((360/300)_2_20).
| |
| Both 3.5" DD and 3.5" HD floppies are 300rpm. While DD data rate is 250 kbit/second, HD data rate is 500 kbit/second. https://www.cpcwiki.eu/index.php/IBM_System_34_double_density_format [https://www.cpcwiki.eu/index.php/IBM_System_34_double_density_format] explains floppy structure. Track marks and sector headers are written during formatting. When floppy controller needs to read a sector it first puts the head on correct track, it does this by checking track0 signal while moving head outwards. When track0 is triggered it knows it is on track0, then moves head to the required track. Here it starts checking sector headers Sector headers contain track/side/sector/size information. When it finds the correct sector it reads or writes into it. Because a disk can be formatted on one controller and written on a completely different controller, headers and data also contains gaps to protect from accidentally overwriting following data structures. And due to different controllers there can be slight differences in data rates so there is a pre-amble
| before data structures (headers & data), usually 12 bytes of 0 where controller syncs to floppy data rate. While writing to disk after finding correct sector header, controller waits gap2(22 bytes of 0x4E) then starts writing 0s for sync, following, 3 sync bytes, data mark byte 0xFB
| and finally data and crc. Previous code was waiting and checking if WRITE_GATE is asserted after sending the sector header. New code is checking whether WRITE_GATE is asserted during sending these 0s. If controller tries to write a sector it should wait for those 22 gap bytes after sector header, only if controller starts sending its sync 0s early, during these gap bytes fddEMU could miss the sector written, because without enough 0s reading fails (fddEMU expects at least 10 0s). I can either shorten the gap2 to 20 bytes (or even more) -which is easier- or add check for WRITE_GATE during gap2. I will be posting the compiled version shortly.
|
| | Have You added some debug information in /WRGATE cycle?
| |
| Yes now it also writes readable chars in addition to hex values.
|
| | Original problems with drive B: stil persist. This is because the last track used before the system reset remains set - head not move to track 0. But now I do not know, how solve it.
| |
| I don't think it is related to track position. Setting track position to 0 for every access is easy, but that is not how a real floppy drive behaves. As I have explained before it has track0 signal for this. A real floppy drive head would stay put where it is last placed, it's controller's job to place head in correct track.
|
| | I looking into record from logical analyzer and comparing with source code of BIOS CP/M system. BIOS checking whether connected the second floppy by service RECALIBRATE. But now i do not know, how it will show on signals from FDC.When I will understand, I suggest some solution.
| |
| BIOS source code would be helpful for understanding how long it waits after finding the correct sector. It is the floppy controller IC that finds the sector then signals the computer to read or write data. I will be waiting your suggestions.
|
| | Added name of used drive to log is super! Thanks for Your support. Have a nice day.
| |
| Thank you for testing fddEMU. With your help fddEMU would become a better emulator that could be used on more computers.
|
| | P.S.: Now is possible use fliped display ;-) . Many thanks.
| |
| You mean "FLIP=1" Ok, will do so.
| —Reply to this email directly, view it on GitHub [https://github.com//pull/21#issuecomment-1120352342], or unsubscribe [https://github.com/notifications/unsubscribe-auth/AY5AEW5UCI4KPD6T7RNGLA3VI5FAFANCNFSM5UNF5XPQ].You are receiving this because you were mentioned.Message ID: </pull/21/c1120352342
| @github
| .com>
|
|

fddEMU (c) 2021 Acemi Elektronikci

S: Select drive
P: Previous
N: Next
L: Load
E: Eject

FS: ÍÓ>*
s
A: BOOT.IMG C40H2S9
B: No disk
Selected Drive A
s
A: BOOT.IMG C40H2S9
B: No disk
Selected Drive B
l>Loading C2717-09.DCZ
FS: ÍÓ>*
C40H2S9
BUSY
A:R0/0/1
A:R0/1/2
A:R0/1/3
A:R0/1/4
A:R0/1/5
A:R0/1/6
A:R0/1/7
A:R0/1/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
Drive idle
BUSY
A:R0/0/2
A:R0/0/2
A:R2/0/3
A:R5/0/4
A:R4/0/5
A:R2/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/1/2
A:R0/1/3
A:R0/1/4
A:R0/1/5
A:R0/1/6
A:R0/1/7
Drive idle
BUSY
A:R0/1/8
Drive idle
BUSY
A:R1/0/2
A:R1/0/2
A:R1/0/3
A:R1/0/4
A:R1/0/5
Drive idle
BUSY
A:R1/0/6
A:R1/0/2
A:R1/0/3
A:R1/0/4
A:R1/0/5
A:R1/0/6
A:R1/0/7
A:R1/0/8
A:R1/0/9
Drive idle
BUSY
A:R1/0/10
A:R1/0/2
A:R1/0/3
A:R1/0/4
Drive idle
BUSY
B:R1/0/5
Drive idle
BUSY
B:R1/0/2
B:R1/0/2
B:R1/0/3
B:R1/0/4
B:R1/0/5
Drive idle
BUSY
B:R1/0/6
B:R1/0/2
B:R1/0/3
B:R1/0/4
B:R1/0/5
B:R1/0/6
B:R1/0/7
B:R1/0/8
B:R1/0/9
Drive idle
BUSY
B:R1/0/10
B:R1/0/2
B:R1/0/3
B:R1/0/4
Drive idle
BUSY
B:R1/0/5
Drive idle
BUSY
B:R1/0/2
B:R9/1/2
Drive idle
BUSY
B:R9/1/3
B:R9/1/2
B:R9/1/3
B:R9/1/4
B:R9/1/5
B:R9/1/6
Drive idle
BUSY
B:R9/1/7
Drive idle
BUSY
B:R10/0/2
B:R10/0/2
B:R10/0/3
B:R10/0/4
B:R10/0/5
Drive idle
BUSY
B:R10/0/6
B:R10/0/2
B:R10/0/3
B:R10/0/4
B:R10/0/5
B:R10/0/6
B:R10/0/7
B:R10/0/8
B:R10/0/9
Drive idle
BUSY
B:R10/0/10
B:R10/0/2
B:R10/0/3
B:R10/0/4
Drive idle
BUSY
B:R10/0/5
B:R10/0/2
B:R10/0/3
B:R10/0/4
B:R10/0/5
B:R10/0/6
B:R10/0/7
B:R10/0/8
Drive idle
BUSY
B:R10/0/9
B:R10/0/2
B:R10/0/3
Drive idle
BUSY
B:R10/0/4
B:R10/0/2
B:R10/0/3
B:R10/0/4
B:R10/0/5
B:R10/0/6
B:R10/0/7
Drive idle
BUSY
B:R10/0/8
B:R10/0/2
Drive idle
BUSY
B:R10/0/3
B:R10/0/2
B:R10/0/3
B:R10/0/4
B:R10/0/5
B:R10/0/6
Drive idle
BUSY
B:R10/0/7
Drive idle
BUSY
B:R10/1/2
B:R10/1/2
B:R10/1/3
B:R10/1/4
B:R10/1/5
Drive idle
BUSY
B:R10/1/6
B:R10/1/2
B:R10/1/3
B:R10/1/4
B:R10/1/5
B:R10/1/6
B:R10/1/7
B:R10/1/8
B:R10/1/9
Drive idle
BUSY
B:R10/1/10
B:R10/1/2
B:R10/1/3
B:R10/1/4
Drive idle
BUSY
B:R10/1/5
B:R10/1/2
B:R10/1/3
B:R10/1/4
B:R10/1/5
B:R10/1/6
B:R10/1/7
B:R10/1/8
Drive idle
BUSY
B:R10/1/9
B:R10/1/2
B:R10/1/3
Drive idle
BUSY
B:R10/1/4
B:R10/1/2
B:R10/1/3
B:R10/1/4
B:R10/1/5
B:R10/1/6
B:R10/1/7
Drive idle
BUSY
B:R10/1/8
B:R10/1/2
Drive idle
BUSY
B:R10/1/3
B:R10/1/2
B:R10/1/3
B:R10/1/4
B:R10/1/5
B:R10/1/6
Drive idle
BUSY
B:R10/1/7
Drive idle
BUSY
B:R11/0/2
B:R11/0/2
B:R11/0/3
B:R11/0/4
B:R11/0/5
Drive idle
BUSY
B:R11/0/6
B:R11/0/2
B:R11/0/3
B:R11/0/4
B:R11/0/5
B:R11/0/6
B:R11/0/7
B:R11/0/8
B:R11/0/9
Drive idle
BUSY
B:R11/0/10
B:R11/0/2
B:R11/0/3
B:R11/0/4
Drive idle
BUSY
B:R11/0/5
B:R11/0/2
B:R11/0/3
B:R11/0/4
B:R11/0/5
B:R11/0/6
B:R11/0/7
B:R11/0/8
Drive idle
BUSY
B:R11/0/9
B:R11/0/2
B:R11/0/3
Drive idle
BUSY
B:R11/0/4
B:R11/0/2
B:R11/0/3
B:R11/0/4
B:R11/0/5
B:R11/0/6
B:R11/0/7
Drive idle
BUSY
B:R11/0/8
B:R11/0/2
Drive idle
BUSY
B:R11/0/3
B:R11/0/2
B:R11/0/3
B:R11/0/4
B:R11/0/5
B:R11/0/6
Drive idle
BUSY
B:R11/0/7
Drive idle
BUSY
B:R11/1/2
B:R11/1/2
B:R11/1/3
B:R11/1/4
B:R11/1/5
Drive idle
BUSY
B:R11/1/6
B:R11/1/2
B:R11/1/3
B:R11/1/4
B:R11/1/5
B:R11/1/6
B:R11/1/7
B:R11/1/8
B:R11/1/9
Drive idle
BUSY
B:R11/1/10
Drive idle
BUSY
B:R1/0/2
B:R11/1/2
B:R11/1/3
B:R11/1/4
Drive idle
BUSY
B:R11/1/5
B:R11/1/2
B:R11/1/3
B:R11/1/4
B:R11/1/5
B:R11/1/6
B:R11/1/7
B:R11/1/8
Drive idle
BUSY
B:R11/1/9
B:R11/1/2
B:R11/1/3
Drive idle
BUSY
B:R11/1/4
B:R11/1/2
B:R11/1/3
B:R11/1/4
B:R11/1/5
B:R11/1/6
B:R11/1/7
Drive idle
BUSY
B:R11/1/8
B:R11/1/2
Drive idle
BUSY
B:R11/1/3
B:R11/1/2
B:R11/1/3
B:R11/1/4
B:R11/1/5
B:R11/1/6
Drive idle
BUSY
B:R11/1/7
Drive idle
BUSY
B:R12/0/2
B:R12/0/2
B:R12/0/3
B:R12/0/4
B:R12/0/5
Drive idle
BUSY
B:R12/0/6
B:R12/0/2
B:R12/0/3
B:R12/0/4
B:R12/0/5
B:R12/0/6
B:R12/0/7
B:R12/0/8
B:R12/0/9
Drive idle
BUSY
B:R12/0/10
B:R12/0/2
B:R12/0/3
B:R12/0/4
Drive idle
BUSY
B:R12/0/5
B:R12/0/2
B:R12/0/3
B:R12/0/4
B:R12/0/5
B:R12/0/6
B:R12/0/7
B:R12/0/8
Drive idle
BUSY
B:R12/0/9
B:R12/0/2
B:R12/0/3
Drive idle
BUSY
B:R12/0/4
B:R12/0/2
B:R12/0/3
B:R12/0/4
B:R12/0/5
B:R12/0/6
B:R12/0/7
Drive idle
BUSY
B:R12/0/8
B:R12/0/2
Drive idle
BUSY
B:R12/0/3
B:R12/0/2
B:R12/0/3
B:R12/0/4
B:R12/0/5
B:R12/0/6
Drive idle
BUSY
B:R12/0/7
Drive idle
BUSY
B:R12/1/2
B:R12/1/2
B:R12/1/3
B:R12/1/4
B:R12/1/5
Drive idle
BUSY
B:R12/1/6
B:R12/1/2
B:R12/1/3
B:R12/1/4
B:R12/1/5
B:R12/1/6
B:R12/1/7
B:R12/1/8
B:R12/1/9
Drive idle
BUSY
B:R12/1/10
B:R12/1/2
B:R12/1/3
B:R12/1/4
Drive idle
BUSY
B:R12/1/5
B:R12/1/2
B:R12/1/3
B:R12/1/4
B:R12/1/5
B:R12/1/6
B:R12/1/7
B:R12/1/8
Drive idle
BUSY
B:R12/1/9
B:R12/1/2
B:R12/1/3
Drive idle
BUSY
B:R12/1/4
B:R12/1/2
B:R12/1/3
B:R12/1/4
B:R12/1/5
B:R12/1/6
B:R12/1/7
Drive idle
BUSY
B:R12/1/8
B:R12/1/2
Drive idle
BUSY
B:R12/1/3
B:R12/1/2
B:R12/1/3
B:R12/1/4
B:R12/1/5
B:R12/1/6
Drive idle
--------------------SYSTEM RESET-----------------------
BUSY
A:R12/1/7
A:R0/0/2
A:R2/0/3
A:R4/0/4
A:R4/0/5
A:R2/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/0/2
A:R0/0/3
A:R0/0/4
A:R0/0/5
A:R0/0/6
A:R0/0/7
A:R0/0/8
A:R0/0/9
A:R0/0/10
A:R0/1/2
A:R0/1/3
A:R0/1/4
A:R0/1/5
A:R0/1/6
A:R0/1/7
Drive idle
BUSY
A:R0/1/8
Drive idle
BUSY
A:R1/0/2
A:R1/0/2
A:R1/0/3
A:R1/0/4
A:R1/0/5
Drive idle
BUSY
A:R1/0/6
A:R1/0/2
A:R1/0/3
A:R1/0/4
A:R1/0/5
A:R1/0/6
A:R1/0/7
A:R1/0/8
A:R1/0/9
Drive idle
BUSY
A:R1/0/10
A:R1/0/2
A:R1/0/3
A:R1/0/4
Drive idle
BUSY
B:R1/0/5
B:R13/0/2
B:R13/0/3
B:R13/0/4
B:R13/0/5
B:R13/0/6
B:R13/0/7
B:R13/0/8
B:R13/0/9
B:R13/0/10
B:R13/0/2
B:R13/0/3
B:R13/0/4
B:R13/0/5
B:R13/0/6
B:R13/0/7
B:R13/0/8
B:R13/0/9
B:R13/0/10
B:R13/0/2
B:R13/0/3
B:R13/0/4
B:R13/0/5
B:R13/0/6
B:R13/0/7
B:R13/0/8
B:R13/0/9
B:R13/0/10
B:R13/0/2
B:R13/0/3
B:R13/0/4
B:R13/0/5
B:R13/0/6
B:R13/0/7
B:R13/0/8
B:R13/0/9
B:R13/0/10
B:R13/0/2
B:R13/0/3
B:R13/0/4
B:R13/0/5
B:R13/0/6
B:R13/0/7
B:R13/0/8
B:R13/0/9
B:R13/0/10
B:R13/0/2
B:R13/0/3
B:R13/0/4
B:R13/0/5
B:R13/0/6
B:R13/0/7
B:R13/0/8
B:R13/0/9
B:R13/0/10
B:R13/0/2
B:R13/0/3
B:R13/0/4
B:R13/0/5
B:R13/0/6
B:R13/0/7
B:R13/0/8
B:R13/0/9
B:R13/0/10
Drive idle
-------------------BDOS ERR B:----------------------

Originally posted by @RaceSoft in #21 (comment)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.