summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/jvshost.cpp
blob: 1f720b4fa00723be0216ebb0a8da123ba4df420a (plain) (tree)
1
2
3

                                     
                



























                                                    

                                                                                                                     
 
                               

 
                                














                                                                                                               






                                                                                                 
























                                                                                                                    
                                                                    








                                               
                                                                        










                                               
                                       







                                                                    
                                                      


                       


                                      

                                 
                                      

                                                          

                                        







                                               
                    

 
                                                      


                       


                                        







                                        
                                 
 
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
#include "emu.h"
#include "jvshost.h"
#include "jvsdev.h"

void jvs_host::add_device(jvs_device *dev)
{
	if(first_device)
		first_device->chain(dev);
	else
		first_device = dev;
}

void jvs_host::device_start()
{
	save_item(NAME(send_size));
	save_item(NAME(recv_size));
	save_item(NAME(send_buffer));
	save_item(NAME(recv_buffer));
	save_item(NAME(recv_is_encoded));
}

void jvs_host::device_reset()
{
	send_size = recv_size = 0;
	recv_is_encoded = false;
	memset(send_buffer, 0, sizeof(send_buffer));
	memset(recv_buffer, 0, sizeof(recv_buffer));
}

jvs_host::jvs_host(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock), send_size(0), recv_size(0), recv_is_encoded(false)
{
	first_device = nullptr;
}

void jvs_host::push(uint8_t val)
{
	send_buffer[send_size++] = val;
}

void jvs_host::commit_raw()
{
	recv_size = 0;
	if(!send_size)
		return;

	// Message must:
	// - have a non-zero destination in the first byte
	// - have the message length without the two header bytes but with the checksum byte in the second byte
	// - have at least one command byte
	if(send_size < 3 || send_buffer[0] == 0x00 || send_buffer[1] != send_size-1) {
				logerror("JVS checksum error\n");
				// "This message is crap" doesn't exist so call it checksum error
				recv_buffer[0] = 0x00;
				recv_buffer[1] = 0x02;
				recv_buffer[2] = 0x03;
				recv_size = 3;
		} else {
		if(first_device) {
			first_device->message(send_buffer[0], send_buffer+2, send_size-2, recv_buffer+2, recv_size);
			recv_is_encoded = false;
			if(recv_size) {
				// Add the reply header, host is always destination 0x00
				recv_buffer[0] = 0x00;
				recv_buffer[1] = recv_size+1;
				recv_size += 2;
			}
		} else
			recv_size = 0;
	}
	send_size = 0;
}

void jvs_host::commit_encoded()
{
	recv_size = 0;
	if(!send_size)
		return;
	decode(send_buffer, send_size);
	commit_raw();
}


void jvs_host::get_raw_reply(const uint8_t *&buffer, uint32_t &size)
{
	if(recv_is_encoded) {
		decode(recv_buffer, recv_size);
		recv_is_encoded = false;
	}
	buffer = recv_buffer;
	size = recv_size;
}

void jvs_host::get_encoded_reply(const uint8_t *&buffer, uint32_t &size)
{
	if(!recv_is_encoded) {
		encode(recv_buffer, recv_size);
		recv_is_encoded = true;
	}
	buffer = recv_buffer;
	size = recv_size;
}

bool jvs_host::get_presence_line()
{
	return first_device != nullptr;
}

bool jvs_host::get_address_set_line()
{
	return first_device && first_device->get_address_set_line();
}


void jvs_host::encode(uint8_t *buffer, uint32_t &size)
{
	if(!size)
		return;
	uint32_t add = 1;
	uint8_t sum = 0;
	for(uint32_t i=0; i<size; i++)
		sum += buffer[i];
	buffer[size++] = sum;
	for(uint32_t i=0; i<size; i++)
		if(buffer[i] == 0xd0 || buffer[i] == 0xe0)
			add++;
	for(uint32_t i=size; i; i--) {
		uint8_t t = buffer[i-1];
		if(t == 0xd0 || t == 0xe0) {
			buffer[i+add-1] = t-1;
			buffer[i+add-2] = 0xd0;
			add--;
		} else
			buffer[i+add-1] = t;
	}
	buffer[0] = 0xe0;
	size += add;
}

void jvs_host::decode(uint8_t *buffer, uint32_t &size)
{
	if(!size)
		return;
	uint32_t pos = 0;
	for(uint32_t i=0; i<size; i++) {
		uint8_t t = buffer[i];
		if(!i && t == 0xe0)
			continue;
		if(t == 0xd0) {
			i++;
			t = buffer[i]+1;
		}
		buffer[pos++] = t;
	}
	size = pos ? pos - 1 : 0;
}