private void ParseHeader() { byte[] header = CopyOfRange(mData, mData.Length - BYTE_HEADER_SIZE, BYTE_HEADER_SIZE); byte[] osbyte = CopyOfRange(header, 6, 4); mSectionId = (int)(osbyte[3] & 0xFF); mOwnerId = ByteConverter.ByteToInt(new byte[] { osbyte[0], osbyte[1], osbyte[2], (byte)0x00 }); mNoteId = ByteConverter.ByteToInt(CopyOfRange(header, 10, 4)); mPageId = ByteConverter.ByteToInt(CopyOfRange(header, 14, 4)); mLineCount = ByteConverter.ByteToInt(CopyOfRange(header, 22, 4)); mDataSize = ByteConverter.ByteToInt(CopyOfRange(header, 26, 4)); //this.headerCheckSum = header[BYTE_HEADER_SIZE-1]; mBody = CopyOfRange(mData, 0, mData.Length - BYTE_HEADER_SIZE); if (mBody.Length != mDataSize) { throw new Exception("data size is invalid"); } //System.Console.WriteLine( "[OfflineDataParser] noteId : " + noteId + ", pageId : " + pageId + ", lineCount : " + lineCount + ", fileSize : " + dataSize + "byte" ); }
private void ParseDotPacket(Cmd cmd, Packet pk) { switch (cmd) { case Cmd.ONLINE_PEN_UPDOWN_EVENT: IsStartWithDown = pk.GetByte() == 0x00; mDotCount = 0; mTime = pk.GetLong(); mPenTipType = pk.GetByte() == 0x00 ? PenTipType.Normal : PenTipType.Eraser; mPenTipColor = pk.GetInt(); if (mPrevPacket != null && !IsStartWithDown) { mPrevPacket.Reset(); previousDot = null; ParseDot(mPrevPacket, DotTypes.PEN_UP); } break; case Cmd.ONLINE_PEN_DOT_EVENT: if (HoverMode && !IsStartWithDown) { // 호버모드 처리 ParseDot(pk, DotTypes.PEN_HOVER); } else if (IsStartWithDown) { ParseDot(pk, mDotCount == 0 ? DotTypes.PEN_DOWN : DotTypes.PEN_MOVE); } else { //오류 } mPrevPacket = pk; mDotCount++; break; case Cmd.ONLINE_PAPER_INFO_EVENT: byte[] rb = pk.GetBytes(4); mCurSection = (int)(rb[3] & 0xFF); mCurOwner = ByteConverter.ByteToInt(new byte[] { rb[0], rb[1], rb[2], (byte)0x00 }); mCurNote = pk.GetInt(); mCurPage = pk.GetInt(); break; } }
public OfflineDataSerializer(string filepath, int packetCount, bool isCompressed) { chunks = new Dictionary <int, byte[]>(); string[] arr = filepath.Split('\\'); int sectionOwner = int.Parse(arr[2]); byte[] bso = ByteConverter.IntToByte(sectionOwner); sectionId = (int)(bso[3] & 0xFF); ownerId = ByteConverter.ByteToInt(new byte[] { bso[0], bso[1], bso[2], (byte)0x00 }); noteId = int.Parse(arr[3]); pageId = int.Parse(arr[4]); mPacketCount = packetCount; IsCompressed = isCompressed; base.SetupFileSystem(); }
private void ParsePacket(IPacket pk) { switch ((Cmd)pk.Cmd) { case Cmd.A_DotData: { long time = pk.GetByteToInt(); int x = pk.GetShort(); int y = pk.GetShort(); int fx = pk.GetByteToInt(); int fy = pk.GetByteToInt(); int force = pk.GetByteToInt(); long timeLong = mPrevDotTime + time; Dot.Builder builder = new Dot.Builder(MaxForce); builder.owner(mOwnerId) .section(mSectionId) .note(mNoteId) .page(mPageId) .timestamp(timeLong) .coord(x, fx, y, fy) .force(force) .color(mCurrentColor); if (!IsStartWithDown) { if (!IsStartWithPaperInfo) { //펜 다운 없이 페이퍼 정보 없고 무브가 오는 현상(다운 - 무브 - 업 - 다운X - 무브) Callback.onErrorDetected(this, ErrorType.MissingPenDown, -1, null, null); } else { //펜 다운 없이 페이퍼 정보 있고 무브가 오는 현상(다운 - 무브 - 업 - 다운X - 무브) builder.dotType(DotTypes.PEN_ERROR); var errorDot = builder.Build(); Callback.onErrorDetected(this, ErrorType.MissingPenDown, -1, errorDot, null); IsStartWithDown = true; builder.timestamp(Time.GetUtcTimeStamp()); } } if (!IsStartWithDown) { if (!IsStartWithPaperInfo) { //펜 다운 없이 페이퍼 정보 없고 무브가 오는 현상(다운 - 무브 - 업 - 다운X - 무브) Callback.onErrorDetected(this, ErrorType.MissingPenDown, -1, null, null); } else { timeLong = Time.GetUtcTimeStamp(); PenDownTime = timeLong; //펜 다운 없이 페이퍼 정보 있고 무브가 오는 현상(다운 - 무브 - 업 - 다운X - 무브) builder.dotType(DotTypes.PEN_ERROR); var errorDot = builder.Build(); Callback.onErrorDetected(this, ErrorType.MissingPenDown, PenDownTime, errorDot, null); IsStartWithDown = true; builder.timestamp(timeLong); } } if (timeLong < 10000) { // 타임스템프가 10000보다 작을 경우 도트 필터링 builder.dotType(DotTypes.PEN_ERROR); var errorDot = builder.Build(); Callback.onErrorDetected(this, ErrorType.InvalidTime, PenDownTime, errorDot, null); } Dot dot = null; if (IsStartWithDown && IsStartWithPaperInfo && IsBeforePaperInfo) { // 펜다운의 경우 시작 도트로 저장 dot = builder.timestamp(PenDownTime).dotType(DotTypes.PEN_DOWN).Build(); } else if (IsStartWithDown && IsStartWithPaperInfo && !IsBeforePaperInfo && IsBeforeMiddle) { // 펜다운이 아닌 경우 미들 도트로 저장 dot = builder.dotType(DotTypes.PEN_MOVE).Build(); } else if (IsStartWithDown && !IsStartWithPaperInfo) { //펜 다운 이후 페이지 체인지 없이 도트가 들어왔을 경우 Callback.onErrorDetected(this, ErrorType.MissingPageChange, PenDownTime, null, null); } if (dot != null) { ProcessDot(dot); } mPrevDot = dot; mPrevDotTime = timeLong; IsBeforeMiddle = true; IsBeforePaperInfo = false; } break; case Cmd.A_DotUpDownDataNew: case Cmd.A_DotUpDownData: { long updownTime = pk.GetLong(); int updown = pk.GetByteToInt(); byte[] cbyte = pk.GetBytes(3); mCurrentColor = ByteConverter.ByteToInt(new byte[] { cbyte[2], cbyte[1], cbyte[0], (byte)0xFF }); if (updown == 0x00) { // 펜 다운 일 경우 Start Dot의 timestamp 설정 mPrevDotTime = updownTime; //IsPrevDotDown = true; if (IsBeforeMiddle && mPrevDot != null) { // 펜업이 넘어오지 않는 경우 //var errorDot = mPrevDot.Clone(); //errorDot.DotType = DotTypes.PEN_ERROR; //Callback.onErrorDetected(this, ErrorType.MissingPenUp, PenDownTime, errorDot, null); MakeUpDot(); } IsStartWithDown = true; PenDownTime = updownTime; //Callback.onUpDown( this, false ); } else if (updown == 0x01) { mPrevDotTime = -1; if (IsStartWithDown && IsBeforeMiddle && mPrevDot != null) { MakeUpDot(false); } else if (!IsStartWithDown && !IsBeforeMiddle) { Callback.onErrorDetected(this, ErrorType.MissingPenDownPenMove, PenDownTime, null, null); } else if (!IsBeforeMiddle) { // 무브없이 다운-업만 들어올 경우 UP dot을 보내지 않음 Callback.onErrorDetected(this, ErrorType.MissingPenMove, PenDownTime, null, null); } IsStartWithDown = false; PenDownTime = -1; } IsBeforeMiddle = false; IsStartWithPaperInfo = false; mPrevDot = null; } break; case Cmd.A_DotIDChange: if (IsStartWithDown && IsBeforeMiddle && mPrevDot != null) { MakeUpDot(false); } byte[] rb = pk.GetBytes(4); mSectionId = (int)(rb[3] & 0xFF); mOwnerId = ByteConverter.ByteToInt(new byte[] { rb[0], rb[1], rb[2], (byte)0x00 }); mNoteId = pk.GetInt(); mPageId = pk.GetInt(); //IsPrevDotDown = true; IsBeforePaperInfo = true; IsStartWithPaperInfo = true; break; case Cmd.A_PenOnState: pk.Move(8); int STATUS = pk.GetByteToInt(); int FORCE_MAX = pk.GetByteToInt(); MaxForce = (short)FORCE_MAX; string SW_VER = pk.GetString(5); if (STATUS == 0x00) { SendPenOnOffData(); Clean(); } else if (STATUS == 0x01) { Reset(); SendPenOnOffData(); SendRTCData(); needToInputDefaultPassword = true; mOfflineworker.PenMaxForce = FORCE_MAX; Callback.onConnected(this, FORCE_MAX, SW_VER); } break; case Cmd.A_RTCsetResponse: break; case Cmd.A_PenStatusResponse: if (!Authenticated) { Authenticated = true; needToInputDefaultPassword = false; Callback.onPenAuthenticated(this); } pk.Move(2); int stat_timezone = pk.GetInt(); long stat_timetick = pk.GetLong(); int stat_forcemax = pk.GetByteToInt(); int stat_battery = pk.GetByteToInt(); int stat_usedmem = pk.GetByteToInt(); int stat_pencolor = pk.GetInt(); bool stat_autopower = pk.GetByteToInt() == 2 ? false : true; bool stat_accel = pk.GetByteToInt() == 2 ? false : true; bool stat_hovermode = pk.GetByteToInt() == 2 ? false : true; bool stat_beep = pk.GetByteToInt() == 2 ? false : true; short stat_autoshutdowntime = pk.GetShort(); short stat_pensensitivity = pk.GetShort(); string model_name = string.Empty; if (pk.CheckMoreData()) { int model_name_length = pk.GetByte(); model_name = pk.GetString(model_name_length); } Callback.onReceivedPenStatus(this, stat_timezone, stat_timetick, stat_forcemax, stat_battery, stat_usedmem, stat_pencolor, stat_autopower, stat_accel, stat_hovermode, stat_beep, stat_autoshutdowntime, stat_pensensitivity, model_name); break; // 오프라인 데이터 크기,갯수 전송 case Cmd.A_OfflineDataInfo: mOfflineTotalFileCount = pk.GetInt(); mOfflineTotalDataSize = pk.GetInt(); System.Console.WriteLine("[PenCommCore] A_OfflineDataInfo : {0}, {1}", mOfflineTotalFileCount, mOfflineTotalDataSize); Callback.onStartOfflineDownload(this); IsStartOfflineTask = true; break; // 오프라인 전송 최종 결과 응답 case Cmd.A_OfflineResultResponse: int result = pk.GetByteToInt(); //System.Console.WriteLine( "[PenCommCore] A_OfflineDataResponse : {0}", result ); IsStartOfflineTask = false; Callback.onFinishedOfflineDownload(this, result == 0x00 ? false : true); mOfflineworker.onFinishDownload(); mOfflineRcvDataSize = 0; break; // 오프라인 파일 정보 case Cmd.A_OfflineFileInfo: mOfflineFileName = pk.GetString(128); mOfflineFileSize = pk.GetInt(); mOfflinePacketCount = pk.GetShort(); mOfflinePacketSize = pk.GetShort(); System.Console.WriteLine("[PenCommCore] offline file transfer is started ( name : " + mOfflineFileName + ", size : " + mOfflineFileSize + ", packet_qty : " + mOfflinePacketCount + ", packet_size : " + mOfflinePacketSize + " )"); mOfflineDataBuilder = null; mOfflineDataBuilder = new OfflineDataSerializer(mOfflineFileName, mOfflinePacketCount, mOfflineFileName.Contains(".zip") ? true : false); SendOfflineInfoResponse(); break; // 오프라인 파일 조각 전송 case Cmd.A_OfflineChunk: int index = pk.GetShort(); // 체크섬 필드 byte cs = pk.GetByte(); // 체크섬 계산 byte calcChecksum = pk.GetChecksum(); // 오프라인 데이터 byte[] data = pk.GetBytes(); // 체크섬이 틀리거나, 카운트, 사이즈 정보가 맞지 않으면 버린다. if (cs == calcChecksum && mOfflinePacketCount > index && mOfflinePacketSize >= data.Length) { mOfflineDataBuilder.Put(data, index); // 만약 Chunk를 다 받았다면 offline data를 처리한다. if (mOfflinePacketCount == mOfflineDataBuilder.chunks.Count) { string output = mOfflineDataBuilder.MakeFile(); if (output != null) { SendOfflineChunkResponse((short)index); mOfflineworker.onCreateFile(mOfflineDataBuilder.sectionId, mOfflineDataBuilder.ownerId, mOfflineDataBuilder.noteId, output); } mOfflineDataBuilder = null; } else { SendOfflineChunkResponse((short)index); } mOfflineRcvDataSize += data.Length; if (mOfflineTotalDataSize > 0) { System.Console.WriteLine("[PenCommCore] mOfflineRcvDataSize : " + mOfflineRcvDataSize); Callback.onUpdateOfflineDownload(this, mOfflineTotalDataSize, mOfflineRcvDataSize); } } else { System.Console.WriteLine("[PenCommCore] offline data file verification failed ( index : " + index + " )"); } break; case Cmd.A_UsingNoteNotifyResponse: { bool accepted = pk.GetByteToInt() == 0x01; Callback.onAvailableNoteAccepted(this, accepted); } break; case Cmd.A_OfflineNoteListResponse: { int status = pk.GetByteToInt(); byte[] rxb = pk.GetBytes(4); int section = (int)(rxb[3] & 0xFF); int owner = ByteConverter.ByteToInt(new byte[] { rxb[0], rxb[1], rxb[2], (byte)0x00 }); int noteCnt = pk.GetByteToInt(); for (int i = 0; i < noteCnt; i++) { int note = pk.GetInt(); mOfflineNotes.Add(new OfflineDataInfo(section, owner, note)); } if (status == 0x01) { OfflineDataInfo[] array = mOfflineNotes.ToArray(); Callback.onOfflineDataList(this, array); mOfflineNotes.Clear(); } else { Callback.onOfflineDataList(this, new OfflineDataInfo[0]); } } break; case Cmd.A_OfflineDataRemoveResponse: //System.Console.WriteLine( "[PenCommCore] CMD.A_OfflineDataRemoveResponse" ); break; case Cmd.A_PasswordRequest: { int countRetry = pk.GetByteToInt(); int countReset = pk.GetByteToInt(); System.Console.WriteLine("[PenCommCore] A_PasswordRequest ( " + countRetry + " / " + countReset + " )"); if (needToInputDefaultPassword) { _ReqInputPassword(DEFAULT_PASSWORD); needToInputDefaultPassword = false; } else { Callback.onPenPasswordRequest(this, countRetry, countReset); } } break; case Cmd.A_PasswordSetResponse: { int setResult = pk.GetByteToInt(); //System.Console.WriteLine( "[PenCommCore] A_PasswordSetResponse => " + setResult ); if (setResult == 0x00) { needToInputDefaultPassword = true; } Callback.onPenPasswordSetUpResponse(this, setResult == 0x00 ? true : false); } break; case Cmd.A_PenSensitivityResponse: case Cmd.A_AutoShutdownTimeResponse: case Cmd.A_AutoPowerOnResponse: case Cmd.A_BeepSetResponse: case Cmd.A_PenColorSetResponse: case Cmd.A_HoverOnOffResponse: ResPenSetup((Cmd)pk.Cmd, pk.GetByteToInt() == 0x01); break; case Cmd.A_PenSWUpgradeRequest: short idx = pk.GetShort(); ResponseChunkRequest(idx); break; case Cmd.A_PenSWUpgradeStatus: { int upgStatus = pk.GetByteToInt(); if (upgStatus == 0x02) { return; } Callback.onReceivedFirmwareUpdateResult(this, upgStatus == 0x01); mFwChunk = null; } break; } }
private void ParseBody(int penMaxForce) { mDots.Clear(); long penDownTime = 0, penUpTime = 0, prevTimestamp = 0; int dotTotalCount = 0, dotCount = 0; byte lineCheckSum = 0; int dotStartIndex = 0, dotSize = 0; byte[] lineColorBytes = new byte[4]; int lineColor = 0x000000; // 현재 라인의 도트 offlineDots = new List <Dot>(); int i = 0; while (i < mBody.Length && mBody.Length > 0) { if (ByteConverter.SingleByteToInt(mBody[i]) == LINE_MARK_1 && ByteConverter.SingleByteToInt(mBody[i + 1]) == LINE_MARK_2) { offlineDots = new List <Dot>(); penDownTime = ByteConverter.ByteToLong(CopyOfRange(mBody, i + 2, 8)); penUpTime = ByteConverter.ByteToLong(CopyOfRange(mBody, i + 10, 8)); dotTotalCount = ByteConverter.ByteToInt(CopyOfRange(mBody, i + 18, 4)); lineColorBytes = CopyOfRange(mBody, i + 23, 4); lineColor = ByteConverter.ByteToInt(new byte[] { lineColorBytes[2], lineColorBytes[1], lineColorBytes[0], (byte)0 }); //System.Console.WriteLine( "[OfflineDataParser] penDownTime : {0}, penUpTime : {1}, dotTotalCount : {2}, lineColor : {3}", penDownTime, penUpTime, dotTotalCount, lineColor ); lineCheckSum = mBody[i + 27]; i += BYTE_LINE_SIZE; dotStartIndex = i; dotSize = 0; dotCount = 0; } else { dotCount++; // 스트로크 헤더에 정의된 도트갯수보다 넘어가면 LN이 나올때까지 한바이트씩 포인터를 이동한다. if (dotCount > dotTotalCount) { i++; continue; } long timeGap = ByteConverter.SingleByteToInt(mBody[i]); short x = ByteConverter.ByteToShort(CopyOfRange(mBody, i + 1, 2)); short y = ByteConverter.ByteToShort(CopyOfRange(mBody, i + 3, 2)); int fx = ByteConverter.SingleByteToInt(mBody[i + 5]); int fy = ByteConverter.SingleByteToInt(mBody[i + 6]); int force = ByteConverter.SingleByteToInt(mBody[i + 7]); int color = lineColor; bool isPenUp = false; long timestamp = -1L; DotTypes dotType; if (dotSize == 0) { dotType = DotTypes.PEN_DOWN; timestamp = penDownTime + timeGap; prevTimestamp = timestamp; } else if (dotTotalCount > dotCount) { dotType = DotTypes.PEN_MOVE; timestamp = prevTimestamp + timeGap; prevTimestamp = timestamp; } else { dotType = DotTypes.PEN_UP; timestamp = penUpTime; isPenUp = true; } Dot.Builder builder; if (penMaxForce == 0) { builder = new Dot.Builder(); } else { builder = new Dot.Builder(penMaxForce); } offlineFilterForPaper.Put( builder .section(mSectionId) .owner(mOwnerId) .note(mNoteId) .page(mPageId) .coord(x + fx * 0.01f, y + fy * 0.01f) .force(force) .color(color) .timestamp(timestamp) .dotType(dotType).Build(), null ); dotSize += 8; if (isPenUp) { byte dotCalcCs = CalcChecksum(CopyOfRange(mBody, dotStartIndex, dotSize)); if (dotCalcCs == lineCheckSum) { for (int j = 0; j < offlineDots.Count; j++) { mDots.Add(offlineDots[j]); } } else { Debug.WriteLine("[OfflineDataParser] invalid CheckSum cs : " + lineCheckSum + ", calc : " + dotCalcCs); } offlineDots = new List <Dot>(); } i += BYTE_DOT_SIZE; } } }
public void ParsePacket(Packet packet) { //Debug.WriteLine("[PenCommCore] ParsePacket : " + packet.Cmd); switch ((Cmd)packet.Cmd) { case Cmd.A_DotData: { long time = packet.GetByteToInt(); int x = packet.GetShort(); int y = packet.GetShort(); int fx = packet.GetByteToInt(); int fy = packet.GetByteToInt(); int force = packet.GetByteToInt(); long timeLong = mPrevDotTime + time; if (!IsStartWithDown || timeLong < 10000) { Debug.WriteLine("[PenCommCore] this stroke start with middle dot."); return; } if (IsPrevDotDown) { // 펜업의 경우 시작 도트로 저장 IsPrevDotDown = false; ProcessDot(mOwnerId, mSectionId, mNoteId, mPageId, timeLong, x, y, fx, fy, force, DotTypes.PEN_DOWN, mCurrentColor); } else { // 펜업이 아닌 경우 미들 도트로 저장 ProcessDot(mOwnerId, mSectionId, mNoteId, mPageId, timeLong, x, y, fx, fy, force, DotTypes.PEN_MOVE, mCurrentColor); } mPrevDotTime = timeLong; mPrevPacket = packet; } break; case Cmd.A_DotUpDownDataNew: case Cmd.A_DotUpDownData: { // TODO Check long updownTime = packet.GetLong(); int updown = packet.GetByteToInt(); byte[] cbyte = packet.GetBytes(3); mCurrentColor = ByteConverter.ByteToInt(new byte[] { cbyte[2], cbyte[1], cbyte[0], (byte)0 }); if (updown == 0x00) { // 펜 다운 일 경우 Start Dot의 timestamp 설정 mPrevDotTime = updownTime; IsPrevDotDown = true; IsStartWithDown = true; //Callback.onUpDown(this, false); } else if (updown == 0x01) { if (mPrevPacket != null) { mPrevPacket.Reset(); // 펜 업 일 경우 바로 이전 도트를 End Dot로 삽입 int time = mPrevPacket.GetByteToInt(); int x = mPrevPacket.GetShort(); int y = mPrevPacket.GetShort(); int fx = mPrevPacket.GetByteToInt(); int fy = mPrevPacket.GetByteToInt(); int force = mPrevPacket.GetByteToInt(); ProcessDot(mOwnerId, mSectionId, mNoteId, mPageId, updownTime, x, y, fx, fy, force, DotTypes.PEN_UP, mCurrentColor); } //Callback.onUpDown(this, true); IsStartWithDown = false; } mPrevPacket = null; } break; case Cmd.A_DotIDChange: byte[] rb = packet.GetBytes(4); mSectionId = (int)(rb[3] & 0xFF); mOwnerId = ByteConverter.ByteToInt(new byte[] { rb[0], rb[1], rb[2], (byte)0x00 }); mNoteId = packet.GetInt(); mPageId = packet.GetInt(); break; case Cmd.A_PenOnState: packet.Move(8); int STATUS = packet.GetByteToInt(); int FORCE_MAX = packet.GetByteToInt(); string SW_VER = packet.GetString(5); if (STATUS == 0x00) { SendPenOnOffData(); } else if (STATUS == 0x01) { Reset(); SendPenOnOffData(); SendRTCData(); PenController.onConnected(new ConnectedEventArgs(SW_VER, FORCE_MAX)); PenMaxForce = FORCE_MAX; mOfflineworker.PenMaxForce = FORCE_MAX; } break; case Cmd.A_RTCsetResponse: break; case Cmd.A_PenStatusResponse: if (!Authenticated) { Authenticated = true; PenController.onPenAuthenticated(); } packet.Move(2); int stat_timezone = packet.GetInt(); long stat_timetick = packet.GetLong(); int stat_forcemax = packet.GetByteToInt(); int stat_battery = packet.GetByteToInt(); int stat_usedmem = packet.GetByteToInt(); int stat_pencolor = packet.GetInt(); bool stat_autopower = packet.GetByteToInt() == 2 ? false : true; bool stat_accel = packet.GetByteToInt() == 2 ? false : true; bool stat_hovermode = packet.GetByteToInt() == 2 ? false : true; bool stat_beep = packet.GetByteToInt() == 2 ? false : true; short stat_autoshutdowntime = packet.GetShort(); short stat_pensensitivity = packet.GetShort(); PenController.onReceivePenStatus(new PenStatusReceivedEventArgs(stat_timezone, stat_timetick, stat_forcemax, stat_battery, stat_usedmem, stat_pencolor, stat_autopower, stat_accel, stat_hovermode, stat_beep, stat_autoshutdowntime, stat_pensensitivity)); break; // 오프라인 데이터 크기,갯수 전송 case Cmd.A_OfflineDataInfo: mOfflineTotalFileCount = packet.GetInt(); mOfflineTotalDataSize = packet.GetInt(); Debug.WriteLine("[PenCommCore] A_OfflineDataInfo : {0}, {1}", mOfflineTotalFileCount, mOfflineTotalDataSize); PenController.onStartOfflineDownload(); IsStartOfflineTask = true; break; // 오프라인 전송 최종 결과 응답 case Cmd.A_OfflineResultResponse: int result = packet.GetByteToInt(); //System.Console.WriteLine( "[PenCommCore] A_OfflineDataResponse : {0}", result ); IsStartOfflineTask = false; PenController.onFinishedOfflineDownload(new SimpleResultEventArgs(result == 0x00)); mOfflineworker.onFinishDownload(); break; // 오프라인 파일 정보 case Cmd.A_OfflineFileInfo: mOfflineFileName = packet.GetString(128); mOfflineFileSize = packet.GetInt(); mOfflinePacketCount = packet.GetShort(); mOfflinePacketSize = packet.GetShort(); Debug.WriteLine("[PenCommCore] offline file transfer is started ( name : " + mOfflineFileName + ", size : " + mOfflineFileSize + ", packet_qty : " + mOfflinePacketCount + ", packet_size : " + mOfflinePacketSize + " )"); mOfflineDataBuilder = null; mOfflineDataBuilder = new OfflineDataSerializer(mOfflineFileName, mOfflinePacketCount, mOfflineFileName.Contains(".zip") ? true : false); SendOfflineInfoResponse(); break; // 오프라인 파일 조각 전송 case Cmd.A_OfflineChunk: int index = packet.GetShort(); // 체크섬 필드 byte cs = packet.GetByte(); // 체크섬 계산 byte calcChecksum = packet.GetChecksum(); // 오프라인 데이터 byte[] data = packet.GetBytes(); // 체크섬이 틀리거나, 카운트, 사이즈 정보가 맞지 않으면 버린다. if (cs == calcChecksum && mOfflinePacketCount > index && mOfflinePacketSize >= data.Length) { mOfflineDataBuilder.Put(data, index); // 만약 Chunk를 다 받았다면 offline data를 처리한다. if (mOfflinePacketCount == mOfflineDataBuilder.chunks.Count) { string output = mOfflineDataBuilder.MakeFile(); if (output != null) { SendOfflineChunkResponse((short)index); mOfflineworker.onCreateFile(mOfflineDataBuilder.sectionId, mOfflineDataBuilder.ownerId, mOfflineDataBuilder.noteId, output, mOfflineTotalDataSize, mOfflineRcvDataSize); } mOfflineDataBuilder = null; } else { SendOfflineChunkResponse((short)index); } mOfflineRcvDataSize += data.Length; // TODO Check //if (mOfflineTotalDataSize > 0) //{ // Debug.WriteLine("[PenCommCore] mOfflineRcvDataSize : " + mOfflineRcvDataSize); // //Callback.onUpdateOfflineDownload(this, mOfflineTotalDataSize, mOfflineRcvDataSize); //} } else { Debug.WriteLine("[PenCommCore] offline data file verification failed ( index : " + index + " )"); } break; case Cmd.A_UsingNoteNotifyResponse: PenController.onAvailableNoteAdded(); break; case Cmd.A_OfflineNoteListResponse: { int status = packet.GetByteToInt(); byte[] rxb = packet.GetBytes(4); int section = (int)(rxb[3] & 0xFF); int owner = ByteConverter.ByteToInt(new byte[] { rxb[0], rxb[1], rxb[2], (byte)0x00 }); int noteCnt = packet.GetByteToInt(); for (int i = 0; i < noteCnt; i++) { int note = packet.GetInt(); mOfflineNotes.Add(new OfflineDataInfo(section, owner, note)); } if (status == 0x01) { OfflineDataInfo[] array = mOfflineNotes.ToArray(); PenController.onReceiveOfflineDataList(new OfflineDataListReceivedEventArgs(array)); mOfflineNotes.Clear(); } else { PenController.onReceiveOfflineDataList(new OfflineDataListReceivedEventArgs(new OfflineDataInfo[0])); } } break; case Cmd.A_OfflineDataRemoveResponse: //System.Console.WriteLine( "[PenCommCore] CMD.A_OfflineDataRemoveResponse" ); break; case Cmd.A_PasswordRequest: { int countRetry = packet.GetByteToInt(); int countReset = packet.GetByteToInt(); Debug.WriteLine("[PenCommCore] A_PasswordRequest ( " + countRetry + " / " + countReset + " )"); PenController.onPenPasswordRequest(new PasswordRequestedEventArgs(countRetry, countReset)); } break; case Cmd.A_PasswordSetResponse: { int setResult = packet.GetByteToInt(); //System.Console.WriteLine( "[PenCommCore] A_PasswordSetResponse => " + setResult ); PenController.onPenPasswordSetupResponse(new SimpleResultEventArgs(setResult == 0x00)); } break; case Cmd.A_PenSensitivityResponse: case Cmd.A_AutoShutdownTimeResponse: case Cmd.A_AutoPowerOnResponse: case Cmd.A_BeepSetResponse: case Cmd.A_PenColorSetResponse: ResPenSetup((Cmd)packet.Cmd, packet.GetByteToInt() == 0x01); break; case Cmd.A_PenSWUpgradeRequest: short idx = packet.GetShort(); Debug.WriteLine("[PenCommCore] A_PenSWUpgradeRequest => " + idx); ResponseChunkRequest(idx); break; case Cmd.A_PenSWUpgradeStatus: { int upgStatus = packet.GetByteToInt(); if (upgStatus == 0x02) { return; } PenController.onReceiveFirmwareUpdateResult(new SimpleResultEventArgs(upgStatus == 0x01)); mFwChunk = null; } break; } }
public void ParsePacket(Packet packet) { Cmd cmd = (Cmd)packet.Cmd; //Debug.Write("Cmd : {0}", cmd.ToString()); switch (cmd) { case Cmd.VERSION_RESPONSE: { DeviceName = packet.GetString(16); FirmwareVersion = packet.GetString(16); ProtocolVersion = packet.GetString(8); SubName = packet.GetString(16); DeviceType = packet.GetShort(); MaxForce = -1; MacAddress = BitConverter.ToString(packet.GetBytes(6)).Replace("-", ""); IsUploading = false; ReqPenStatus(); } break; #region event case Cmd.SHUTDOWN_EVENT: { byte reason = packet.GetByte(); Debug.Write(" => SHUTDOWN_EVENT : {0}", reason.ToString()); } break; case Cmd.LOW_BATTERY_EVENT: { int battery = (int)(packet.GetByte() & 0xff); PenController.onReceiveBatteryAlarm(new BatteryAlarmReceivedEventArgs(battery)); } break; case Cmd.ONLINE_PEN_UPDOWN_EVENT: case Cmd.ONLINE_PEN_DOT_EVENT: case Cmd.ONLINE_PAPER_INFO_EVENT: { ParseDotPacket(cmd, packet); } break; #endregion #region setting response case Cmd.SETTING_INFO_RESPONSE: { // 비밀번호 사용 여부 bool lockyn = packet.GetByteToInt() == 1; // 비밀번호 입력 최대 시도 횟수 int pwdMaxRetryCount = packet.GetByteToInt(); // 비밀번호 입력 시도 횟수 int pwdRetryCount = packet.GetByteToInt(); // 1970년 1월 1일부터 millisecond tick long time = packet.GetLong(); // 사용하지 않을때 자동으로 전원이 종료되는 시간 (단위:분) short autoPowerOffTime = packet.GetShort(); // 최대 필압 short maxForce = packet.GetShort(); // 현재 메모리 사용량 int usedStorage = packet.GetByteToInt(); // 펜의 뚜껑을 닫아서 펜의 전원을 차단하는 기능 사용 여부 bool penCapOff = packet.GetByteToInt() == 1; // 전원이 꺼진 펜에 필기를 시작하면 자동으로 펜의 켜지는 옵션 사용 여부 bool autoPowerON = packet.GetByteToInt() == 1; // 사운드 사용여부 bool beep = packet.GetByteToInt() == 1; // 호버기능 사용여부 bool hover = packet.GetByteToInt() == 1; // 남은 배터리 수치 int batteryLeft = packet.GetByteToInt(); // 오프라인 데이터 저장 기능 사용 여부 bool useOffline = packet.GetByteToInt() == 1; // 필압 단계 설정 (0~4) 0이 가장 민감 short fsrStep = (short)packet.GetByteToInt(); // 최초 연결시 if (MaxForce == -1) { MaxForce = maxForce; var connectedEventArgs = new ConnectedEventArgs(); PenController.onConnected(new ConnectedEventArgs(MacAddress, DeviceName, FirmwareVersion, ProtocolVersion, SubName, MaxForce)); PenMaxForce = MaxForce; if (lockyn) { // TODO 여기서 부터 시작 PenController.onPenPasswordRequest(new PasswordRequestedEventArgs(pwdRetryCount, pwdMaxRetryCount)); } else { PenController.onPenAuthenticated(); } } else { PenController.onReceivePenStatus(new PenStatusReceivedEventArgs(lockyn, pwdMaxRetryCount, pwdRetryCount, time, autoPowerOffTime, MaxForce, batteryLeft, usedStorage, useOffline, autoPowerON, penCapOff, hover, beep, fsrStep)); } } break; case Cmd.SETTING_CHANGE_RESPONSE: { int inttype = packet.GetByteToInt(); SettingType stype = (SettingType)inttype; bool result = packet.Result == 0x00; switch (stype) { case SettingType.AutoPowerOffTime: PenController.onPenAutoShutdownTimeSetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.AutoPowerOn: PenController.onPenAutoPowerOnSetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.Beep: PenController.onPenBeepSetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.Hover: PenController.onPenHoverSetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.LedColor: PenController.onPenColorSetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.OfflineData: PenController.onPenOfflineDataSetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.PenCapOff: PenController.onPenCapPowerOnOffSetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.Sensitivity: PenController.onPenSensitivitySetupResponse(new SimpleResultEventArgs(result)); break; case SettingType.Timestamp: PenController.onPenTimestampSetupResponse(new SimpleResultEventArgs(result)); break; } } break; #endregion #region password response case Cmd.PASSWORD_RESPONSE: { int status = packet.GetByteToInt(); int cntRetry = packet.GetByteToInt(); int cntMax = packet.GetByteToInt(); if (status == 0) { PenController.onPenPasswordRequest(new PasswordRequestedEventArgs(cntRetry, cntMax)); } else { PenController.onPenAuthenticated(); } } break; case Cmd.PASSWORD_CHANGE_RESPONSE: { int cntRetry = packet.GetByteToInt(); int cntMax = packet.GetByteToInt(); PenController.onPenPasswordSetupResponse(new SimpleResultEventArgs(packet.Result == 0x00)); } break; #endregion #region offline response case Cmd.OFFLINE_NOTE_LIST_RESPONSE: { short length = packet.GetShort(); List <OfflineDataInfo> result = new List <OfflineDataInfo>(); for (int i = 0; i < length; i++) { byte[] rb = packet.GetBytes(4); int section = (int)(rb[3] & 0xFF); int owner = ByteConverter.ByteToInt(new byte[] { rb[0], rb[1], rb[2], (byte)0x00 }); int note = packet.GetInt(); result.Add(new OfflineDataInfo(section, owner, note)); } PenController.onReceiveOfflineDataList(new OfflineDataListReceivedEventArgs(result.ToArray())); } break; case Cmd.OFFLINE_PAGE_LIST_RESPONSE: { byte[] rb = packet.GetBytes(4); int section = (int)(rb[3] & 0xFF); int owner = ByteConverter.ByteToInt(new byte[] { rb[0], rb[1], rb[2], (byte)0x00 }); int note = packet.GetInt(); short length = packet.GetShort(); int[] pages = new int[length]; for (int i = 0; i < length; i++) { pages[i] = packet.GetInt(); } OfflineDataInfo info = new OfflineDataInfo(section, owner, note); PenController.onReceiveOfflineDataList(new OfflineDataListReceivedEventArgs(info)); } break; case Cmd.OFFLINE_DATA_RESPONSE: { mTotalOfflineStroke = packet.GetInt(); mReceivedOfflineStroke = 0; mTotalOfflineDataSize = packet.GetInt(); bool isCompressed = packet.GetByte() == 1; PenController.onStartOfflineDownload(); } break; case Cmd.OFFLINE_PACKET_REQUEST: { #region offline data parsing List <Stroke> result = new List <Stroke>(); short packetId = packet.GetShort(); bool isCompressed = packet.GetByte() == 1; short sizeBefore = packet.GetShort(); short sizeAfter = packet.GetShort(); short location = (short)(packet.GetByte() & 0xFF); byte[] rb = packet.GetBytes(4); int section = (int)(rb[3] & 0xFF); int owner = ByteConverter.ByteToInt(new byte[] { rb[0], rb[1], rb[2], (byte)0x00 }); int note = packet.GetInt(); short strCount = packet.GetShort(); mReceivedOfflineStroke += strCount; Debug.WriteLine(" packetId : {0}, isCompressed : {1}, sizeBefore : {2}, sizeAfter : {3}, size : {4}", packetId, isCompressed, sizeBefore, sizeAfter, packet.Data.Length - 18); if (sizeAfter != (packet.Data.Length - 18)) { SendOfflinePacketResponse(packetId, false); return; } byte[] oData = packet.GetBytes(sizeAfter); GZipStream gzipStream = new GZipStream(new System.IO.MemoryStream(oData), CompressionLevel.Fastest); byte[] strData = Ionic.Zlib.ZlibStream.UncompressBuffer(oData); if (strData.Length != sizeBefore) { SendOfflinePacketResponse(packetId, false); return; } ByteUtil butil = new ByteUtil(strData); for (int i = 0; i < strCount; i++) { int pageId = butil.GetInt(); long timeStart = butil.GetLong(); long timeEnd = butil.GetLong(); int penTipType = (int)(butil.GetByte() & 0xFF); int color = butil.GetInt(); short dotCount = butil.GetShort(); long time = timeStart; //System.Console.WriteLine( "pageId : {0}, timeStart : {1}, timeEnd : {2}, penTipType : {3}, color : {4}, dotCount : {5}, time : {6},", pageId, timeStart, timeEnd, penTipType, color, dotCount, time ); Stroke stroke = new Stroke(section, owner, note, pageId); for (int j = 0; j < dotCount; j++) { byte dotChecksum = butil.GetChecksum(15); int timeadd = butil.GetByte(); time += timeadd; int force = butil.GetShort(); int x = butil.GetShort(); int y = butil.GetShort(); int fx = butil.GetByte(); int fy = butil.GetByte(); int tx = butil.GetByte(); int ty = butil.GetByte(); int twist = butil.GetShort(); short reserved = butil.GetShort(); byte checksum = butil.GetByte(); //System.Console.WriteLine( "x : {0}, y : {1}, force : {2}, checksum : {3}, dotChecksum : {4}", tx, ty, twist, checksum, dotChecksum ); if (dotChecksum != checksum) { SendOfflinePacketResponse(packetId, false); result.Clear(); return; } DotTypes dotType; if (j == 0) { dotType = DotTypes.PEN_DOWN; } else if (j == dotCount - 1) { dotType = DotTypes.PEN_UP; } else { dotType = DotTypes.PEN_MOVE; } stroke.Add(MakeDot(PenMaxForce, owner, section, note, pageId, time, x, y, fx, fy, force, dotType, color)); } result.Add(stroke); } SendOfflinePacketResponse(packetId); PenController.onReceiveOfflineStrokes(new OfflineStrokeReceivedEventArgs(mTotalOfflineStroke, mReceivedOfflineStroke, result.ToArray())); if (location == 2) { PenController.onFinishedOfflineDownload(new SimpleResultEventArgs(true)); } #endregion } break; case Cmd.OFFLINE_DATA_DELETE_RESPONSE: { PenController.onRemovedOfflineData(new SimpleResultEventArgs(packet.Result == 0x00)); } break; #endregion #region firmware response case Cmd.FIRMWARE_UPLOAD_RESPONSE: { if (packet.Result != 0 || packet.GetByteToInt() != 0) { IsUploading = false; PenController.onReceiveFirmwareUpdateResult(new SimpleResultEventArgs(false)); } } break; case Cmd.FIRMWARE_PACKET_REQUEST: { int status = packet.GetByteToInt(); int offset = packet.GetInt(); ResponseChunkRequest(offset, status != 3); } break; #endregion case Cmd.ONLINE_DATA_RESPONSE: break; default: break; } }