/**************************************************************************** serial.c Code for handling serial port image devices ****************************************************************************/ #include "emu.h" #include "serial.h" // device type definition const device_type SERIAL = &device_creator; //------------------------------------------------- // serial_image_device - constructor //------------------------------------------------- serial_image_device::serial_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, SERIAL, "Serial", tag, owner, clock), device_serial_interface(mconfig, *this), device_image_interface(mconfig, *this) { } //------------------------------------------------- // serial_image_device - destructor //------------------------------------------------- serial_image_device::~serial_image_device() { } //------------------------------------------------- // device_config_complete - perform any // operations now that the configuration is // complete //------------------------------------------------- void serial_image_device::device_config_complete() { // inherit a copy of the static data const serial_image_interface *intf = reinterpret_cast(static_config()); if (intf != NULL) *static_cast(this) = *intf; // or initialize to defaults if none provided else { m_baud_rate = 2400; m_data_bits = 8; m_stop_bits = 2; m_parity = SERIAL_PARITY_NONE; m_transmit_on_start = FALSE; m_tag_connected = NULL; } // set brief and instance name update_names(); } static TIMER_CALLBACK(serial_device_baud_rate_callback) { reinterpret_cast(ptr)->timer_callback(); } /*------------------------------------------------- input_callback - called when other side has updated state -------------------------------------------------*/ void serial_image_device::input_callback(UINT8 state) { m_input_state = state; } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void serial_image_device::device_start() { set_data_frame(m_data_bits, m_stop_bits,m_parity); m_timer = machine().scheduler().timer_alloc(FUNC(serial_device_baud_rate_callback), this); /* signal to other end it is clear to send! */ /* data is initially high state */ /* set /rts */ m_connection_state |= SERIAL_STATE_RTS; /* signal to other end data is ready to be accepted */ /* set /dtr */ m_connection_state |= SERIAL_STATE_DTR; set_out_data_bit(1); serial_connection_out(); transmit_register_reset(); receive_register_reset(); device_serial_interface *intf = NULL; if (m_tag_connected) { device_t *dev = machine().device(m_tag_connected); if (dev!=NULL && dev->interface(intf)) { intf->connect(this); } } } /*************************************************************************** IMPLEMENTATION ***************************************************************************/ /* reset position in stream */ void serial_image_device::data_stream_reset(serial_data_stream *stream) { /* reset byte offset */ stream->ByteCount= 0; /* reset bit count */ stream->BitCount = 0; } /* free stream */ void serial_image_device::data_stream_free(serial_data_stream *stream) { if (stream->pData!=NULL) { free(stream->pData); stream->pData = NULL; } stream->DataLength = 0; } /* initialise stream */ void serial_image_device::data_stream_init(serial_data_stream *stream, unsigned char *pData, unsigned long DataLength) { stream->pData = pData; stream->DataLength = DataLength; data_stream_reset(stream); } /* get a bit from input stream */ int serial_image_device::data_stream_get_data_bit_from_data_byte(serial_data_stream *stream) { int data_bit; int data_byte; if (stream->ByteCountDataLength) { /* get data from buffer */ data_byte= stream->pData[stream->ByteCount]; } else { /* over end of buffer, so return 0 */ data_byte= 0; } /* get bit from data */ data_bit = (data_byte>>(7-stream->BitCount)) & 0x01; /* update bit count */ stream->BitCount++; /* ripple overflow onto byte count */ stream->ByteCount+=stream->BitCount>>3; /* lock bit count into range */ stream->BitCount &=0x07; /* do not let it read over end of data */ if (stream->ByteCount>=stream->DataLength) { stream->ByteCount = stream->DataLength-1; } return data_bit; } void serial_image_device::set_transmit_state(int state) { int previous_state = m_transmit_state; m_transmit_state = state; if ((state^previous_state)!=0) { if (state) { /* start timer */ m_timer->adjust(attotime::zero, 0, attotime::from_hz(m_baud_rate)); } else { /* remove timer */ m_timer->reset(); } } } void serial_image_device::sent_char() { int bit; UINT8 data_byte; /* generate byte to transmit */ data_byte = 0; for (int i=0; i< m_data_bits; i++) { data_byte = data_byte<<1; bit = data_stream_get_data_bit_from_data_byte(&m_transmit); data_byte = data_byte|bit; } /* setup register */ transmit_register_setup(data_byte); logerror("serial device transmitted char: %02x\n",data_byte); } /*------------------------------------------------- timer_callback -------------------------------------------------*/ void serial_image_device::timer_callback() { /* receive data into receive register */ receive_register_update_bit(get_in_data_bit()); if (is_receive_register_full()) { //logerror("SERIAL DEVICE\n"); receive_register_extract(); logerror("serial device receive char: %02x\n",get_received_char()); } /* is transmit empty? */ if (is_transmit_register_empty()) { /* char has been sent, execute callback */ sent_char(); } /* other side says it is clear to send? */ if (m_connection_state & SERIAL_STATE_CTS) { /* send bit */ transmit_register_send_bit(); } } int serial_image_device::load_internal(unsigned char **ptr, int *pDataSize) { int datasize; unsigned char *data; /* get file size */ datasize = length(); if (datasize!=0) { /* malloc memory for this data */ data = (unsigned char *)malloc(datasize); if (data!=NULL) { /* read whole file */ fread(data, datasize); *ptr = data; *pDataSize = datasize; logerror("File loaded!\r\n"); /* ok! */ return 1; } } return 0; } /*------------------------------------------------- call_load -------------------------------------------------*/ bool serial_image_device::call_load() { int data_length; unsigned char *data; /* load file and setup transmit data */ if (load_internal(&data, &data_length)) { data_stream_init(&m_transmit, data, data_length); set_transmit_state(m_transmit_on_start ? 1 :0); return IMAGE_INIT_PASS; } return IMAGE_INIT_FAIL; } /*------------------------------------------------- call_unload -------------------------------------------------*/ void serial_image_device::call_unload() { /* stop transmit */ set_transmit_state(0); /* free streams */ data_stream_free(&m_transmit); data_stream_free(&m_receive); }