Rework SD interface and add head 4

This commit is contained in:
2025-09-05 19:36:48 +01:00
parent d8ddc608aa
commit bf6760347e
7 changed files with 17244 additions and 15949 deletions

View File

@@ -0,0 +1,92 @@
(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor)
(symbol "5031821852" (pin_names (offset 0.254)) (in_bom yes) (on_board yes)
(property "Reference" "J" (id 0) (at 25.4 10.16 0)
(effects (font (size 1.524 1.524)))
)
(property "Value" "5031821852" (id 1) (at 25.4 7.62 0)
(effects (font (size 1.524 1.524)))
)
(property "Footprint" "503182-1852_MOL" (id 2) (at 0 0 0)
(effects (font (size 1.27 1.27) italic) hide)
)
(property "Datasheet" "https://www.molex.com/en-us/products/part-detail-pdf/5031821852?display=pdf" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27) italic) hide)
)
(property "ki_keywords" "5031821852" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_locked" "" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "503182-1852_MOL" (id 6) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "5031821852_0_1"
(polyline
(pts
(xy 7.62 5.08)
(xy 7.62 -12.7)
)
(stroke (width 0.127) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 7.62 -12.7)
(xy 43.18 -12.7)
)
(stroke (width 0.127) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 43.18 -12.7)
(xy 43.18 5.08)
)
(stroke (width 0.127) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 43.18 5.08)
(xy 7.62 5.08)
)
(stroke (width 0.127) (type default) (color 0 0 0 0))
(fill (type none))
)
(pin bidirectional line (at 0 0 0) (length 7.62)
(name "DATA_2" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 0 -2.54 0) (length 7.62)
(name "CD/DAT_3" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
(pin unspecified line (at 0 -5.08 0) (length 7.62)
(name "CMD" (effects (font (size 1.27 1.27))))
(number "3" (effects (font (size 1.27 1.27))))
)
(pin power_in line (at 0 -7.62 0) (length 7.62)
(name "VDD" (effects (font (size 1.27 1.27))))
(number "4" (effects (font (size 1.27 1.27))))
)
(pin unspecified line (at 50.8 -7.62 180) (length 7.62)
(name "CLK" (effects (font (size 1.27 1.27))))
(number "5" (effects (font (size 1.27 1.27))))
)
(pin power_out line (at 50.8 -5.08 180) (length 7.62)
(name "VSS" (effects (font (size 1.27 1.27))))
(number "6" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 50.8 -2.54 180) (length 7.62)
(name "DAT0" (effects (font (size 1.27 1.27))))
(number "7" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 50.8 0 180) (length 7.62)
(name "DAT1" (effects (font (size 1.27 1.27))))
(number "8" (effects (font (size 1.27 1.27))))
)
)
)
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,8 @@ BIN=bin/$(SKETCH).ino.bin
#IP=$(shell avahi-resolve -n $(HOST).local | cut -f2 -d' ')
$(BIN): $(SKETCH).ino datastream.h
arduino-cli compile --fqbn $(BOARD) --board-options "freq=300,arch=riscv" --output-dir bin --build-path build
#arduino-cli compile --fqbn $(BOARD) --board-options "freq=300,arch=riscv" --output-dir bin --build-path build
arduino-cli compile --fqbn $(BOARD) --board-options "freq=300" --output-dir bin --build-path build
upload: $(BIN)
arduino-cli upload --fqbn $(BOARD) -p $(PORT) --input-dir bin

View File

@@ -1,31 +1,54 @@
#include <CLI.h>
#include <SdFat.h>
#include "datastream.h"
#define SDIO_CLK 16
#define SDIO_CMD 17
#define SDIO_DAT0 18
#define SDIO_DAT1 19
#define SDIO_DAT2 20
#define SDIO_DAT3 21
#define SECTOR_128 0
#define SECTOR_256 1
#define SECTOR_512 2
#define SECTOR_1024 3
#define INDEX 13
#define DOUT 12
#define STEP 7
#define DIR 8
#define SEEK_DONE 9
#define TRACK0 10
#define HSEL0 4
#define HSEL1 5
#define HSEL2 6
#define HSEL3 7
static PIOProgram datastreamPgm(&datastream_program);
PIO pio;
int sm;
int offset;
int dma;
uint32_t loadtime;
uint32_t current_head = 0;
uint32_t current_cyl = 0;
uint32_t current_sector = 0;
#define POLY16 0x1021
#define POLY32 0xa00805
#define CQ16(V, C, P) C = crc16(V, C, P); queue(mfm_encode(V))
#define CQ32(V, C, P) C = crc32(V, C, P); queue(mfm_encode(V))
#define NUM_SECTORS 17
#define TRACK_SIZE (512 * NUM_SECTORS)
uint8_t *track_data;
uint8_t track_data[512 * 17 * 16];
#define OPT_HEADER_CRC16 0x00000001
#define OPT_HEADER_CRC32 0x00000002
@@ -34,16 +57,19 @@ uint8_t *track_data;
#define OPT_DATA_CRC32 0x00000008
#define OPT_DATA_CRC_MASK 0xFFFFFFF3
SdFs sd;
FsFile mounted_file;
struct disk_format {
uint16_t cyls;
uint8_t heads;
uint8_t sectors;
uint8_t sector_size;
uint8_t track_pregap;
uint8_t track_postgap;
uint8_t header_postgap;
uint8_t data_postgap;
uint32_t index_width;
uint32_t track_pregap;
uint32_t track_postgap;
uint32_t header_postgap;
uint32_t data_postgap;
float data_rate;
uint32_t flags;
uint32_t header_poly;
@@ -64,10 +90,11 @@ struct disk_format RD54 = {
15, // Heads
17, // Sectors,
SECTOR_512, // Bytes per sector
151, // Track pregap
151, // Track postgap
16, // Header postgap
50, // Data postgap
10, // Index width - how long the index pulse is low
290, // Track pregap - Time between index pulse and first sync byte
1100, // Track postgap - Time between last sync byte and index pulse
41, // Header postgap - Time between header sync byte and data sync byte
911, // Data postgap - Time between data sync byte and header sync byte of next sector
5000000, // Data Rate
OPT_HEADER_CRC16 | OPT_DATA_CRC32,
0x1021, // Header CRC polynomial
@@ -75,6 +102,10 @@ struct disk_format RD54 = {
};
struct sector {
uint16_t header[10];
uint16_t data[520];
};
struct disk_format *format;
@@ -120,8 +151,6 @@ uint32_t crc32(uint8_t val, uint32_t crc, uint32_t poly)
uint8_t last_bit = 0;
uint16_t mfm_encode_bit(uint8_t b) {
if (b == 0x80) {
last_bit = 1;
return 0b01;
@@ -136,7 +165,10 @@ uint16_t mfm_encode_bit(uint8_t b) {
}
}
uint16_t mfm_encode(uint8_t b) {
uint16_t mfm_encode(uint8_t b, bool reset = false) {
if (reset) {
last_bit = 0;
}
uint16_t out = 0;
@@ -149,120 +181,202 @@ uint16_t mfm_encode(uint8_t b) {
return out;
}
static inline void queue(uint16_t val) {
while(pio_sm_is_tx_fifo_full(pio, sm));
pio->txf[sm] = val;
}
void sync() {
uint16_t sync = mfm_encode(0xA1);
sync &= 0b1111111111011111;
queue(sync);
}
void zero_pad() {
queue(mfm_encode(0x00));
}
void send_header(uint16_t cyl, uint8_t head, uint8_t sector, uint8_t size) {
zero_pad();
sync();
if (format->flags & OPT_HEADER_CRC16) {
uint16_t header_crc = 0xFFFF;
header_crc = crc16(0xA1, header_crc, format->header_poly);
CQ16(0xFE, header_crc, format->header_poly);
CQ16(cyl & 0xFF, header_crc, format->header_poly);
CQ16(((cyl >> 4) & 0xF0) | (head & 0x0F), header_crc, format->header_poly);
CQ16(sector, header_crc, format->header_poly);
CQ16(size, header_crc, format->header_poly);
queue(mfm_encode((header_crc >> 8) & 0xFF));
queue(mfm_encode(header_crc & 0xFF));
} else if (format->flags & OPT_HEADER_CRC32) {
uint32_t header_crc = 0xFFFFFFFF;
header_crc = crc32(0xA1, header_crc, format->header_poly);
CQ32(0xFE, header_crc, format->header_poly);
CQ32(cyl & 0xFF, header_crc, format->header_poly);
CQ32(((cyl >> 4) & 0xF0) | (head & 0x0F), header_crc, format->header_poly);
CQ32(sector, header_crc, format->header_poly);
CQ32(size, header_crc, format->header_poly);
queue(mfm_encode((header_crc >> 24) & 0xFF));
queue(mfm_encode((header_crc >> 16) & 0xFF));
queue(mfm_encode((header_crc >> 8) & 0xFF));
queue(mfm_encode(header_crc & 0xFF));
}
zero_pad();
}
void send_data(uint8_t *data, uint16_t len) {
zero_pad();
sync();
if (format->flags & OPT_DATA_CRC16) {
uint16_t data_crc = 0xFFFF;
data_crc = crc16(0xA1, data_crc, format->data_poly);
CQ16(0xFB, data_crc, format->data_poly);
for (int i = 0; i < len; i++) {
CQ16(data[i], data_crc, format->data_poly);
}
queue(mfm_encode((data_crc >> 8) & 0xFF));
queue(mfm_encode(data_crc & 0xFF));
} else if (format->flags & OPT_DATA_CRC32) {
uint32_t data_crc = 0xFFFFFFFF;
data_crc = crc32(0xA1, data_crc, format->data_poly);
CQ32(0xFB, data_crc, format->data_poly);
for (int i = 0; i < len; i++) {
CQ32(data[i], data_crc, format->data_poly);
}
queue(mfm_encode((data_crc >> 24) & 0xFF));
queue(mfm_encode((data_crc >> 16) & 0xFF));
queue(mfm_encode((data_crc >> 8) & 0xFF));
queue(mfm_encode(data_crc & 0xFF));
}
zero_pad();
}
void send_sector(uint16_t cyl, uint8_t head, uint8_t sector, uint8_t size, uint8_t *data, uint8_t pad) {
send_header(cyl, head, sector, size);
for (int i = 0; i < pad; i++) {
zero_pad();
}
uint16_t len = 0x80 << size;
send_data(data, len);
}
enum {
PH_INDEX_START,
PH_INDEX_END,
PH_TRACK_PREGAP,
PH_SEND_HEADER,
PH_HEADER_POSTGAP,
PH_SEND_DATA,
PH_DATA_POSTGAP,
PH_TRACK_POSTGAP
};
void second_cpu_thread() {
dma = dma_claim_unused_channel(true);
dma_channel_config config = dma_channel_get_default_config(dma);
channel_config_set_read_increment(&config, true);
channel_config_set_write_increment(&config, false);
channel_config_set_dreq(&config, pio_get_dreq(pio, sm, true));
channel_config_set_transfer_data_size(&config, DMA_SIZE_16);
uint32_t ts = micros();
int phase = 0;
int next_sector = 1;
current_sector = 0;
struct sector sectorA;
struct sector sectorB;
struct sector *load = &sectorA;
struct sector *send = &sectorB;
struct sector *swap;
load_sector(load, current_cyl, current_head, current_sector, &track_data[0]);
pinMode(HSEL0, INPUT);
pinMode(HSEL1, INPUT);
pinMode(HSEL2, INPUT);
pinMode(HSEL3, INPUT);
while (1) {
for (int i = 0; i < format->track_postgap; i++) {
zero_pad();
}
current_head = digitalRead(HSEL0) | (digitalRead(HSEL1) << 1) | (digitalRead(HSEL2) << 2) | (digitalRead(HSEL3) << 3);
switch (phase) {
case PH_INDEX_START: // Start index pulse
ts = micros();
format->idx_period = micros() - format->idx_ts;
format->idx_ts = micros();
digitalWrite(13, LOW);
zero_pad();
digitalWrite(13, HIGH);
for (int i = 0; i < format->track_pregap; i++) {
zero_pad();
digitalWrite(INDEX, LOW);
phase++;
break;
case PH_INDEX_END: // Index pulse timing
if ((micros() - ts) >= format->index_width) {
ts = micros();
digitalWrite(INDEX, HIGH);
phase++;
}
break;
case PH_TRACK_PREGAP: // Track pre-gap
if ((micros() - ts) >= format->track_pregap) {
ts = micros();
phase = PH_SEND_HEADER;
}
break;
case PH_SEND_HEADER:
ts = micros();
swap = load;
load = send;
send = swap;
dma_channel_configure(dma, &config,
&pio->txf[sm],
send->header,
10,
true
);
phase = PH_HEADER_POSTGAP;
break;
case PH_HEADER_POSTGAP:
if ((micros() - ts) >= format->header_postgap) {
ts = micros();
phase = PH_SEND_DATA;
}
break;
case PH_SEND_DATA:
ts = micros();
dma_channel_configure(dma, &config,
&pio->txf[sm],
send->data,
520,
true
);
next_sector = (current_sector + 1) % format->sectors;
load_sector(load, current_cyl, current_head, next_sector, &track_data[512 * next_sector]);
if (current_sector < format->sectors - 1) {
phase = PH_DATA_POSTGAP;
} else {
phase = PH_TRACK_POSTGAP;
}
break;
case PH_DATA_POSTGAP:
if ((micros() - ts) > format->data_postgap) {
ts = micros();
current_sector++;
phase = PH_SEND_HEADER;
}
break;
case PH_TRACK_POSTGAP:
if ((micros() - ts) > format->track_postgap) {
ts = micros();
current_sector = 0;
phase = PH_INDEX_START;
}
break;
}
for (int sector = 0; sector < format->sectors; sector++) {
}
}
send_sector(0, 0, sector, format->sector_size, track_data + (sector * format->slen), format->header_postgap);
void load_sector(struct sector *s, int cno, int hno, int secno, uint8_t *data) {
for (int i = 0; i < format->data_postgap; i++) {
zero_pad();
uint32_t ts = micros();
uint16_t hp = format->header_poly;
uint32_t dp = format->data_poly;
s->header[0] = 0;
s->header[1] = 0xA1;
s->header[2] = 0xFE;
s->header[3] = (cno & 0xFF);
s->header[4] = ((cno & 0xF00) >> 4) | (hno & 0x0F);
s->header[5] = secno;
s->header[6] = 0x02;
uint16_t crc = 0xFFFF;
for (int i = 1; i < 7; i++) {
crc = crc16(s->header[i], crc, hp);
}
s->header[7] = (crc >> 8) & 0xFF;
s->header[8] = crc & 0xFF;
s->header[9] = 0;
for (int i = 0; i < 10; i++) {
s->header[i] = mfm_encode(s->header[i], i == 0);
}
s->header[1] &= 0b1111111111011111;
s->data[0] = 0;
s->data[1] = 0xA1;
s->data[2] = 0xFB;
for (int i = 0; i < 512; i++) {
s->data[3 + i] = data[i];
}
uint32_t c32 = 0xFFFFFFFF;
for (int i = 1; i < 515; i++) {
c32 = crc32(s->data[i], c32, dp);
}
s->data[515] = (c32 >> 24) & 0xFF;
s->data[516] = (c32 >> 16) & 0xFF;
s->data[517] = (c32 >> 8) & 0xFF;
s->data[518] = c32 & 0xFF;
s->data[519] = 0;
for (int i = 0; i < 520; i++) {
s->data[i] = mfm_encode(s->data[i], i == 0);
}
s->data[1] &= 0b1111111111011111;
loadtime = micros() - ts;
}
void load_cyl(FsFile file, uint8_t *data, uint32_t cyl, uint32_t heads, uint32_t sectors, uint32_t sectorsize) {
uint32_t len = 0x80 << sectorsize;
len *= sectors;
len *= heads;
uint32_t offset = cyl * len;
file.seekSet(offset);
file.read(data, len);
}
@@ -343,14 +457,35 @@ CLI_COMMAND(cli_status) {
dev->print("Requested Data Rate: ");
dev->print(format->data_rate);
dev->println("MHz");
dev->println("Hz");
dev->print("Actual Data Rate: ");
dev->print(F_CPU / format->clock_div / 20.0);
dev->println("MHz");
dev->println("Hz");
dev->print("Clock divider: ");
dev->println(format->clock_div);
dev->println();
dev->print("PIO: ");
dev->println(PIO_NUM(pio));
dev->print("State Machine: ");
dev->println(sm);
dev->print("Offset: ");
dev->println(offset);
dev->println();
dev->print("Load time: ");
dev->print(loadtime);
dev->println("uS");
dev->println();
dev->print("Current C/H/S: ");
dev->print(current_cyl);
dev->print("/");
dev->print(current_head);
dev->print("/");
dev->println(current_sector);
return 0;
}
@@ -458,9 +593,93 @@ CLI_COMMAND(cli_set) {
return 10;
}
CLI_COMMAND(cli_ls) {
sd.ls(LS_A | LS_DATE | LS_SIZE);
return 0;
}
CLI_COMMAND(cli_create) {
if (argc != 2) {
dev->println("Usage: create <filename>");
dev->println("Create a new image file using the current disk format");
return 10;
}
if (sd.exists(argv[1])) {
dev->println("File already exists");
return 10;
}
uint32_t disk_size = 0x80 << format->sector_size;
disk_size *= format->sectors;
disk_size *= format->heads;
disk_size *= format->cyls;
dev->println("Creating new file, please wait...");
FsFile newfile;
newfile.open(argv[1], O_RDWR | O_CREAT);
newfile.preAllocate(disk_size);
newfile.close();
return 0;
}
CLI_COMMAND(cli_mount) {
if (argc != 2) {
dev->println("Usage: mount <filename>");
dev->println("Mount an image file as the virtual disk");
return 10;
}
if (!sd.exists(argv[1])) {
dev->println("File not found");
return 10;
}
mounted_file = sd.open(argv[1], O_RDWR);
current_cyl = 0;
current_head = 0;
load_cyl(mounted_file, track_data, current_cyl, format->heads, format->sectors, format->sector_size);
return 0;
}
void do_step() {
digitalWrite(SEEK_DONE, LOW);
int dir = digitalRead(DIR);
if (dir == 1 && current_cyl == 0) {
// No can do.
digitalWrite(SEEK_DONE, HIGH);
return;
}
if (dir == 1) {
current_cyl --;
} else {
current_cyl ++;
}
if (current_cyl >= format->cyls) {
current_cyl = 0;
}
load_cyl(mounted_file, track_data, current_cyl, format->heads, format->sectors, format->sector_size);
digitalWrite(TRACK0, current_cyl == 0);
digitalWrite(SEEK_DONE, HIGH);
}
void setup() {
if (!sd.begin(SdioConfig(SDIO_CLK, SDIO_CMD, SDIO_DAT0, 1.5))) {
sd.initErrorPrint();
}
datastreamPgm.prepare(&pio, &sm, &offset);
datastream_program_init(pio, sm, offset);
datastream_program_init(pio, sm, offset, DOUT);
pio_sm_set_enabled(pio, sm, true);
pio->txf[sm] = mfm_encode(0x00);
@@ -474,9 +693,7 @@ void setup() {
format->slen = 0x80 << format->sector_size;
format->tlen = format->slen * format->sectors;
track_data = (uint8_t *)malloc(format->tlen);
for (int i = 0; i < format->tlen; i++) {
for (int i = 0; i < 512 * 17; i++) {
track_data[i] = rand();
}
@@ -492,6 +709,18 @@ void setup() {
CLI.addCommand("status", cli_status);
CLI.addCommand("set", cli_set);
CLI.addCommand("ls", cli_ls);
CLI.addCommand("create", cli_create);
CLI.addCommand("mount", cli_mount);
pinMode(STEP, INPUT);
pinMode(DIR, INPUT);
pinMode(SEEK_DONE, OUTPUT);
digitalWrite(SEEK_DONE, HIGH);
pinMode(TRACK0, OUTPUT);
digitalWrite(TRACK0, current_cyl == 0);
attachInterrupt(STEP, do_step, RISING);
}
void loop() {

View File

@@ -26,17 +26,17 @@ loop:
% c-sdk {
static inline void datastream_program_init(PIO pio, uint sm, uint offset) {
static inline void datastream_program_init(PIO pio, uint sm, uint offset, int dout) {
pio_set_gpio_base(pio, 0);
pio_gpio_init(pio, 12);
pio_sm_set_consecutive_pindirs(pio, sm, 12, 1, true);
pio_gpio_init(pio, dout);
pio_sm_set_consecutive_pindirs(pio, sm, dout, 1, true);
pio_sm_config c = datastream_program_get_default_config(offset);
sm_config_set_out_shift(&c, false, false, 0);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_clkdiv(&c, 3.0);
sm_config_set_out_pin_base(&c, 12);
sm_config_set_out_pin_base(&c, dout);
sm_config_set_out_pin_count(&c, 1);
sm_config_set_set_pin_base(&c, 12);
sm_config_set_set_pin_base(&c, dout);
sm_config_set_set_pin_count(&c, 1);
pio_sm_init(pio, sm, offset, &c);
}

View File

@@ -0,0 +1,69 @@
(footprint "503182-1852_MOL" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tags "5031821852 ")
(attr smd)
(fp_text reference "REF**" (at 0 5.610299 unlocked) (layer F.SilkS)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_text value 503182-1852_MOL (at 0 5.610299 unlocked) (layer F.Fab)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_text user "${REFERENCE}" (at 0 5.610299 unlocked) (layer F.Fab)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_line (start -1.8367 19.190798) (end -1.8367 18.954898) (layer "F.CrtYd") (width 0.1524))
(fp_arc (start -8.22544 5.991276) (mid -8.6106 5.610299) (end -8.22544 5.229321) (layer "F.SilkS") (width 0.508))
(fp_circle (center -8.2296 5.610299) (end -7.8486 5.610299) (layer "B.SilkS") (width 0.508) (fill none))
(fp_circle (center -2.794 4.064) (end -2.413 4.064) (layer "F.Fab") (width 0.508) (fill none))
(fp_line (start -7.5946 18.827898) (end -3.92204 18.827898) (layer "F.SilkS") (width 0.1524))
(fp_line (start 7.5946 18.827898) (end 7.5946 7.527939) (layer "F.SilkS") (width 0.1524))
(fp_line (start 7.5946 3.613299) (end -7.5946 3.613299) (layer "F.SilkS") (width 0.1524))
(fp_line (start -7.5946 3.613299) (end -7.5946 4.662959) (layer "F.SilkS") (width 0.1524))
(fp_line (start -7.4676 18.700898) (end 7.4676 18.700898) (layer "F.Fab") (width 0.0254))
(fp_line (start 7.4676 18.700898) (end 7.4676 3.740299) (layer "F.Fab") (width 0.0254))
(fp_line (start 7.4676 3.740299) (end -7.4676 3.740299) (layer "F.Fab") (width 0.0254))
(fp_line (start -7.4676 3.740299) (end -7.4676 18.700898) (layer "F.Fab") (width 0.0254))
(fp_line (start -1.75796 18.827898) (end 3.85796 18.827898) (layer "F.SilkS") (width 0.1524))
(fp_line (start 6.02204 18.827898) (end 7.5946 18.827898) (layer "F.SilkS") (width 0.1524))
(fp_line (start -7.5946 7.817639) (end -7.5946 18.827898) (layer "F.SilkS") (width 0.1524))
(fp_line (start 7.5946 4.652659) (end 7.5946 3.613299) (layer "F.SilkS") (width 0.1524))
(fp_line (start -1.8367 18.954898) (end 3.9367 18.954898) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 3.9367 18.954898) (end 3.9367 19.190798) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 3.9367 19.190798) (end 5.9433 19.190798) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 5.9433 19.190798) (end 5.9433 18.954898) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 5.9433 18.954898) (end 7.7216 18.954898) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 7.7216 18.954898) (end 7.7216 7.449199) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 7.7216 7.449199) (end 7.9705 7.449199) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 7.9705 7.449199) (end 7.9705 4.731399) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 7.9705 4.731399) (end 7.7216 4.731399) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 7.7216 4.731399) (end 7.7216 3.486299) (layer "F.CrtYd") (width 0.1524))
(fp_line (start 7.7216 3.486299) (end -7.7216 3.486299) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.7216 3.486299) (end -7.7216 4.741699) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.7216 4.741699) (end -7.9689 4.741699) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.9689 4.741699) (end -7.9689 7.738899) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.9689 7.738899) (end -7.7216 7.738899) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.7216 7.738899) (end -7.7216 16.211399) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.7216 16.211399) (end -7.970501 16.211399) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.970501 16.211399) (end -7.970501 18.929199) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.970501 18.929199) (end -6.319501 18.929199) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -6.319501 18.929199) (end -7.7216 18.929199) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.7216 18.929199) (end -7.7216 18.954898) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -7.7216 18.954898) (end -3.8433 18.954898) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -3.8433 18.954898) (end -3.8433 19.190798) (layer "F.CrtYd") (width 0.1524))
(fp_line (start -3.8433 19.190798) (end -1.8367 19.190798) (layer "F.CrtYd") (width 0.1524))
(pad "1" smd rect (at -2.899999 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "2" smd rect (at -1.800001 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "3" smd rect (at -0.700001 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "4" smd rect (at 0.399999 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "5" smd rect (at 1.5 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "6" smd rect (at 2.6 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "7" smd rect (at 3.7 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "8" smd rect (at 4.800001 5.610299) (size 0.8128 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "9" smd rect (at -2.84 18.365298) (size 1.4986 1.143) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "10" smd rect (at 4.94 18.365298) (size 1.4986 1.143) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "11" smd rect (at -7.245 6.240299) (size 0.9398 2.4892) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "15" smd rect (at 6.74 17.240299) (size 1.1684 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "13" smd rect (at -7.145001 17.570299) (size 1.143 2.2098) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "12" smd rect (at 7.145 6.090299) (size 1.143 2.2098) (layers "F.Cu" "F.Paste" "F.Mask"))
(pad "14" smd rect (at 6.74 8.240299) (size 1.1684 1.2446) (layers "F.Cu" "F.Paste" "F.Mask"))
)