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