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); } }
/* * 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; }
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; }
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; }
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; }