예제 #1
0
void SN76496_dump(int chip, uint8_t buf[16])
{
	struct SN76496 *R = &sn[chip];
	uint16_t tmp;
	unsigned int i;

	for (i = 0; (i < 8); ++i) {
		tmp = h2le16(R->Register[i]);
		memcpy(&buf[(i * 2)], &tmp, 2);
	}
}
예제 #2
0
int eip_pccc_tag_read_start(ab_tag_p tag)
{
    int rc = PLCTAG_STATUS_OK;
    ab_request_p req;
    uint16_t conn_seq_id = (uint16_t)(session_get_new_seq_id(tag->session));;
    int overhead;
    int data_per_packet;
    pccc_req *pccc;
    uint8_t *data;
    uint8_t *embed_start;
    int debug = tag->debug;

    pdebug(debug,"Starting");

    /* how many packets will we need? How much overhead? */
    overhead = sizeof(pccc_resp) + 4 + tag->encoded_name_size; /* MAGIC 4 = fudge */

    data_per_packet = MAX_PCCC_PACKET_SIZE - overhead;

	if(data_per_packet <= 0) {
		pdebug(debug,"Unable to send request.  Packet overhead, %d bytes, is too large for packet, %d bytes!", overhead, MAX_EIP_PACKET_SIZE);
		tag->status = PLCTAG_ERR_TOO_LONG;
		return tag->status;
	}

	if(data_per_packet < tag->size) {
		pdebug(debug,"PCCC requests cannot be fragmented.  Too much data requested.");
		tag->status = PLCTAG_ERR_TOO_LONG;
		return tag->status;
	}

	if(!tag->reqs) {
		tag->reqs = (ab_request_p*)mem_alloc(1 * sizeof(ab_request_p));
		tag->max_requests = 1;
		tag->num_read_requests = 1;
		tag->num_write_requests = 1;

		if(!tag->reqs) {
			pdebug(debug,"Unable to get memory for request array!");
			tag->status = PLCTAG_ERR_NO_MEM;
			return tag->status;
		}
	}

	/* get a request buffer */
	rc = request_create(&req);

	if(rc != PLCTAG_STATUS_OK) {
		pdebug(debug,"Unable to get new request.  rc=%d",rc);
		tag->status = rc;
		return rc;
	}

	req->debug = tag->debug;

	/* point the struct pointers to the buffer*/
	pccc = (pccc_req*)(req->data);

	/* set up the embedded PCCC packet */
	embed_start = (uint8_t*)(&pccc->service_code);

	/* Command Routing */
	pccc->service_code = AB_EIP_CMD_PCCC_EXECUTE;  /* ALWAYS 0x4B, Execute PCCC */
	pccc->req_path_size = 2;   /* ALWAYS 2, size in words of path, next field */
	pccc->req_path[0] = 0x20;  /* class */
	pccc->req_path[1] = 0x67;  /* PCCC Execute */
	pccc->req_path[2] = 0x24;  /* instance */
	pccc->req_path[3] = 0x01;  /* instance 1 */

	/* PCCC ID */
	pccc->request_id_size = 7;  /* ALWAYS 7 */
	pccc->vendor_id = h2le16(AB_EIP_VENDOR_ID);             /* Our CIP Vendor */
	pccc->vendor_serial_number = h2le32(AB_EIP_VENDOR_SN);      /* our unique serial number */

	/* fill in the PCCC command */
	pccc->pccc_command = AB_EIP_PCCC_TYPED_CMD;
	pccc->pccc_status = 0;  /* STS 0 in request */
	pccc->pccc_seq_num = h2le16(conn_seq_id); /* FIXME - get sequence ID from session? */
	pccc->pccc_function = AB_EIP_PCCC_TYPED_READ_FUNC;
	pccc->pccc_transfer_size = h2le16(tag->elem_count); /* This is not in the docs, but it is in the data. */

	/* point to the end of the struct */
	data = ((uint8_t *)pccc) + sizeof(pccc_req);
	
	/* copy LAA tag name into the request */
	mem_copy(data,tag->encoded_name,tag->encoded_name_size);
	data += tag->encoded_name_size;
	
	/* we need the count twice? */
	*((uint16_t*)data) = h2le16(tag->elem_count); /* FIXME - bytes or INTs? */
	data += sizeof(uint16_t);
	
	/*
	 * after the embedded packet, we need to tell the message router
	 * how to get to the target device.
	 */

	/* encap fields */
	pccc->encap_command = h2le16(AB_EIP_READ_RR_DATA);    /* ALWAYS 0x0070 Unconnected Send*/

	/* router timeout */
	pccc->router_timeout = h2le16(1);                 /* one second timeout, enough? */

	/* Common Packet Format fields for unconnected send. */
	pccc->cpf_item_count 		= h2le16(2);				/* ALWAYS 2 */
	pccc->cpf_nai_item_type 	= h2le16(AB_EIP_ITEM_NAI);  /* ALWAYS 0 */
	pccc->cpf_nai_item_length 	= h2le16(0);   				/* ALWAYS 0 */
	pccc->cpf_udi_item_type		= h2le16(AB_EIP_ITEM_UDI);  /* ALWAYS 0x00B2 - Unconnected Data Item */
	pccc->cpf_udi_item_length	= h2le16(data - embed_start);  /* REQ: fill in with length of remaining data. */

	/* set the size of the request */
	req->request_size = data - (req->data);

	/* mark it as ready to send */
	req->send_request = 1;

	/* add the request to the session's list. */
	rc = request_add(tag->session, req);

	if(rc != PLCTAG_STATUS_OK) {
		pdebug(debug,"Unable to lock add request to session! rc=%d",rc);
		request_destroy(&req);
		tag->status = rc;
		return rc;
	}

	/* save the request for later */
	tag->reqs[0] = req;
	req = NULL;

    tag->read_in_progress = 1;

    tag->status = PLCTAG_STATUS_PENDING;

    return PLCTAG_STATUS_PENDING;
}
예제 #3
0
int eip_pccc_tag_write_start(ab_tag_p tag)
{
	int rc = PLCTAG_STATUS_OK;
    pccc_req *pccc;
    uint8_t *data;
    uint8_t element_def[16];
    int element_def_size;
    uint8_t array_def[16];
    int array_def_size;
    int pccc_data_type;
    uint16_t conn_seq_id = (uint16_t)(session_get_new_seq_id(tag->session));;
    ab_request_p req = NULL;
    int debug = tag->debug;
	uint8_t *embed_start;
	int overhead, data_per_packet;

    pdebug(debug,"Starting.");
	
	/* how many packets will we need? How much overhead? */
    overhead = sizeof(pccc_resp) + 4 + tag->encoded_name_size; /* MAGIC 4 = fudge */

    data_per_packet = MAX_PCCC_PACKET_SIZE - overhead;

	if(data_per_packet <= 0) {
		pdebug(debug,"Unable to send request.  Packet overhead, %d bytes, is too large for packet, %d bytes!", overhead, MAX_EIP_PACKET_SIZE);
		tag->status = PLCTAG_ERR_TOO_LONG;
		return tag->status;
	}

	if(data_per_packet < tag->size) {
		pdebug(debug,"PCCC requests cannot be fragmented.  Too much data requested.");
		tag->status = PLCTAG_ERR_TOO_LONG;
		return tag->status;
	}

	
	/* set up the requests */
	if(!tag->reqs) {
		tag->reqs = (ab_request_p*)mem_alloc(1 * sizeof(ab_request_p));
		tag->max_requests = 1;
		tag->num_read_requests = 1;
		tag->num_write_requests = 1;

		if(!tag->reqs) {
			pdebug(debug,"Unable to get memory for request array!");
			tag->status = PLCTAG_ERR_NO_MEM;
			return tag->status;
		}
	}

    /* get a request buffer */
    rc = request_create(&req);

    if(rc != PLCTAG_STATUS_OK) {
    	pdebug(debug,"Unable to get new request.  rc=%d",rc);
    	tag->status = rc;
    	return rc;
    }

    req->debug = tag->debug;

    pccc = (pccc_req*)(req->data);

	/* set up the embedded PCCC packet */
	embed_start = (uint8_t*)(&pccc->service_code);

    /* point to the end of the struct */
    data = (req->data) + sizeof(pccc_req);

    /* copy laa into the request */
    mem_copy(data,tag->encoded_name,tag->encoded_name_size);
    data += tag->encoded_name_size;

    /* What type and size do we have? */
    if(tag->elem_size != 2 && tag->elem_size != 4) {
        pdebug(debug,"Unsupported data type size: %d",tag->elem_size);
    	request_destroy(&req);
    	tag->status = PLCTAG_ERR_NOT_ALLOWED;
        return PLCTAG_ERR_NOT_ALLOWED;
    }

    if(tag->elem_size == 4)
        pccc_data_type = AB_PCCC_DATA_REAL;
    else
        pccc_data_type = AB_PCCC_DATA_INT;

    /* generate the data type/data size fields, first the element part so that
     * we can get the size for the array part.
     */
    if(!(element_def_size = pccc_encode_dt_byte(element_def,sizeof(element_def),pccc_data_type,tag->elem_size))) {
        pdebug(debug,"Unable to encode PCCC request array element data type and size fields!");
    	request_destroy(&req);
    	tag->status = PLCTAG_ERR_ENCODE;
        return PLCTAG_ERR_ENCODE;
    }

    if(!(array_def_size = pccc_encode_dt_byte(array_def,sizeof(array_def),AB_PCCC_DATA_ARRAY,element_def_size + tag->size))) {
        pdebug(debug,"Unable to encode PCCC request data type and size fields!");
    	request_destroy(&req);
        tag->status = PLCTAG_ERR_ENCODE;
        return PLCTAG_ERR_ENCODE;
    }

    /* copy the array data first. */
    mem_copy(data,array_def,array_def_size);
    data += array_def_size;

    /* copy the element data */
    mem_copy(data,element_def,element_def_size);
    data += element_def_size;

    /* now copy the data to write */
    mem_copy(data,tag->data,tag->size);
    data += tag->size;

    /* now fill in the rest of the structure. */

    /* encap fields */
    pccc->encap_command = h2le16(AB_EIP_READ_RR_DATA);    /* ALWAYS 0x0070 Unconnected Send*/

    /* router timeout */
    pccc->router_timeout = h2le16(1);                 /* one second timeout, enough? */

 	/* Common Packet Format fields for unconnected send. */
	pccc->cpf_item_count 		= h2le16(2);				/* ALWAYS 2 */
	pccc->cpf_nai_item_type 	= h2le16(AB_EIP_ITEM_NAI);  /* ALWAYS 0 */
	pccc->cpf_nai_item_length 	= h2le16(0);   				/* ALWAYS 0 */
	pccc->cpf_udi_item_type		= h2le16(AB_EIP_ITEM_UDI);  /* ALWAYS 0x00B2 - Unconnected Data Item */
	pccc->cpf_udi_item_length	= h2le16(data - embed_start);  /* REQ: fill in with length of remaining data. */

    /* Command Routing */
    pccc->service_code = AB_EIP_CMD_PCCC_EXECUTE;  /* ALWAYS 0x4B, Execute PCCC */
    pccc->req_path_size = 2;   /* ALWAYS 2, size in words of path, next field */
    pccc->req_path[0] = 0x20;  /* class */
    pccc->req_path[1] = 0x67;  /* PCCC Execute */
    pccc->req_path[2] = 0x24;  /* instance */
    pccc->req_path[3] = 0x01;  /* instance 1 */

    /* PCCC ID */
    pccc->request_id_size = 7;  /* ALWAYS 7 */
    pccc->vendor_id = h2le16(AB_EIP_VENDOR_ID);             /* Our CIP Vendor */
    pccc->vendor_serial_number = h2le32(AB_EIP_VENDOR_SN);      /* our unique serial number */

    /* PCCC Command */
    pccc->pccc_command = AB_EIP_PCCC_TYPED_CMD;
    pccc->pccc_status = 0;  /* STS 0 in request */
    //pccc->pccc_seq_num = h2le16(tag->connection->conn_seq_num);
    pccc->pccc_function = AB_EIP_PCCC_TYPED_WRITE_FUNC;
    /* FIXME - what should be the count here?  It is bytes, 16-bit
     * words or something else?
     *
     * Seems to be the number of elements??
     */
    pccc->pccc_transfer_size = h2le16(tag->elem_count); /* This is not in the docs, but it is in the data. */


    /* get ready to add the request to the queue for this session */
    req->request_size = data - (req->data);
    req->send_request = 1;
    req->conn_seq = conn_seq_id;

    /* add the request to the session's list. */
    rc = request_add(tag->session, req);

    if(rc != PLCTAG_STATUS_OK) {
    	pdebug(debug,"Unable to lock add request to session! rc=%d",rc);
    	request_destroy(&req);
    	tag->status = rc;
    	return rc;
    }

    /* save the request for later */
    tag->reqs[0] = req;

    /* the write is now pending */
    tag->write_in_progress = 1;
    tag->status = PLCTAG_STATUS_PENDING;

    return PLCTAG_STATUS_PENDING;
}
예제 #4
0
int build_write_request(ab_tag_p tag, int slot, int byte_offset)
{
	int rc = PLCTAG_STATUS_OK;
	int debug = tag->debug;
    eip_cip_uc_req *cip;
    uint8_t *data;
    uint8_t *embed_start, *embed_end;
    ab_request_p req = NULL;

    pdebug(debug,"Starting.");

	/* get a request buffer */
	rc = request_create(&req);

	if(rc != PLCTAG_STATUS_OK) {
		pdebug(debug,"Unable to get new request.  rc=%d",rc);
		tag->status = rc;
		return rc;
	}

	/* set debug flag on the request too */
	req->debug = tag->debug;

	cip = (eip_cip_uc_req*)(req->data);

	/* point to the end of the struct */
	data = (req->data) + sizeof(eip_cip_uc_req);

	/*
	 * set up the embedded CIP read packet
	 * The format is:
	 *
	 * uint8_t cmd
	 * LLA formatted name
	 * data type to write
	 * uint16_t # of elements to write
	 * data to write
	 */

	embed_start = data;

	/*
	 * set up the CIP Read request type.
	 * Different if more than one request.
	 *
	 * This handles a bug where attempting fragmented requests
	 * does not appear to work with a single boolean.
	 */
	*data = (tag->num_write_requests > 1) ? AB_EIP_CMD_CIP_WRITE_FRAG : AB_EIP_CMD_CIP_WRITE;
	data++;

	/* copy the tag name into the request */
	mem_copy(data,tag->encoded_name,tag->encoded_name_size);
	data += tag->encoded_name_size;

	/* copy encoded type info */
	if(tag->encoded_type_info_size) {
		mem_copy(data,tag->encoded_type_info,tag->encoded_type_info_size);
		data += tag->encoded_type_info_size;
	} else {
		tag->status = PLCTAG_ERR_UNSUPPORTED;
		return tag->status;
	}

	/* copy the item count, little endian */
	*((uint16_t*)data) = h2le16(tag->elem_count);
	data += 2;

	if(tag->num_write_requests > 1) {
		/* put in the byte offset */
		*((uint32_t*)data) = h2le32(byte_offset);
		data += 4;
	}

	/* now copy the data to write */
	mem_copy(data, tag->data + byte_offset, tag->write_req_sizes[slot]);
	data += tag->write_req_sizes[slot];

	/* need to pad data to multiple of 16-bits */
	if(tag->write_req_sizes[slot] & 0x01) {
		*data = 0;
		data++;
	}

	/* mark the end of the embedded packet */
	embed_end = data;

	/*
	 * after the embedded packet, we need to tell the message router
	 * how to get to the target device.
	 */

	/* Now copy in the routing information for the embedded message */
	*data = (tag->conn_path_size)/2; /* in 16-bit words */
	data++;
	*data = 0;
	data++;
	mem_copy(data,tag->conn_path, tag->conn_path_size);
	data += tag->conn_path_size;

	/* now fill in the rest of the structure. */

	/* encap fields */
	cip->encap_command = h2le16(AB_EIP_READ_RR_DATA);    /* ALWAYS 0x006F Unconnected Send*/

	/* router timeout */
	cip->router_timeout = h2le16(1);                 /* one second timeout, enough? */

	/* Common Packet Format fields for unconnected send. */
	cip->cpf_item_count 		= h2le16(2);				/* ALWAYS 2 */
	cip->cpf_nai_item_type 		= h2le16(AB_EIP_ITEM_NAI);  /* ALWAYS 0 */
	cip->cpf_nai_item_length 	= h2le16(0);   				/* ALWAYS 0 */
	cip->cpf_udi_item_type		= h2le16(AB_EIP_ITEM_UDI);  /* ALWAYS 0x00B2 - Unconnected Data Item */
	cip->cpf_udi_item_length	= h2le16(data - (uint8_t*)(&(cip->cm_service_code)));  /* REQ: fill in with length of remaining data. */

	/* CM Service Request - Connection Manager */
	cip->cm_service_code = AB_EIP_CMD_UNCONNECTED_SEND;        /* 0x52 Unconnected Send */
	cip->cm_req_path_size = 2;   /* 2, size in 16-bit words of path, next field */
	cip->cm_req_path[0] = 0x20;  /* class */
	cip->cm_req_path[1] = 0x06;  /* Connection Manager */
	cip->cm_req_path[2] = 0x24;  /* instance */
	cip->cm_req_path[3] = 0x01;  /* instance 1 */

	/* Unconnected send needs timeout information */
	cip->secs_per_tick = AB_EIP_SECS_PER_TICK;	/* seconds per tick */
	cip->timeout_ticks = AB_EIP_TIMEOUT_TICKS;  /* timeout = srd_secs_per_tick * src_timeout_ticks */

	/* size of embedded packet */
	cip->uc_cmd_length = h2le16(embed_end - embed_start);

	/* set the size of the request */
	req->request_size = data - (req->data);

	/* mark it as ready to send */
	req->send_request = 1;

	/* add the request to the session's list. */
	rc = request_add(tag->session, req);

	if(rc != PLCTAG_STATUS_OK) {
		pdebug(debug,"Unable to lock add request to session! rc=%d",rc);
		plc_tag_abort((plc_tag)tag);
		request_destroy(&req);
		tag->status = rc;
		return rc;
	}

	/* save the request for later */
	tag->reqs[slot] = req;

	pdebug(debug,"Done");

	return PLCTAG_STATUS_OK;
}
예제 #5
0
int build_read_request(ab_tag_p tag, int slot, int byte_offset)
{
    eip_cip_uc_req *cip;
    uint8_t *data;
    uint8_t *embed_start, *embed_end;
    ab_request_p req = NULL;
    int debug = tag->debug;
    int rc;

    pdebug(debug,"Starting.");

	/* get a request buffer */
	rc = request_create(&req);

	if(rc != PLCTAG_STATUS_OK) {
		pdebug(debug,"Unable to get new request.  rc=%d",rc);
		tag->status = rc;
		return rc;
	}

	req->debug = debug;

	/* point the request struct at the buffer */
	cip = (eip_cip_uc_req*)(req->data);

	/* point to the end of the struct */
	data = (req->data) + sizeof(eip_cip_uc_req);


	/*
	 * set up the embedded CIP read packet
	 * The format is:
	 *
	 * uint8_t cmd
	 * LLA formatted name
	 * uint16_t # of elements to read
	 */

	embed_start = data;

	/* set up the CIP Read request */
	*data = AB_EIP_CMD_CIP_READ_FRAG;
	data++;

	/* copy the tag name into the request */
	mem_copy(data,tag->encoded_name,tag->encoded_name_size);
	data += tag->encoded_name_size;

	/* add the count of elements to read. */
	*((uint16_t*)data) = h2le16(tag->elem_count);
	data += sizeof(uint16_t);

	/* add the byte offset for this request */
	*((uint32_t*)data) = h2le32(byte_offset);
	data += sizeof(uint32_t);

	/* mark the end of the embedded packet */
	embed_end = data;

	/* Now copy in the routing information for the embedded message */
	/*
	 * routing information.  Format:
	 *
	 * uint8_t path_size in 16-bit words
	 * uint8_t reserved/pad (zero)
	 * uint8_t[...] path (padded to even number of bytes)
	 */
	*data = (tag->conn_path_size)/2; /* in 16-bit words */
	data++;
	*data = 0; /* reserved/pad */
	data++;
	mem_copy(data, tag->conn_path, tag->conn_path_size);
	data += tag->conn_path_size;

	/* now we go back and fill in the fields of the static part */

	/* encap fields */
	cip->encap_command = h2le16(AB_EIP_READ_RR_DATA);    /* ALWAYS 0x0070 Unconnected Send*/

	/* router timeout */
	cip->router_timeout = h2le16(1);                 /* one second timeout, enough? */

	/* Common Packet Format fields for unconnected send. */
	cip->cpf_item_count 		= h2le16(2);				/* ALWAYS 2 */
	cip->cpf_nai_item_type 		= h2le16(AB_EIP_ITEM_NAI);  /* ALWAYS 0 */
	cip->cpf_nai_item_length 	= h2le16(0);   				/* ALWAYS 0 */
	cip->cpf_udi_item_type		= h2le16(AB_EIP_ITEM_UDI);  /* ALWAYS 0x00B2 - Unconnected Data Item */
	cip->cpf_udi_item_length	= h2le16(data - (uint8_t*)(&(cip->cm_service_code)));  /* REQ: fill in with length of remaining data. */

	/* CM Service Request - Connection Manager */
	cip->cm_service_code = AB_EIP_CMD_UNCONNECTED_SEND;        /* 0x52 Unconnected Send */
	cip->cm_req_path_size = 2;   /* 2, size in 16-bit words of path, next field */
	cip->cm_req_path[0] = 0x20;  /* class */
	cip->cm_req_path[1] = 0x06;  /* Connection Manager */
	cip->cm_req_path[2] = 0x24;  /* instance */
	cip->cm_req_path[3] = 0x01;  /* instance 1 */

	/* Unconnected send needs timeout information */
	cip->secs_per_tick = AB_EIP_SECS_PER_TICK;	/* seconds per tick */
	cip->timeout_ticks = AB_EIP_TIMEOUT_TICKS;  /* timeout = src_secs_per_tick * src_timeout_ticks */

	/* size of embedded packet */
	cip->uc_cmd_length = h2le16(embed_end - embed_start);

	/* set the size of the request */
	req->request_size = data - (req->data);

	/* mark it as ready to send */
	req->send_request = 1;

	/* add the request to the session's list. */
	rc = request_add(tag->session, req);

	if(rc != PLCTAG_STATUS_OK) {
		pdebug(debug,"Unable to add request to session! rc=%d",rc);
		request_destroy(&req);
		tag->status = rc;
		return rc;
	}

	/* save the request for later */
	tag->reqs[slot] = req;

	pdebug(debug,"Done");

	return PLCTAG_STATUS_OK;
}