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

	for (i = 0; (i < 8); ++i) {
		memcpy(&tmp, &buf[(i * 2)], 2);
		R->Register[i] = le2h16(tmp);
	}
}
Example #2
0
/*
 * check_write_status
 *
 * Fragments are not supported.
 */
static int check_write_status(ab_tag_p tag)
{
    pccc_resp *pccc;
    int rc = PLCTAG_STATUS_OK;
    ab_request_p req;
    int debug = tag->debug;

    pdebug(debug,"Starting.");

    /* is there an outstanding request? */
    if(!tag->reqs || !(tag->reqs[0]) ) {
    	tag->write_in_progress = 0;
    	tag->status = PLCTAG_ERR_NULL_PTR;
    	return PLCTAG_ERR_NULL_PTR;
    }

    req = tag->reqs[0];

    if(!req->resp_received) {
    	tag->status = PLCTAG_STATUS_PENDING;
    	return PLCTAG_STATUS_PENDING;
    }

    /* fake exception */
    do {
		pccc = (pccc_resp*)(req->data);

		/* check the response status */
		if( le2h16(pccc->encap_command) != AB_EIP_READ_RR_DATA) {
			pdebug(debug,"EIP unexpected response packet type: %d!",pccc->encap_command);
			rc = PLCTAG_ERR_BAD_DATA;
			break;
		}

		if(le2h16(pccc->encap_status) != AB_EIP_OK) {
			pdebug(debug,"EIP command failed, response code: %d",pccc->encap_status);
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

		if(pccc->general_status != AB_EIP_OK) {
			pdebug(debug,"PCCC command failed, response code: %d",pccc->general_status);
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

		if(pccc->pccc_status != AB_EIP_OK) {
			/*pdebug(PLC_LOG_ERR,PLC_ERR_READ, "PCCC command failed, response code: %d",pccc->pccc_status);*/
			pdebug(debug,pccc_decode_error(pccc->pccc_data[0]));
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

		tag->status = PLCTAG_STATUS_OK;
		rc = PLCTAG_STATUS_OK;
    } while(0);

	/* let the IO thread free the memory. */
	ab_tag_abort(tag);

    tag->status = rc;

    pdebug(debug,"Done.");

    /* Success! */
    return rc;
}
Example #3
0
static int check_read_status(ab_tag_p tag)
{
    pccc_resp *pccc;

    uint8_t *data;
    uint8_t *data_end;
    int pccc_res_type;
    int pccc_res_length;
    int rc = PLCTAG_STATUS_OK;
    ab_request_p req;
    int debug = tag->debug;

    pdebug(debug,"Starting");

    /* PCCC only can have one request outstanding */
    /* is there an outstanding request? */
    if(!tag->reqs || !(tag->reqs[0])) {
    	tag->read_in_progress = 0;
    	tag->status = PLCTAG_ERR_NULL_PTR;
    	return PLCTAG_ERR_NULL_PTR;
    }

    req = tag->reqs[0];

    if(!req->resp_received) {
    	tag->status = PLCTAG_STATUS_PENDING;
    	return PLCTAG_STATUS_PENDING;
    }

    /* fake exceptions */
    do {
    	pccc = (pccc_resp*)(req->data);

		data_end = (req->data + pccc->encap_length + sizeof(eip_encap_t));

		if(le2h16(pccc->encap_command) != AB_EIP_READ_RR_DATA) {
			pdebug(debug,"Unexpected EIP packet type received: %d!",pccc->encap_command);
			rc = PLCTAG_ERR_BAD_DATA;
			break;
		}

		if(le2h16(pccc->encap_status) != AB_EIP_OK) {
			pdebug(debug,"EIP command failed, response code: %d",pccc->encap_status);
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

		if(pccc->general_status != AB_EIP_OK) {
			pdebug(debug,"PCCC command failed, response code: %d",pccc->general_status);
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

		if(pccc->pccc_status != AB_EIP_OK) {
			/*pdebug(PLC_LOG_ERR,PLC_ERR_READ, "PCCC command failed, response code: %d",pccc_resp->pccc_status);*/
			pdebug(debug,pccc_decode_error(pccc->pccc_data[0]));
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

		/* point to the start of the data */
		data = pccc->pccc_data;

		if(!(data = pccc_decode_dt_byte(data,data_end - data, &pccc_res_type,&pccc_res_length))) {
			pdebug(debug,"Unable to decode PCCC response data type and data size!");
			rc = PLCTAG_ERR_BAD_DATA;
			break;
		}

		/* this gives us the overall type of the response and the number of bytes remaining in it.
		 * If the type is an array, then we need to decode another one of these words
		 * to get the type of each element and the size of each element.  We will
		 * need to adjust the size if we care.
		 */

		if(pccc_res_type == AB_PCCC_DATA_ARRAY) {
			if(!(data = pccc_decode_dt_byte(data,data_end - data, &pccc_res_type,&pccc_res_length))) {
				pdebug(debug,"Unable to decode PCCC response array element data type and data size!");
				rc = PLCTAG_ERR_BAD_DATA;
				break;
			}
		}

		/* copy data into the tag. */
		if((data_end - data) > tag->size) {
			rc = PLCTAG_ERR_TOO_LONG;
			break;
		}

		mem_copy(tag->data, data, data_end - data);

		rc = PLCTAG_STATUS_OK;
    } while(0);

    /* get rid of the request now */
	ab_tag_abort(tag);

    tag->status = rc;

    pdebug(debug,"Done.");

    return rc;
}
Example #4
0
static int check_write_status(ab_tag_p tag)
{
    eip_cip_uc_resp *cip_resp;
    int rc = PLCTAG_STATUS_OK;
    int i;
    ab_request_p req;
    int debug = tag->debug;

    /* is there an outstanding request? */
    if(!tag->reqs) {
    	tag->write_in_progress = 0;
    	tag->status = PLCTAG_ERR_NULL_PTR;
    	return PLCTAG_ERR_NULL_PTR;
    }

    for(i = 0; i < tag->num_write_requests; i++) {
		if(tag->reqs[i] && !tag->reqs[i]->resp_received) {
			tag->status = PLCTAG_STATUS_PENDING;
			return PLCTAG_STATUS_PENDING;
		}
    }



    /*
     * process each request.  If there is more than one request, then
     * we need to make sure that we copy the data into the right part
     * of the tag's data buffer.
     */
    for(i = 0; i < tag->num_write_requests; i++) {
    	int reply_service;

    	req = tag->reqs[i];

    	if(!req) {
    		rc = PLCTAG_ERR_NULL_PTR;
    		break;
    	}

		/* point to the data */
		cip_resp = (eip_cip_uc_resp*)(req->data);

		if(le2h16(cip_resp->encap_command) != AB_EIP_READ_RR_DATA) {
			pdebug(debug,"Unexpected EIP packet type received: %d!",cip_resp->encap_command);
			rc = PLCTAG_ERR_BAD_DATA;
			break;
		}

		if(le2h16(cip_resp->encap_status) != AB_EIP_OK) {
			pdebug(debug,"EIP command failed, response code: %d",cip_resp->encap_status);
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

    	/* if we have fragmented the request, we need to look for a different return code */
		reply_service = ((tag->num_write_requests > 1) ? (AB_EIP_CMD_CIP_WRITE_FRAG | AB_EIP_CMD_CIP_OK) : (AB_EIP_CMD_CIP_WRITE | AB_EIP_CMD_CIP_OK));

		if(cip_resp->reply_service != reply_service) {
			pdebug(debug,"CIP response reply service unexpected: %d",cip_resp->reply_service);
			rc = PLCTAG_ERR_BAD_DATA;
			break;
		}

		if(cip_resp->status != AB_CIP_STATUS_OK && cip_resp->status != AB_CIP_STATUS_FRAG) {
			pdebug(debug,"CIP read failed with status: %d",cip_resp->status);
			pdebug(debug,cip_decode_status(cip_resp->status));
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}
    }

    /*
     * Now remove the requests from the session's request list.
	 * 
	 * FIXME - this has been removed in favor of making the
	 * IO thread do the clean up.
     */
    //for(i = 0; i < tag->num_write_requests; i++) {
    //	int tmp_rc;

    //	req = tag->reqs[i];

    //	tmp_rc = request_remove(tag->session, req);

	//	if(tmp_rc != PLCTAG_STATUS_OK) {
	//		pdebug(debug,"Unable to remove the request from the list! rc=%d",rc);

	//		/* since we could not remove it, maybe the thread can. */
	//		req->abort_request = 1;

	//		rc = tmp_rc;
	//	} else {
	//		/* free up the request resources */
	//		request_destroy(&req);
	//	}

	//	/* mark it as freed */
	//	tag->reqs[i] = NULL;
    //}
	
	/* this triggers the clean up */
	ab_tag_abort(tag);

    tag->write_in_progress = 0;
    tag->status = rc;

    pdebug(debug,"Done.");

    return rc;
}
Example #5
0
static int check_read_status(ab_tag_p tag)
{
	int rc = PLCTAG_STATUS_OK;
	eip_cip_uc_resp *cip_resp;
    uint8_t *data;
    uint8_t *data_end;
    int i;
    ab_request_p req;
    int byte_offset = 0;
    int debug = tag->debug;

    /* is there an outstanding request? */
    if(!tag->reqs) {
    	tag->read_in_progress = 0;
    	tag->status = PLCTAG_ERR_NULL_PTR;
    	return PLCTAG_ERR_NULL_PTR;
    }

    for(i = 0; i < tag->num_read_requests; i++) {
		if(tag->reqs[i] && !tag->reqs[i]->resp_received) {
			tag->status = PLCTAG_STATUS_PENDING;
			return PLCTAG_STATUS_PENDING;
		}
    }

    /*
     * process each request.  If there is more than one request, then
     * we need to make sure that we copy the data into the right part
     * of the tag's data buffer.
     */
    for(i = 0; i < tag->num_read_requests; i++) {
    	req = tag->reqs[i];

    	if(!req) {
    		rc = PLCTAG_ERR_NULL_PTR;
    		break;
    	}

    	/* skip if already processed */
    	if(req->processed) {
    		byte_offset += tag->read_req_sizes[i];
    		continue;
    	}

    	req->processed = 1;

    	pdebug(debug,"processing request %d",i);

 		/* point to the data */
		cip_resp = (eip_cip_uc_resp*)(req->data);

		/* point to the start of the data */
		data = (req->data)+sizeof(eip_cip_uc_resp);

		/* point the end of the data */
		data_end = (req->data + cip_resp->encap_length + sizeof(eip_encap_t));

		/* check the status */
		if(le2h16(cip_resp->encap_command) != AB_EIP_READ_RR_DATA) {
			pdebug(debug,"Unexpected EIP packet type received: %d!",cip_resp->encap_command);
			rc = PLCTAG_ERR_BAD_DATA;
			break;
		}

		if(le2h16(cip_resp->encap_status) != AB_EIP_OK) {
			pdebug(debug,"EIP command failed, response code: %d",cip_resp->encap_status);
			rc = PLCTAG_ERR_REMOTE_ERR;
			break;
		}

		if(cip_resp->reply_service != (AB_EIP_CMD_CIP_READ_FRAG | AB_EIP_CMD_CIP_OK)) {
			pdebug(debug,"CIP response reply service unexpected: %d",cip_resp->reply_service);
			rc = PLCTAG_ERR_BAD_DATA;
			break;
		}

		if(cip_resp->status != AB_CIP_STATUS_OK && cip_resp->status != AB_CIP_STATUS_FRAG) {
			pdebug(debug,"CIP read failed with status: %d",cip_resp->status);
			pdebug(debug,cip_decode_status(cip_resp->status));
			switch(cip_resp->status) {
				case 0x04:		/* FIXME - should be defined constants */
				case 0x05:
				case 0x13:
				case 0x1C:
					rc = PLCTAG_ERR_BAD_PARAM;
					break;
				default:
					rc = PLCTAG_ERR_REMOTE_ERR;
					break;
			}

			break;
		}

		/* the first byte of the response is a type byte. */
		pdebug(debug,"type byte = %d (%x)",(int)*data,(int)*data);

		/*
		 * AB has a relatively complicated scheme for data typing.  The type is
		 * required when writing.  Most of the types are basic types and occupy
		 * a known amount of space.  Aggregate types like structs and arrays
		 * occupy a variable amount of space.  In addition, structs and arrays
		 * can be in two forms: full and abbreviated.  Full form for structs includes
		 * all data types (in full) for fields of the struct.  Abbreviated form for
		 * structs includes a two byte CRC calculated across the full form.  For arrays,
		 * full form includes index limits and base data type.  Abbreviated arrays
		 * drop the limits and encode any structs as abbreviate structs.  At least
		 * we think this is what is happening.
		 *
		 * Luckily, we do not actually care what these bytes mean, we just need
		 * to copy them and skip past them for the actual data.
		 */

		/* check for a simple/base type */
		if((*data) >= AB_CIP_DATA_BIT && (*data) <= AB_CIP_DATA_STRINGI) {
			/* copy the type info for later. */
			if(tag->encoded_type_info_size == 0) {
				tag->encoded_type_info_size = 2;
				mem_copy(tag->encoded_type_info,data,tag->encoded_type_info_size);
			}

			/* skip the type byte and zero length byte */
			data += 2;
		} else if(     (*data) == AB_CIP_DATA_ABREV_STRUCT
					|| (*data) == AB_CIP_DATA_ABREV_ARRAY
					|| (*data) == AB_CIP_DATA_FULL_STRUCT
					|| (*data) == AB_CIP_DATA_FULL_ARRAY)
		{
			/* this is an aggregate type of some sort, the type info is variable length */
			int type_length = *(data+1) + 2; /*
												   * MAGIC
												   * add 2 to get the total length including
												   * the type byte and the length byte.
												   */

			/* check for extra long types */
			if(type_length > MAX_TAG_TYPE_INFO) {
				pdebug(debug,"Read data type info is too long (%d)!", type_length);
				rc = PLCTAG_ERR_TOO_LONG;
				break;
			}

			/* copy the type info for later. */
			if(tag->encoded_type_info_size == 0) {
				tag->encoded_type_info_size = type_length;
				mem_copy(tag->encoded_type_info,data,tag->encoded_type_info_size);
			}

			data += type_length;
		} else {
			pdebug(debug,"Unsupported data type returned, type byte=%d",*data);
			rc = PLCTAG_ERR_UNSUPPORTED;
			break;
		}

		/* copy data into the tag. */
		if((byte_offset + (data_end - data)) > tag->size) {
			pdebug(debug,"Read data is too long (%d bytes) to fit in tag data buffer (%d bytes)!",byte_offset + (int)(data_end-data),tag->size);
			rc = PLCTAG_ERR_TOO_LONG;
			break;
		}

		pdebug(debug,"Got %d bytes of data", (data_end - data));

		/*
		 * copy the data, but only if this is not
		 * a pre-read for a subsequent write!  We do not
		 * want to overwrite the data the upstream has
		 * put into the tag's data buffer.
		 */
		if(!tag->pre_write_read) {
			mem_copy(tag->data  + byte_offset, data, (data_end - data));
		}

		/* save the size of the response for next time */
		tag->read_req_sizes[i] = (data_end - data);

		/*
		 * did we get any data back? a zero-length response is
		 * an error here.
		 */

		if((data_end - data) == 0) {
			rc = PLCTAG_ERR_NO_DATA;
			break;
		} else {
			/* bump the byte offset */
			byte_offset += (data_end - data);

			/* set the return code */
			rc = PLCTAG_STATUS_OK;
		}
    } /* end of for(i = 0; i < tag->num_requests; i++) */

    /* are we actually done? */
    if(rc == PLCTAG_STATUS_OK) {
		if(byte_offset < tag->size) {
			/* no, not yet */
			if(tag->first_read) {
				/* call read start again to get the next piece */
				pdebug(debug,"calling ab_rag_read_cip_start_unsafe() to get the next chunk.");
				rc = eip_cip_tag_read_start(tag);
			} else {
				pdebug(debug,"Insufficient data read for tag!");
				ab_tag_abort(tag);
				rc = PLCTAG_ERR_READ;
			}
		} else {
			/* done! */
			tag->first_read = 0;

			tag->read_in_progress = 0;
			
			/* have the IO thread take care of the request buffers */
			ab_tag_abort(tag);

			/* Now remove the requests from the session's request list. */
			
			/* FIXME - this functionality has been removed to simplify
			 * this case.  All deallocation of requests is done by the
			 * IO thread now.  The abort call above handles this.
			 */
			//for(i = 0; i < tag->num_read_requests; i++) {
				//int tmp_rc;

				//req = tag->reqs[i];

				//tmp_rc = request_remove(tag->session, req);

				//if(tmp_rc != PLCTAG_STATUS_OK) {
				//	pdebug(debug,"Unable to remove the request from the list! rc=%d",rc);
				//
				//	/* since we could not remove it, maybe the thread can. */
				//	req->abort_request = 1;
				//
				//	rc = tmp_rc;
				//} else {
				//	/* free up the request resources */
				//	request_destroy(&req);
				//}

				///* mark it as freed */
				//tag->reqs[i] = NULL;
			//}

			/* if this is a pre-read for a write, then pass off the the write routine */
			if(tag->pre_write_read) {
				pdebug(debug,"Restarting write call now.");

				tag->pre_write_read = 0;
				rc = eip_cip_tag_write_start(tag);
			}
		}
    } else {
    	/* error ! */
    	pdebug(debug,"Error received!");
    }

    tag->status = rc;

    pdebug(debug,"Done.");

    return rc;
}