#include "gpiointerface.h" #include #include #include #include #include #include #define GRID210X_GPIB_STATE_IDLE 0 #define GRID210X_GPIB_STATE_WAIT_DAV_FALSE 1 #define GRID210X_GPIB_STATE_SEND_DATA_START 2 #define GRID210X_GPIB_STATE_WAIT_NDAC_FALSE 3 #define GRID210X_GPIB_STATE_WAIT_ATN_UNASSERT 4 #define GRID210X_STATE_IDLE 0 #define GRID210X_STATE_READING_DATA 1 #define GRID210X_STATE_WRITING_DATA 2 #define GRID210X_STATE_WRITING_DATA_WAIT 3 #define SILENT 1 #define LOG(format, args...) #define LOG_INFO(format, args...) { \ timespec ts; \ clock_gettime(CLOCK_MONOTONIC, &ts); \ printf("+%lu.%09lu: " format, ts.tv_sec, ts.tv_nsec, ##args); \ } \ #define GRID2102_FETCH32(Array, Offset) ((uint32_t)(\ (Array[Offset] << 0) |\ (Array[Offset + 1] << 8) |\ (Array[Offset + 2] << 16) |\ (Array[Offset + 3] << 24)\ )) #define GRID2102_FETCH16(Array, Offset) ((uint16_t)(\ (Array[Offset] << 0) |\ (Array[Offset + 1] << 8)\ )) typedef void (*LineCallback)(); struct LineCallbacks { LineCallback onATNLow; LineCallback onATNHigh; LineCallback onDAVLow; LineCallback onDAVHigh; LineCallback onNRFDLow; LineCallback onNRFDHigh; LineCallback onNDACLow; LineCallback onNDACHigh; }; LineCallback stateMachine = {0}; uint8_t G210x_gpib_state = GRID210X_GPIB_STATE_IDLE; uint8_t G210x_state = GRID210X_STATE_IDLE; uint8_t G210x_last_recv_byte; int G210x_last_recv_eoi; int G210x_last_recv_atn; bool G210x_listening = false; bool G210x_talking = false; bool G210x_serial_polling = false; // int G210x_bus_addr = 4; int G210x_bus_addr = 5; std::vector G210x_data_buffer; std::queue G210x_output_data_buffer; bool G210x_has_srq = false; uint8_t G210x_byte_to_send = 0; uint8_t G210x_serial_poll_byte = 0; uint8_t G210x_send_eoi = 0; uint32_t G210x_floppy_sector_number = 0; uint16_t G210x_io_size = 0; FILE *G210x_image_file = NULL; useconds_t G210x_read_delay = 150; // uint8_t G2101H_identify_response[56] = { // 0x00, 0x02, 0xF8, 0x01, 0x8C, 0x51, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4D, 0x41, // 0x4D, 0x45, 0x20, 0x48, 0x41, 0x52, 0x44, 0x44, 0x49, 0x53, 0x4B, 0x20, 0x44, 0x52, 0x49, 0x56, // 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x47, 0x52, 0x49, 0x44, 0x32, 0x31, 0x30, 0x31, 0x00, 0x02, // 0x11, 0x00, 0x33, 0x01, 0x00, 0x00, 0x04, 0x00 // }; uint8_t G2101H_identify_response[52] = { 0x00, 0x02, 0xF8, 0x01, 0xD0, 0x02, 0x01, 0x20, 0x01, 0x21, 0x01, 0x01, 0x00, 0x00, 0x34, 0x38, 0x20, 0x54, 0x50, 0x49, 0x20, 0x44, 0x53, 0x20, 0x44, 0x44, 0x20, 0x46, 0x4C, 0x4F, 0x50, 0x50, 0x59, 0x20, 0x20, 0x20, 0x20, 0x33, 0x30, 0x30, 0x32, 0x33, 0x37, 0x2D, 0x30, 0x30, 0x00, 0x02, 0x09, 0x00, 0x02, 0x00 }; enum GPIB_Pin { GPIB_PIN_DIO1, GPIB_PIN_DIO2, GPIB_PIN_DIO3, GPIB_PIN_DIO4, GPIB_PIN_DIO5, GPIB_PIN_DIO6, GPIB_PIN_DIO7, GPIB_PIN_DIO8, GPIB_PIN_EOI, GPIB_PIN_ATN, GPIB_PIN_DAV, GPIB_PIN_NRFD, GPIB_PIN_NDAC, GPIB_PIN_SRQ, GPIB_PIN_MAX }; uint8_t remapGPIBPin(GPIB_Pin pin) { switch(pin) { case GPIB_PIN_DIO1: return 4; case GPIB_PIN_DIO2: return 17; case GPIB_PIN_DIO3: return 27; case GPIB_PIN_DIO4: return 22; case GPIB_PIN_DIO5: return 18; case GPIB_PIN_DIO6: return 23; case GPIB_PIN_DIO7: return 24; case GPIB_PIN_DIO8: return 25; case GPIB_PIN_EOI: return 26; case GPIB_PIN_DAV: return 19; case GPIB_PIN_NRFD: return 5; case GPIB_PIN_NDAC: return 6; case GPIB_PIN_ATN: return 12; case GPIB_PIN_SRQ: return 13; } return 0xFF; } int GPIB_host_pin_states[GPIB_PIN_MAX] {}; // int GPIB_pin_states[GPIB_PIN_MAX] {}; #define GPIB_WRITE_FUNCTION_DEFINE(pinName) \ void GPIB_Write_##pinName(int value) { \ LOG("Write " #pinName" %d\n", value); \ GPIB_Pin gpibPin = GPIB_PIN_##pinName; \ /*if (GPIB_pin_states[gpibPin] == value) return;*/ \ uint8_t pin = remapGPIBPin(gpibPin); \ if (value) { \ GPIO_IF_SetMode(pin, GPIO_IF_INPUT); \ } else { \ GPIO_IF_SetMode(pin, GPIO_IF_OUTPUT); \ GPIO_IF_SetPinState(pin, value); \ } \ /*GPIB_pin_states[gpibPin] = value;*/ \ } int GPIB_Read_Pin(GPIB_Pin gpibPin) { // if (GPIB_pin_states[gpibPin] == 0) return 0; return GPIB_host_pin_states[gpibPin]; } #define GPIB_READ_FUNCTION_DEFINE(pinName) \ int GPIB_Read_##pinName() { \ return GPIB_Read_Pin(GPIB_PIN_##pinName); \ } GPIB_WRITE_FUNCTION_DEFINE(NDAC) GPIB_WRITE_FUNCTION_DEFINE(SRQ) GPIB_WRITE_FUNCTION_DEFINE(EOI) GPIB_WRITE_FUNCTION_DEFINE(DAV) GPIB_WRITE_FUNCTION_DEFINE(NRFD) void GPIB_Write_DIO(int byteValue) { for(int i = 0; i < 8; i++) { int value = (byteValue >> i) & 1; GPIB_Pin gpibPin = (GPIB_Pin) (GPIB_PIN_DIO1 + i); // if (GPIB_pin_states[gpibPin] == value) continue; uint8_t pin = remapGPIBPin(gpibPin); if (value) { GPIO_IF_SetMode(pin, GPIO_IF_INPUT); } GPIO_IF_SetPinState(pin, value); if (!value) { GPIO_IF_SetMode(pin, GPIO_IF_OUTPUT); } // GPIB_pin_states[gpibPin] = value; } } GPIB_READ_FUNCTION_DEFINE(ATN) GPIB_READ_FUNCTION_DEFINE(EOI) GPIB_READ_FUNCTION_DEFINE(NDAC) GPIB_READ_FUNCTION_DEFINE(NRFD) int GPIB_Read_DIO() { int byteValue = 0; for(int i = 0; i < 8; i++) { // GPIB_Pin gpibPin = (GPIB_Pin) (GPIB_PIN_DIO1 + i); byteValue |= GPIO_IF_GetPinState(remapGPIBPin((GPIB_Pin) i)) << i; } return byteValue; } void G210x_ExecTimer() { if (G210x_state == GRID210X_STATE_READING_DATA) { std::unique_ptr data(new uint8_t[G210x_io_size]); fseek(G210x_image_file, G210x_floppy_sector_number * 512, SEEK_SET); fread(data.get(), 1, G210x_io_size, G210x_image_file); for (int i = 0; i < G210x_io_size; i++) { G210x_output_data_buffer.push(data[i]); } G210x_serial_poll_byte = 0x0F; G210x_has_srq = true; GPIB_Write_SRQ(0); G210x_state = GRID210X_STATE_IDLE; } else if (G210x_state == GRID210X_STATE_WRITING_DATA_WAIT) { // send an srq as success flag for (int i = 0; i < 7; i++) { // FIXME: G210x_output_data_buffer.push(0); } G210x_serial_poll_byte = 0x0F; G210x_has_srq = true; GPIB_Write_SRQ(0); G210x_state = GRID210X_STATE_IDLE; } } void G210x_AcceptTransfer() { if (G210x_state == GRID210X_STATE_IDLE) { if (G210x_data_buffer.size() >= 0xA) { uint8_t command = G210x_data_buffer[0]; uint32_t sector_number = GRID2102_FETCH32(G210x_data_buffer, 3); uint16_t data_size = GRID2102_FETCH16(G210x_data_buffer, 7); LOG_INFO("grid210x_device command %u, data size %u, sector no %u\n", (unsigned)command, (unsigned)data_size, (unsigned)sector_number); (void)(sector_number); if (command == 0x1) { // ddGetStatus for (int i = 0; i < 52 && i < data_size; i++) { G210x_output_data_buffer.push(G2101H_identify_response[i]); } } else if (command == 0x4) { // ddRead G210x_floppy_sector_number = sector_number; G210x_io_size = data_size; G210x_state = GRID210X_STATE_READING_DATA; // usleep(G210x_read_delay); G210x_ExecTimer(); } else if (command == 0x5) { G210x_floppy_sector_number = sector_number; G210x_io_size = data_size; G210x_state = GRID210X_STATE_WRITING_DATA; } } // else something is wrong, ignore } else if (G210x_state == GRID210X_STATE_WRITING_DATA) { // write if (G210x_floppy_sector_number != 0xFFFFFFFF) { fseek(G210x_image_file, G210x_floppy_sector_number * 512, SEEK_SET); fwrite(G210x_data_buffer.data(), 1, G210x_data_buffer.size(), G210x_image_file); } else { // TODO: set status } // LOG("grid210x_device write sector %d\n", floppy_sector_number); // wait G210x_state = GRID210X_STATE_WRITING_DATA_WAIT; // usleep(G210x_read_delay); G210x_ExecTimer(); } } void G210x_UpdateNDAC(int atn) { if (G210x_gpib_state == GRID210X_GPIB_STATE_IDLE) { if (atn) { // pull NDAC low GPIB_Write_NDAC(0); } else { // pull NDAC high if not listener and low if listener GPIB_Write_NDAC(G210x_listening ? 0 : 1); } } } void G210x_NDAC_Callback(int state); void G210x_NRFD_Callback(int state) { if (state == 0 || state == 1) { LOG("receive NRFD=%d\n", state); } if (state == 1 && G210x_gpib_state == GRID210X_GPIB_STATE_SEND_DATA_START) { // set dio and assert dav GPIB_Write_DIO(G210x_byte_to_send ^ 0xFF); GPIB_Write_EOI(G210x_send_eoi ^ 1); GPIO_IF_USleep(10); // LOG_INFO("grid210x_device byte send %02x eoi %d\n", G210x_byte_to_send, G210x_send_eoi); GPIB_Write_DAV(0); GPIB_Write_NDAC(1); G210x_gpib_state = GRID210X_GPIB_STATE_WAIT_NDAC_FALSE; G210x_NDAC_Callback(GPIB_Read_NDAC()); } // LOG("grid210x_device nrfd state set to %d\n", state); } void G210x_NDAC_Callback(int state) { if (state == 0 || state == 1) { LOG("receive NDAC=%d\n", state); } if (state == 1 && G210x_gpib_state == GRID210X_GPIB_STATE_WAIT_NDAC_FALSE) { // restore initial state // LOG("grid210x_device restore ndac nrfd dav eoi\n"); GPIO_IF_USleep(5); GPIB_Write_DAV(1); GPIB_Write_EOI(1); GPIO_IF_USleep(10); GPIB_Write_NRFD(1); G210x_gpib_state = GRID210X_GPIB_STATE_IDLE; if (G210x_serial_polling) { G210x_talking = false; GPIB_Write_NDAC(0); } else { G210x_UpdateNDAC(GPIB_Read_ATN() ^ 1); } if (!G210x_serial_polling && G210x_talking && !G210x_output_data_buffer.empty()) { G210x_byte_to_send = G210x_output_data_buffer.front(); G210x_output_data_buffer.pop(); G210x_send_eoi = G210x_output_data_buffer.empty() ? 1 : 0; G210x_gpib_state = GRID210X_GPIB_STATE_SEND_DATA_START; } else { // rpi drive emulator fix: CLEAR THE DIO LINES GPIB_Write_DIO(0xFF); } } // LOG("grid210x_device ndac state set to %d\n", state); } void G210x_ATN_Callback(int state) { if (state == 0 || state == 1) { LOG("receive ATN=%d\n", state); } if (state == 1 && G210x_gpib_state == GRID210X_GPIB_STATE_WAIT_ATN_UNASSERT) { G210x_gpib_state = GRID210X_GPIB_STATE_SEND_DATA_START; G210x_NRFD_Callback(GPIB_Read_NRFD()); } if (state == 1 || state == 0) { G210x_UpdateNDAC(state ^ 1); } } void G210x_DAV_Callback(int state) { if (state == 0 || state == 1) { LOG("receive DAV=%d\n", state); } if(state == 0 && G210x_gpib_state == GRID210X_GPIB_STATE_IDLE) { // read data and wait for transfer end GPIB_Write_NRFD(0); int atn = GPIB_Read_ATN() ^ 1; uint8_t data = GPIB_Read_DIO() ^ 0xFF; int eoi = GPIB_Read_EOI() ^ 1; // LOG_INFO("grid210x_device byte recv %02x atn %d eoi %d\n", data, atn, eoi); G210x_last_recv_byte = data; G210x_last_recv_atn = atn; if (!atn) { // update EOI only in data mode (ATN unasserted) G210x_last_recv_eoi = eoi; } GPIB_Write_NDAC(1); G210x_gpib_state = GRID210X_GPIB_STATE_WAIT_DAV_FALSE; } else if (state == 1 && G210x_gpib_state == GRID210X_GPIB_STATE_WAIT_DAV_FALSE) { // restore initial state // m_bus->ndac_w(this, 0); G210x_gpib_state = GRID210X_GPIB_STATE_IDLE; // use ATN value on low DAV; here it can be new already G210x_UpdateNDAC(G210x_last_recv_atn); // GPIO_IF_USleep(100); // Unassert NRFD early GPIB_Write_NRFD(1); if (G210x_last_recv_atn) { if ((G210x_last_recv_byte & 0xE0) == 0x20) { if ((G210x_last_recv_byte & 0x1F) == G210x_bus_addr) { // dev-id = 5 G210x_listening = true; // LOG_INFO("grid210x_device now listening\n"); G210x_data_buffer.clear(); } else if((G210x_last_recv_byte & 0x1F) == 0x1F) { // reset listen G210x_listening = false; // LOG_INFO("grid210x_device now not listening\n"); // Not listening: It's time to handle received command! if (G210x_last_recv_eoi) { G210x_AcceptTransfer(); G210x_data_buffer.clear(); } } } else if ((G210x_last_recv_byte & 0xE0) == 0x40) { if ((G210x_last_recv_byte & 0x1F) == G210x_bus_addr) { // dev-id = 5 G210x_talking = true; // LOG_INFO("grid210x_device now talking\n"); } else { // reset talk G210x_talking = false; // LOG_INFO("grid210x_device now not talking\n"); } } else if (G210x_last_recv_byte == 0x18) { // serial poll enable G210x_serial_polling = true; } else if (G210x_last_recv_byte == 0x19) { // serial poll disable G210x_serial_polling = false; } } else if (G210x_listening) { G210x_data_buffer.push_back(G210x_last_recv_byte); } if (G210x_talking) { if (G210x_serial_polling) { bool had_srq = G210x_has_srq; if (G210x_has_srq) { G210x_has_srq = false; GPIB_Write_SRQ(1); } G210x_byte_to_send = G210x_serial_poll_byte | (had_srq ? 0x40 : 0); G210x_serial_poll_byte = 0; G210x_send_eoi = 0; G210x_gpib_state = GRID210X_GPIB_STATE_SEND_DATA_START; } else if (!G210x_output_data_buffer.empty()) { G210x_byte_to_send = G210x_output_data_buffer.front(); G210x_output_data_buffer.pop(); G210x_send_eoi = G210x_output_data_buffer.empty() ? 1 : 0; G210x_gpib_state = GRID210X_GPIB_STATE_WAIT_ATN_UNASSERT; } } // G210x_NRFD_Callback(GPIB_Read_NRFD()); } } int main(int argc, char **argv) { if(argc != 2) { fprintf(stderr, "usage: g210x \n"); return 2; } if(!GPIO_IF_Init()) { fprintf(stderr, "Failed to initialize GPIO\n"); return 1; } G210x_image_file = fopen(argv[1], "r+b"); if(!G210x_image_file) { fprintf(stderr, "Failed to open image file.\n"); return 3; } // for (int i = 0; i < GPIB_PIN_MAX; i++) { // uint8_t iopin = remapGPIBPin((GPIB_Pin) i); // GPIO_IF_SetPullDown(iopin); // } // usleep(100); // for (int i = 0; i < GPIB_PIN_MAX; i++) { // uint8_t iopin = remapGPIBPin((GPIB_Pin) i); // fprintf(stderr, "%d:%d %d\n", i, iopin, GPIO_IF_GetPinState(iopin)); // } for (int i = 0; i < GPIB_PIN_MAX; i++) { uint8_t iopin = remapGPIBPin((GPIB_Pin) i); GPIO_IF_SetPullup(iopin); GPIO_IF_SetMode(iopin, GPIO_IF_INPUT); // GPIB_pin_states[i] = -1; GPIB_host_pin_states[i] = 1; } while (1) { int old_host_pin_states[GPIB_PIN_MAX]; memcpy(old_host_pin_states, GPIB_host_pin_states, sizeof(GPIB_host_pin_states)); // check signalling only for (int i = GPIB_PIN_DIO8 + 1; i < GPIB_PIN_MAX; i++) { GPIB_host_pin_states[i] = /* GPIB_pin_states[i] && */ GPIO_IF_GetPinState(remapGPIBPin((GPIB_Pin) i)); } for (int i = GPIB_PIN_DIO8 + 1; i < GPIB_PIN_MAX; i++) { bool changed = false; int newState = GPIB_host_pin_states[i]; if (newState != old_host_pin_states[i]) { changed = true; } if (changed) { if (i == GPIB_PIN_ATN) { G210x_ATN_Callback(newState); } else if (i == GPIB_PIN_DAV) { G210x_DAV_Callback(newState); } else if (i == GPIB_PIN_NRFD) { G210x_NRFD_Callback(newState); } else if (i == GPIB_PIN_NDAC) { G210x_NDAC_Callback(newState); } } } // GPIO_IF_USleep(100); } GPIO_IF_Finish(); return 0; }