/// <summary> /// 메모리 어드레스 변수이름을 생성한다. /// </summary> /// <param name="dataType">데이터타입</param> /// <param name="memType">메모리타입</param> /// <param name="pAddress">주소번지</param> /// <returns></returns> private string CreateValueName(XGT_DataType dataType, XGT_MemoryType memType, string pAddress) { string vReturn = string.Empty; string vMemTypeChar = this.GetMemTypeChar(memType); //메모리타입 string vDataTypeChar = this.GetTypeChar(dataType); //데이터타입 if (dataType == XGT_DataType.Continue) { //연속읽기의 경우는 바이트 단위로만 표현 할 수 있으므로, Word 단위의 메모리를 읽으려면 주소값 * 2 를 해야함. //2Byte = 1Word pAddress = (Convert.ToInt32(pAddress) * 2).ToString(); } if (dataType == XGT_DataType.Bit) { /* * 변수이름 표현 방법에 있어서 비트 영역을 접근하고자 할 때에는 메모리 디바이스의 데이터 * 타입 단위의 순서로 표현하여야 합니다. M172의 C번째 비트를 쓰기 위하여서는 M이 * WORD디바이스 이므로 아래와 같이 비트 타입으로 산출해내는 과정이 필요합니다. * 잘못된 표현: %MX172C * 올바른 표현: 172 x 16(WORD) + 12(BIT) = 2764 * %MX2764 */ int vSEQ = 0; string vAddress = pAddress.Substring(0, pAddress.Length - 1); //입력받은 주소값의 마지막 자리 앞까지가 주소번지 string Last = pAddress.Substring(pAddress.Length - 1); // 입력받은 주소값의 마지막 자리는 비트 위치 vSEQ = Convert.ToInt32(Last, 16); pAddress = (Convert.ToInt32(vAddress) * 16 + vSEQ).ToString(); } return($"%{vMemTypeChar}{vDataTypeChar}{pAddress}"); }
/// <summary> /// 데이터 읽기 /// </summary> /// <param name="pDataType">연속읽기인 경우 (pDataCount)데이터 갯수를 꼭 입력해야함.</param> /// <param name="pAddress">메모리주소 번지</param> /// <param name="pMemtype">메모리 타입</param> /// <param name="pInvokeID"></param> /// <param name="pMsg">리턴 메세지</param> /// <param name="pDataCount">연속읽기일 경우 읽을 데이터 갯수, 개별 읽기면 기본값 0</param> /// <param name="pInputData">쓰기일 경우 입력데이터 받아옴.</param> /// <returns></returns> public XGTData Read(XGT_DataType pDataType, List <XgtAddressData> pAddress, XGT_MemoryType pMemtype, int pInvokeID, int pDataCount = 0) { XGTData vData = new XGTData(); if (pAddress.Count > 16) { vData.Message = "16개 이상 읽어올 수 없습니다."; } else { var buffer = new List <byte>(); try { byte[] data = CreateReadDataFormat(XGT_Request_Func.Read, pDataType, pAddress, pMemtype, pDataCount); byte[] header = CreateHeader(pInvokeID, data.Length); //전송할 프레임 byte[] tcpFrame = new byte[header.Length + data.Length]; //어플레케이션 헤더와 데이터 정보를 합쳐서 전송 Frame을 만든다. int idx = 0; AddByte(header, ref idx, ref tcpFrame); AddByte(data, ref idx, ref tcpFrame); vData.TX = tcpFrame; if (tcpSocket == null || !tcpSocket.Connected) { tcpSocket.Connect(_ip, _port); } tcpSocket.Send(tcpFrame, 0, tcpFrame.Length, SocketFlags.None); do { byte[] currByte = new byte[1]; int byteCounter = tcpSocket.Receive(currByte, 0, currByte.Length, SocketFlags.None); if (byteCounter.Equals(1)) { buffer.Add(currByte[0]); } } while (tcpSocket.Available > 0); vData.RX = buffer.ToArray(); vData.Message = "OK"; } catch (Exception ex) { vData.Message = "ERROR:" + ex.Message.ToString(); } finally { vData.MakeData(); } } return(vData); }
/// <summary> /// 데이터 형식에 따른 Char 반환 /// </summary> /// <param name="type">데이터타입</param> /// <returns></returns> private string GetTypeChar(XGT_DataType type) { string vReturn = string.Empty; // 기본값은 Bit switch (type) { case XGT_DataType.Bit: vReturn = XGT_Data_TypeClass.Bit; break; case XGT_DataType.Byte: vReturn = XGT_Data_TypeClass.Byte; break; case XGT_DataType.Word: vReturn = XGT_Data_TypeClass.Word; break; case XGT_DataType.DWord: vReturn = XGT_Data_TypeClass.DWord; break; case XGT_DataType.LWord: vReturn = XGT_Data_TypeClass.LWord; break; case XGT_DataType.Continue: // 연속읽기에는 ByteType만... vReturn = XGT_Data_TypeClass.Byte; break; default: vReturn = XGT_Data_TypeClass.Bit;; break; } return(vReturn); }
//어플리케이션 데이터 WRITE 포맷 만들기 private byte[] CreateWriteDataFormat (XGT_Request_Func emFunc, XGT_DataType emDatatype, List <XgtAddressData> pAddressList, XGT_MemoryType emMemtype, int pDataCount) { int vLenth = 0; //데이타 포맷 프레임의 크기 byte[] command = BitConverter.GetBytes((short)emFunc); //StringToByteArray((int)emFunc, true); //명령어 읽기,쓰기 byte[] dataType = BitConverter.GetBytes((short)emDatatype); //StringToByteArray((int)emDatatype, true); //데이터 타입 byte[] reserved = BitConverter.GetBytes((short)0); //예약영역 고정(0x0000) byte[] blockcount = BitConverter.GetBytes((short)pAddressList.Count); //블록수 //프레임 크기 설정 : 명령어(2) + 데이터타입(2) + 예약영역(2) + 블록수 (?) + 변수길이(?) + 변수(?) vLenth = command.Length + dataType.Length + reserved.Length + blockcount.Length; List <XgtAddressData> lstAddress = new List <XgtAddressData>(); foreach (XgtAddressData addr in pAddressList) { string vAddress = CreateValueName(emDatatype, emMemtype, addr.Address); addr.AddressString = vAddress; object oData = new object(); //입력받은 값이 숫자형인지 문자형이지 확실치 않아 Object 로 선언 int oDataLength = 0; //입력받은 값의 바이트 배열의 크기. //데이터 쓰기일 경우 입력 데이터의 크기를 구한다. int nInput = 0; //입력받은 데이터가 숫자형일경우 받을 변수 string strInput = string.Empty; //입력받은 데이터가 문자형일 경우 받을 변수. if (!int.TryParse(addr.Data, out nInput)) { //문자형일 경우 strInput = addr.Data; oData = Encoding.ASCII.GetBytes(strInput); } else { //숫자형일 경우 oData = BitConverter.GetBytes((short)nInput); } if (emDatatype == XGT_DataType.Bit) { addr.DataByteArray = new byte[1]; addr.DataByteArray[0] = ((byte[])oData)[0]; } else { addr.DataByteArray = (byte[])oData; } //입력값의 바이트 배열의 크기 oDataLength = ((byte[])oData).Length; vLenth += addr.AddressByteArray.Length + addr.LengthByteArray.Length + 2 + oDataLength; //데이터 갯수 + 데이터 길이 lstAddress.Add(addr); } if (XGT_DataType.Continue == emDatatype) { vLenth += 2; //연속읽기 인 경우 2바이트 추가.(데이터 갯수) } byte[] data = new byte[vLenth]; int idx = 0; AddByte(command, ref idx, ref data); AddByte(dataType, ref idx, ref data); AddByte(reserved, ref idx, ref data); AddByte(blockcount, ref idx, ref data); foreach (XgtAddressData addr in lstAddress) { AddByte(addr.LengthByteArray, ref idx, ref data); AddByte(addr.AddressByteArray, ref idx, ref data); } foreach (XgtAddressData addr in lstAddress) { //데이터 쓰기일 경우 byte[] count = BitConverter.GetBytes((short)addr.DataByteArray.Length); AddByte(count, ref idx, ref data); AddByte(addr.DataByteArray, ref idx, ref data); } return(data); }
//어플리케이션 데이터 READ 포맷 만들기 private byte[] CreateReadDataFormat (XGT_Request_Func emFunc, XGT_DataType emDatatype, List <XgtAddressData> pAddressList, XGT_MemoryType emMemtype, int pDataCount) { List <XgtAddressData> lstAddress = new List <XgtAddressData>(); int vLenth = 0; //데이타 포맷 프레임의 크기 byte[] command = BitConverter.GetBytes((short)emFunc); //StringToByteArray((int)emFunc, true); //명령어 읽기,쓰기 byte[] dataType = BitConverter.GetBytes((short)emDatatype); //StringToByteArray((int)emDatatype, true); //데이터 타입 byte[] reserved = BitConverter.GetBytes((short)0); //예약영역 고정(0x0000) byte[] blockcount = BitConverter.GetBytes((short)pAddressList.Count); //블록수 //프레임 크기 설정 : 명령어(2) + 데이터타입(2) + 예약영역(2) + 블록수 (?) + 변수길이(?) + 변수(?) vLenth = command.Length + dataType.Length + reserved.Length + blockcount.Length; foreach (XgtAddressData addr in pAddressList) { string vAddress = CreateValueName(emDatatype, emMemtype, addr.Address); //byte[] value = Encoding.ASCII.GetBytes(vAddress); //byte[] valueLength = BitConverter.GetBytes((short)value.Length); XgtAddressData XgtAddr = new XgtAddressData(); XgtAddr.AddressString = vAddress; lstAddress.Add(XgtAddr); vLenth += XgtAddr.AddressByteArray.Length + XgtAddr.LengthByteArray.Length; } if (XGT_DataType.Continue == emDatatype && XGT_Request_Func.Read == emFunc) { vLenth += 2; //연속읽기 인 경우 2바이트 추가.(데이터 갯수) } byte[] data = new byte[vLenth]; int idx = 0; AddByte(command, ref idx, ref data); AddByte(dataType, ref idx, ref data); AddByte(reserved, ref idx, ref data); AddByte(blockcount, ref idx, ref data); foreach (XgtAddressData addr in lstAddress) { AddByte(addr.LengthByteArray, ref idx, ref data); AddByte(addr.AddressByteArray, ref idx, ref data); } /* 연속 읽기의 경우 읽을 갯수 지정. */ if (XGT_DataType.Continue == emDatatype) { //데이터 타입이 연속 읽기 인 경우. byte[] vDataCount = BitConverter.GetBytes((short)pDataCount); AddByte(vDataCount, ref idx, ref data); } return(data); }
/// <summary> /// 받아온 응답 값으로 데이터 분서 메서드. /// Read,Write 함수의 finally 구문에서 호출 하도록 작성하시오. /// </summary> public void MakeData() { try { NAK_ErrorCotent = string.Empty; List <XgtAddressData> lstData = new List <XgtAddressData>(); //RX 응답 중 19번째가지는 헤더프레임 정보, 20번째부터 데이터 프레임. //받은 응답이 없으면, 즉 에러가 발생시 if (RX.Length == 0) { NAK_ErrorCotent = "서버로 부터 응답을 받지 못했습니다."; return; } if (RX[20] == (short)XGT_Request_Func.ReadResponse) { ResponseType = XGT_Request_Func.ReadResponse; } if (RX[20] == (short)XGT_Request_Func.WriteResponse) { ResponseType = XGT_Request_Func.WriteResponse; } byte[] vdataType = new byte[2]; vdataType[0] = RX[22]; vdataType[1] = RX[23]; foreach (XGT_DataType item in Enum.GetValues(typeof(XGT_DataType))) { string vb = BitConverter.ToString(BitConverter.GetBytes((short)item)); string va = BitConverter.ToString(vdataType); if (vb.Equals(va)) { DataType = item; break; } } if (RX[26] != 0x00 || RX[27] != 0x00) { //에러응답 ResponseStatus = "NAK"; DataList = lstData; //에러메세지 확인 switch (RX[28]) { case 0x12: NAK_ErrorCotent = "(0x12)연속읽기인데 바이트 타입이 아닌 경우"; break; case 0x11: NAK_ErrorCotent = "(0x11)변수명이 4보다 작거나 16보다 큰 경우와 같이 어드레스에 관련된 에러"; break; case 0x10: NAK_ErrorCotent = "(0x10)없는 디바이스를 요청하는 경우와 같이 디바이스에 관련된 에러"; break; case 0x78: NAK_ErrorCotent = "(0x78)unknown command"; break; case 0x77: NAK_ErrorCotent = "(0x77)체크섬 오류"; break; case 0x76: NAK_ErrorCotent = "(0x76)length 정보 오류"; break; case 0x75: NAK_ErrorCotent = "(0x75) “LGIS-GLOFA”가 아니거나 “LSIS-XGT”가 아닌 경우"; break; case 0x24: NAK_ErrorCotent = "(0x24)데이터 타입 에러"; break; default: NAK_ErrorCotent = "알려지지 않은 에러코드, LS산전 고객센터에 문의"; break; } } else { //28번 index 부터 데이터로 정의 int index = 28; //정상응답 ResponseStatus = "ACK"; byte[] blockCount = new byte[2]; //블럭카운터 byte[] dataByteCount = new byte[2]; //데이터 크기 byte[] data = new byte[2]; //블럭카운터 Array.Copy(RX, index, blockCount, 0, 2); BlockCount = BitConverter.ToInt16(blockCount, 0); index = index + 2; //블럭카운터 만큼의 데이터 갯수가 존재한다. //Read일 경우 데이터 생성 if (ResponseType == XGT_Request_Func.ReadResponse) { for (int i = 0; i < BlockCount; i++) { Array.Copy(RX, index, dataByteCount, 0, 2); int biteSize = BitConverter.ToInt16(dataByteCount, 0); //데이터 크기. index = index + 2; Array.Copy(RX, index, data, 0, biteSize); index = index + biteSize; //다음 인덱스 string dataContent = BitConverter.ToString(data, 0); XgtAddressData dataValue = new XgtAddressData(); dataValue.Data = dataContent; dataValue.DataByteArray = data; lstData.Add(dataValue); } } DataList = lstData; } } catch (Exception ex) { Message = "Error: " + ex.Message.ToString(); } }