안경잡이개발자

728x90
반응형

  ※ 본 글은 2021년 05월 31일 기준으로 업데이트되었습니다. 또한 이 글은 2020년, 2021년 두 차례에 걸쳐 업데이트 되어서 내용이 다소 섞여 있습니다. 저는 세무 전문가가 아니므로 참고용으로만 보세요.

 

  종합소득세를 납부하려면 홈택스(Hometax)에 가야 합니다.

 

  ▶ 홈택스https://www.hometax.go.kr/

 

  매년 5월은 종합소득세 신고 기간이니까, 이 기간에 작년의 수입에 대해서 종합소득세를 신고해야 합니다. 일반적으로 신고해야 하는 소득의 종류로는 기타소득, 근로소득, 사업소득 등이 있습니다. 저의 경우 대학원생이면서 유튜버이고, 이전에 사기업에서 강의 활동을 한 적도 있습니다. 그래서 저는 다음과 같이 3가지 종류의 소득을 납부해야 합니다. 아마 일반적인 대학원생이라면 '대학원 인건비'에 해당하는 기타소득만 신고할 겁니다.

 

  ▶ 기타소득: 대학원 월급이 있습니다. (feat. 유튜브/블로그 광고 수익)

  ▶ 근로소득: 대학원 입학 전에 회사에서 근로한 적이 있습니다.

  ▶ 사업소득: 사기업에서 강의 활동을 한 적이 있어서, 강의료를 받은 게 있습니다. (feat. 유튜브/블로그 광고 수익)

 

  참고로 방송을 하시는 분들은 투네이션 수입이 있을 수 있는데, 투네이션(Toonation) 수익은 '사업소득'에 들어가는 것으로 알려져 있습니다.

 

  이제 한 번 종합소득세 납부를 해보겠습니다. 기본적으로 종합소득세를 신고하기 위해서는 가장 먼저 로그인을 해주셔야 합니다. 이때 가능하면 [공인인증서 로그인]을 통해 로그인을 해주세요. 인증서 없이 일반 아이디 로그인을 하는 경우, 신고 과정에서 오류를 만나는 경우가 있습니다.

 

 

  기본적으로 로그인 이후에는 지급명세서부터 확인하도록 합니다. [My 홈택스] 탭으로 이동한 뒤에, [지급명세서 등 지출내역] 링크를 들어가서 내용을 확인합니다. 2020년 기준으로 화면은 다음과 같습니다.

 

 

  2021년에는 다음과 같이 화면 UI가 바뀌었네요.

 

 

  자신이 지급을 받은 내역이 여기에서 나열되는데요. 일단 '지급명세서'에 나와 있는 내용은 기본적으로 당연히 소득세로 신고해야 한다고 보시면 됩니다. (단, 2019년 기준 일용 근로자의 경우 평균 일급이 약 187,000원 미만일 때는 소득세를 납부하지 않아도 됩니다. 이처럼 지급명세서에 나와 있지만, 소득세로 신고하지 않아도 되는 경우도 있으므로, 잘 확인하시는 것이 중요합니다. 물론 기본적으로 대학원 월급, 강사 활동과 같은 활동은 거의 다 소득세 신고가 필요하다고 보시면 됩니다.)

 

  아무튼 현재 2020년 5월이므로, 저는 다음과 같이 2019년에 있었던 모든 소득에 대해서 신고를 해야 합니다.

 

 

  이 중에서 한 번 예시로 대학원생 인건비 (기타소득)을 확인해 보도록 하겠습니다. [보기] 버튼을 눌러줍니다.

 

 

  그러면 다음과 같이 지급을 받았던 금액이 나오게 됩니다. 참고로 오른쪽에 있는 "원천징수 세액"의 경우에는, 이미 제가 다니고 있는 대학원 측에서 국가에 납부한 세금(기납부세액)이라고 보시면 됩니다. 우리가 만약에 내야 할 결정세액이 적다면, 이 원천징수 금액에 따라서 돈을 환급받을 수 있는 겁니다. 일반적으로 기타소득만 존재하는 대학원생들은 이러한 원천징수 금액을 환급받게 됩니다.

 

 

  아무튼 저는 지급명세서상으로만 9개나 존재하네요. 이제 이것들을 신고하러 가야 합니다. 따라서 [신고/납부] 탭에서 [종합소득세] 탭으로 가면 종합소득세를 납부할 수 있습니다.

 

 

  사람들은 자신의 소득 금액, 소득 유형에 따라서 "납부 유형"이 나누어집니다. 기본적으로 자신의 납부 유형을 알기 위해서는 [신고도움 서비스]를 누르시면 됩니다.

 

 

  그러면 다음과 같이 납부 유형을 알려 줄 겁니다. 참고로 여기에서 '추계신고'라는 단어가 있는데요.  추계신고란 세무 장부를 직접 작성해서 사업 비용을 계산하는 게 아니라, 업종별로 경비율을 적용해서 특정 비율만큼 총 수입금액에서 비용을 추정하여 계산하는 것을 말합니다. 저도 장부 등을 작성할 시간이 없어서, 추계신고를 고려했던 적이 있습니다. (다만 저는 2020년에는 단순경비율이었으나, 2021년에는 기준경비율로 신고했습니다.)

 

  ※ 2020년 - 단순경비율 ※

 

  필자의 경우 2020년에는 단순경비율이었습니다. 일정 금액 이하로 돈을 번 경우 단순경비율을 적용하여 경비를 인정받을 수 있습니다.

 

 

  ※ 2021년 - 기준경비율 ※

 

  필자는 2021년에는 기준경비율 적용 대상자가 되었습니다. 필자는 여전히 영세하기 때문에 별도로 장부를 작성하지 않았으며, 추계신고를 고려해야하는 상황이었습니다. (참고로 기준경비율은 단순경비율에 비하여 추계신고 시 경비율이 낮기 때문에, 기준경비율 적용대상자부터는 경비를 인정받기 위한 서류상의 노력 작업이 많이 필요합니다. 거의 60% 정도에 가까운 경비율이 20%로 떨어지는 일이 흔하게 벌어집니다. 그러면 당연히 실질적으로 소득이 많이 잡혀서 세금이 매우 증가할 수 있겠죠? 그래서 결과적으로는 세무사 님께 문의를 했습니다. 단순경비율의 경우에는 유튜브를 보면서 따라하는 게 나을 수 있으나, 기준경비율부터는 세무사를 이용하는 것을 추천합니다.)

 

 

  또한 2021년의 경우에는 [신고시 유의할 사항] 항목이 추가되어 다음과 같은 내용이 들어가 있습니다. 유튜브를 통해 얻은 수익이 있기 때문에, 구글(Google)로부터 외화를 수취한 사실이 있다고 나오는 것을 확인할 수 있습니다.

 

 

  또한 필자의 경우 사업소득 외에도 기타소득이 존재하기 때문에, 다음과 같이 기타소득도 존재한다는 내용도 같이 출력되는 것을 알 수 있습니다.

 

 

  유튜버나 대학원생은 기본적으로 대부분 [일반신고서]로 신고를 하시게 될 거예요. 저 역시 유튜버이면서 대학원생이기 때문에 [일반신고서]로 신고를 해야 합니다. 2021년 기준으로 다음과 같은 화면이 나옵니다.

 

 

  기본적으로 [기본사항]부터 입력하게 됩니다. 그래서 [조회] 버튼을 누른 뒤에 조회된 정보를 확인하시면 됩니다.

 

 

  [조회] 버튼을 눌렀을 때, 작년 1년간의 소득 정보에 따라서 자동으로 다음과 같이 소득을 선택하도록 안내가 제시됩니다. 사업소득의 경우 바로 수입 금액이 얼마인지 나오는 것을 확인할 수 있습니다.

 

 

  저는 사업소득이 있기 때문에 다음과 같이 추가적으로 사업장을 명세하라는 내용이 나옵니다. 저는 강의 활동을 했기 때문에, 업종코드가 940909로 나오고, 이 경우 사업자 등록번호 [없음]을 선택합니다. (앞서 말씀드렸듯이, 방송을 하시는 분이라면 투네이션 수익도 '사업소득'으로 잡히게 됩니다. 물론 저는 해당사항 없습니다.)

 

 

  그러면 다음과 같이 등록할 수 있습니다. 버는 금액이 많지 않으면, [간편장부대상자] 이면서 [단순경비율]이 적용됩니다. (필자는 2020년과 달리 2021년에는 소득이 더 생겨 [기준경비율]을 선택했습니다.)

 

 

  저는 아무튼 결과적으로, 맨 처음 말씀드렸듯이 다음과 같이 세 개의 소득 종류가 있습니다.

 

  ▶ 부동산임대업외의 사업소득: 사기업 강의료

  ▶ 근로소득: 회사 생활

  ▶ 기타소득: 유튜브, 대학원 인건비

 

  드디어 기본사항 명시가 완료되었네요. 이제 다음으로 넘어가면 됩니다.

 

 

  기본적인 내용들은 그냥 다 정보를 [불러오기] 이후에 [확인]하는 식으로 그냥 반복하면 된다고 보시면 됩니다. 생각보다 복잡하지 않습니다. 일단 하나씩 따라가면 됩니다.

 

※ 2020년 - 단순경비율 사업소득금액명세서 ※

 

  이제 사업소득 명세를 해야 하는데요. 일단 2020년에는 단순경비율이 적용되는 사업소득이 있었습니다. [업종별 총수입금액 및 소득금액 계산]을 누릅니다. (실제로 많은 경우, 강의료는 사업소득으로 잡히게 됩니다. 혹은 기타소득입니다.)

 

 

  이후에 직접 "총수입금액"을 적어주셔야 합니다. 혹시 방송을 하시는 분들 중에서 투네이션을 받으시는 분은 기본적으로 사업소득으로 잘힐 테니까, 여기에 넣어주셔야 합니다. 저는 투네이션은 아니고, 사기업에서 강의했던 금액이 사업소득으로 잡힌 금액을 모두 넣어주었습니다.

 

 

  이제 사업소득 금액 명세가 완료되었습니다. 넘어가겠습니다.

 

 

※ 2020년 - 기준경비율 사업소득금액명세서 ※

 

  2020년에는 기준경비율이 적용되었으며, 다음과 같이 업종코드별로 수익금액이 얼마인지 확인하여 정확한 금액을 기입했습니다.

 

 

  참고로 이때 "주요경비"와 같은 경비 요소가 있다면 이를 기입하여 세금을 줄일 수 있습니다. 기준경비율에서 사용되는 주요경비로는 대표적으로 3가지가 있습니다.

 

  ▶ 매입비용: 원료, 전기료, 상품, 제품과 같은 비용을 의미합니다.

  ▶ 임차료: 사업을 위해 사용하는 건축물과 같은 고정자산을 빌려 쓰는 비용을 의미합니다.

  ▶ 인건비: 직원에게 주는 급여와 같은 비용을 의미합니다.

 

  기본적으로 인건비는 지급명세서와 같은 증명 서류가 요구되고, 임차료 또한 세금계산서와 같은 증명 서류가 요구될 수 있습니다. 다만 개인적으로 집에서 유튜브와 같은 플랫폼으로 수익을 얻는 경우에 그 집이 거주 목적으로 임차한 주택이라면, 가사 관련 경비로 보이므로 임차료(필요 경비) 적용이 어려운 경우가 많다고 합니다. 필자 또한 기숙사에 살고 있기 때문에, 임차료는 필요 경비로 넣을 수 없다고 판단하여 비워두었습니다.

 

  이후에 넘어가면, 아까 입력한 사업소득에 대해서 미리 납부한(원천징수한) 세금이 있는지 정보가 나옵니다. 미리 납부한 세금이 있으면, 그만큼은 세금을 내지 않아도 되는 겁니다. 다음과 같이 [사업소득 원천징수내역 불러오기] 버튼을 누른 뒤에 내용을 확인하면 됩니다. (제 2020년 기준 화면은 다음과 같습니다.)

 

 

  이제 이어서 [근로, 기타, 연금소득] 항목을 작성합니다. 어차피 기타 소득이나, 근로 소득 등은 국세청에서 우리의 정보를 알고 있습니다. 그래서 근로, 기타, 연금소득 확인 부분에서는 [근로/연금/기타(종교인)소득 불러오기] 버튼을 누른 다음에 적용하면 됩니다. 간혹 버튼이 안 눌리는경우가 있는데 저의 경우에는 로그아웃 이후에 [공인인증서 로그인]을 하면 버튼이 눌리더라고요. 그러므로 당황하지 마세요.

 

 

※ 애드센스(Adsense)를 기타소득으로 넣는 경우 ※

 

  모든 소득 내역을 불러온 뒤에, 기록되어 있지 않은 내용 중에서 존재하는 소득도 기입해야 합니다. 저자의 경우 유튜브/티스토리 블로그의 애드센스 수익이 있습니다. 따라서 이를 적었습니다. 구글(Google) 애드센스의 경우 사업자 등록번호로 120-86-65164를 입력하면 된다고 합니다. 작년 유튜브 총 수익을 원화 기준으로 입력하면 됩니다. 저자의 경우 2020년에는 애드센스 수익이 매우 적었기 때문에, 단순하게 기타 소득으로 넣었습니다. (이때 당시 경비를 0원으로 넣어서 사실상 어떠한 세금 혜택도 받지 않고, 소득에 따른 세금을 모두 납부했습니다. 아마 사업소득으로 했으면 세금을 더욱 절약할 수 있었을 텐데, 당시에는 그냥 기타소득으로 했습니다.)

 

 

※ 애드센스(Adsense)를 사업소득으로 넣는 경우 ※

 

  필자의 경우 2021년에는 애드센스에 따른 수익이 커짐에 따라서 사업소득으로 넣었습니다. 이때 1인미디어 창작자(940306)는 유튜버와 같이 영상 콘텐츠를 생산하는 사람에게 해당되는 업종코드입니다. 참고로 1인미디어 창작자가 영상 편집자를 쓰고, 사업장과 같은 물리시설을 갖추는 경우에는 과세사업자로 분류됩니다. (국세청 참고 링크) 과세사업자의 경우 미디어 콘텐츠 창작업(921505)가 됩니다.

 

  필자의 경우 영세한 1인 유튜버이므로 업종코드 940306 사업소득을 선택했습니다. 이는 면세사업자로 분류되기 때문에 부가가치세를 신고할 의무는 없습니다. 아무튼, 필자의 경우 업종코드 940306 사업소득으로 유튜브 수익을 넣었습니다. 자세한 내용은 위에 있는 [국세청 참고 링크]에서 확인하세요. (개인적으로는, 규모가 큰 분들은 그냥 세무사를 거쳐서 자세하게 상담하는 것을 추천합니다.)

 

  아무튼 결과적으로 모든 기타 소득, 근로 소득을 반영하면 다음과 같은 모습이 됩니다.

 

 

  이후에 이원결손금 등을 명시하는데, 저의 경우에는 해당이 없습니다.

 

 

  이제 소득공제 명세를 합니다. 가장 먼저 근로소득이 있다면, 이 내용부터 넣게 됩니다. [근로소득(연말정산) 불러오기] 버튼을 눌러서 선택해주세요.

 

 

  저는 다음과 같이 선택했습니다.

 

 

  이후에 진행하면 됩니다. 참고로 여기에서 [특별공제 보험료]나 [신용카드] 항목에 대해서 반드시 [계산하기] 버튼을 눌러서 반영하도록 합니다. (누르지 않으면 공제가 적용되지 않습니다. 생돈을 엄청 날리게 될 수도 있어요.)

 

 

  이제 다음과 같이 소득공제 내용이 반영됩니다. 저는 이것저것 많이 사 먹어서 그런지, 신용카드 쓴걸로도 많이 공제가 되었네요.

 

 

  다음으로 넘어가면 기부금 관련 명세 내용도 확인할 수 있습니다. 기부금이 있다면 공제를 받을 수 있는데요, 저는 작년에 기부한 내용이 없어서 넘어갔습니다.

 

 

  이후에 세액감면이 되는 여부가 있는지 체크합니다. 사실 아래 항목들은 웬만해서 해당되기 어려운 것 같습니다.

 

 

  세액공제신청서도 넘어갑니다.

 

 

  이제 기다리던 세액 공제입니다. 근로자로 활동한 이력이 있는 등, 다양한 요인에 의하여 공제를 받을 수 있습니다.

 

 

  특히 의료비, 교육비로 지출하신 게 있다면 [자동계산] 버튼을 눌러서 꼭 계산해주셔야 합니다. 만약에 학비로 500만 원을 썼는데, 이거 버튼 안 눌러서 세액 공제가 안 되면 엄청난 낭패겠죠.

 

 

  저는 결과적으로 꽤 많은 돈을 공제 받을 수 있었습니다. (특히나 대학원생이라서요.) 또한 기본적으로 전자신고에대한세액공제 이거 하나만으로도 20,000원이나 공제받을 수 있습니다.

 

 

  이후에 가산세 명세서를 확인할 수 있습니다.

 

 

  이후에 기납부세액 명세서를 확인할 수 있습니다. 말 그대로 이미 낸 돈들을 의미합니다.

 

 

  이제 최종적으로 세액을 계산합니다. 마지막에 나오는 "신고기한이내 납부할 세액"이 양수(+) 값이라면, 그만큼 돈을 납부해야 합니다. 반면에 음수(-)라면, 그만큼 환급을 받을 수 있습니다.

 

 

  이제 신고서 작성 완료를 하면 됩니다.

 

 

  최종적으로 다음과 같이 신고 접수가 완료된 것을 알 수 있습니다.

 

 

  이제 아래 쪽에 있는 [신고내역] 탭으로 이동하도록 합니다.

 

 

  제 신고 내역은 다음과 같이 나옵니다. 참고로 "부속서류 제출여부"가 N으로 나온다면, 추가적인 서류를 제출할 필요가 없다는 의미입니다. 저는 환급을 받는게아니라 납부할 금액이 있으므로 먼저 [납부할 세액 조회납부]를 눌러서 납부하도록 하겠습니다. (참고로 2020년 기준 지방소득세는 별도로 납부를 해야 합니다.)

 

 

  결과적으로 다음과 같이 납부할 금액과 납부 계좌번호가 나옵니다. 여기로 계좌이체를 해서 납부하면 됩니다.

 

 

  이제 지방소득세도 연달아 납부하시면 됩니다. 납부서 [보기] 버튼을 누릅니다.

 

 

  다음과 같이 [개인지방소득세 신고하기] 버튼을 눌러서 지방소득세를 신고하시면 됩니다.

 

 

  그러면 다음과 같이 별도의 창이 나오면서 지방소득세 금액을 알려줍니다. 저는 환급이 아니라 세금을 내야 하는 입장이기 때문에, [신고] 버튼을 눌러서 신고할 수 있도록 하겠습니다.

 

 

  다음과 같이 납부를 진행하시면 됩니다.

 

 

  결과적으로 지방소득세까지 납부를 마치셨으면, 종합소득세 신고가 끝난 겁니다.

728x90
반응형

728x90
반응형

  종합소득세 신고 완료 버튼을 누르자마자 종합소득세 신고를 잘못했다는 것을 깨달았다면 어떻게 할까요? 신고를 한 지 오랜 시간이 지났다면, 절차가 복잡해질 수 있습니다. 하지만 종합소득세 신고 직후에 실수를 깨달았다면, 그냥 다시 바로 신고서를 작성하면 됩니다. 바로 [종합소득세 신고] 탭으로 이동해서 [정기신고 작성] 버튼을 눌러 신고서를 다시 작성합시다.

 

 

  종합소득세 신고서를 처음부터 다시 작성을 하면되는데요. 기본적으로 [신고서 불러오기] 버튼을 눌러서 이전 신고서가 저장되어 있다면, 이를 참고해서 더욱 간편하게 재작성을 할 수 있습니다.

 

 

  일단 이미 "신고서 작성완료"라고 나오는 제출된 신고서의 경우에는 이전에 처리가 완료된 신고서라고 보시면 됩니다. 한 번 이 신고서를 [열기] 하려고 시도해보겠습니다.

 

 

  그러면 다음과 같이 안내 메시지가 나옵니다. "신고기한 내에 신고서를 수정하여 다시 제출하고자 하는 경우에는 [작성화면]에서 사업자(주민)등록번호와 과세기간으로 조회하여 재작성"하면 된다고 나오는 것을 확인할 수 있습니다.

 

 

  쉽게 말하면, 그냥 작성 자체를 다시하면 됩니다. 따라서 한 번 처음부터 작성을 다시 해보겠습니다.

 

 

  여차저차 해서 다시 신고서 제출까지 완료하게 되면 다음과 같은 화면이 나옵니다. 정상적으로 새롭게 작성된 신고서로 신고가 완료된 것을 확인할 수 있습니다.

 

 

  이후에 [신고내역] 탭을 확인하면 다음과 같이, 신고한 내용이 성공적으로 변경된 것을 알 수 있습니다.

 

 

728x90
반응형

728x90
반응형

  USB 장치(Device)는 기본적으로 동시에 여러 개의 인터페이스(Interface)를 제공할 수 있다. 여기에서 인터페이스라는 것은 하나의 기능을 의미한다. 예를 들어 하나의 USB 기기가 동시에 마우스이면서 키보드가 되도록 할 수 있다. 실제로 USB 장치를 꽂기만 하면 마우스(Mouse)가 마음대로 동작하고, 그와 동시에 키보드(Keyboard)로 무작위로 아무 내용이나 입력이 되도록 할 수도 있다.

 

  아두이노(Arduino) IDE를 따르는 Teensy Board를 기준으로 설명하겠다. Teensy Board는 아두이노 IDE에서 [USB Type]을 설정할 수 있다. [USB Type]으로 [Keyboard]를 설정하는 경우, Teensy Board가 "Keyboard" 인터페이스를 가지는 USB 기기가 되는 것이다. 이를 선택하면 자동으로 USB Descriptor에 Keyboard 인터페이스 정보가 담기게 된다.

 

 

  예를 들어 다음과 같이 [USB Type]으로 [All of the Above]를 설정하는 경우, 동시에 10개가 넘는 인터페이스를 제공할 수 있다. 호스트(Host) PC는 Teensy Board의 각 인터페이스와 통신하면서 Teensy Board가 의도했던 기능이 수행되는 것이다.

 

 

  그렇다면, 이러한 인터페이스 정보는 어디에 기록되어 있는 것을까? Teensy Board의 경우 아두이노 IDE 위에서 동작하기 때문에, 기본적인 설정 정보는 다 아두이노(Arduino)가 설치된 폴더에 존재한다.

 

  구체적으로 인터페이스 환경설정 내용은 usb_desc.h에 기록되어 있는데, 이것은 다음의 경로에 존재한다.

 

  C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3

 

 

  실제로 usb_desc.h 파일을 열어 보면, "USB_EVERYTHING"으로 정의된 매크로를 확인할 수 있다. 실제로 Teensy Board의 [USB Type]을 "All of the Above"로 설정하면 "USB_EVERYTHING" 매크로가 활성화된다.

 

 

  이 경우 Keyboard, Serial, Mouse 등 다양한 라이브러리를 사용할 수 있다. 바로 다음과 같이 코드를 작성해도 정상 동작하는데, 말 그대로 마우스/키보드/시리얼 등이 동시에 동작하는 하나의 USB 장치를 만들 수 있는 것이다.

 

void setup() {

}

void loop() {
    int i;
    for (i = 0; i < 40; i++) {
        Mouse.move(2, -1);
        delay(100);
    }
    delay(1000);
    Serial.println("Hello");
    Keyboard.print("Hello World");
}

 

728x90
반응형

728x90
반응형

  Teensy BoardUSB 디바이스 개발을 위한 소형 보드(Board)이다. 사실 Teensy에 올라갈 펌웨어 개발 자체를 아두이노(Arduino) IDE를 이용해서 진행하므로, 아두이노 보드랑 사실상 유사하다. Teensy는 USB 디바이스 개발과 관련한 것에 초점이 더 맞추어져 있긴 한데, 아무튼 아두이노랑 기능적으로 비슷한 일을 할 수 있다.

 

  Teensy 3.5나 3.6 버전의 경우 SD 카드 슬롯(Slot)이 있기 때문에 SD 카드를 꽂을 수 있다. 그래서 SD 카드에 있는 파일을 읽거나, 혹은 SD 카드에 파일을 쓰는 것이 가능하다.

 

 

  그렇다면 Teensy Board 자체를 USB Storage처럼 사용할 수 있을까? Teensy Board를 우리의 호스트(PC)에 꽂으면, 호스트 PC가 이를 USB Storage로 인식하여 파일을 주고 받도록 하고 싶다고 가정해보자. 이 때 사용할 수 있는 라이브러리 중에서 MTP (Media Transfer Protocol)이 있다.

 

  MTP란 일종의 USB 클래스 중 하나이다. 하는 역할 자체는 MSC (Mass Storage Class)와 유사한데, 호스트 PC와 많은 양의 데이터를 주고 받기 위해 사용한다. 다만, 기본적으로 Mass Storage는 호스트 PC가 마운트를 하고 나면, 해당 USB 저장 장치에 대해서 절대적인 제어권을 가지게 된다. MSC는 블록 인터페이스 수준에서 동작하기 때문이다. 반면에 MTP는 논리적인 파일 수준의 송수신이 가능하다. 심지어 특정한 파일에 접근할 때는 암호를 입력하도록 설정할 수도 있다. 그래서 호스트 PC에서 특정한 파일만 가져가도록 할 수도 있는 것이다.

 

  아무튼 기본적으로 MTP는 미디어 파일 같은 것을 옮기기 위한 목적으로 설계되었다. Teensy의 경우에는 MTP 라이브러리가 있어서, 이를 이용할 수 있다. 한 번 Teensy Board를 USB 저장 장치처럼 사용해보자.

 

※ Teensyduino에서 MTP Disk 타입 설정 ※

 

  아두이노에서 보드(Board)를 Teensy로 설정하자. 이후에 이러한 Teensyduino에서는 USB Type으로 MTP Disk를 선택할 수 있다. 아래 그림을 확인해보자. 하지만 정작 이렇다할 MTP 라이브러리 사용 예제는 보이지 않는다.

 

 

  애초에 MTP 기능을 이용하기 위해서는 관련 라이브러리가 존재해야 한다. 아두이노 설치 경로인 C:\Program Files (x86)\Arduino에 MTP 라이브러리가 있는지 확인을 해보면, 존재하지 않는다. 그러면 MTP 기능은 어떻게 사용하라는 건지 궁금해진다. 바로 MTP 라이브러리를 '사용자 라이브러리'로 추가해주어야 한다.

 

  기본적으로 다음의 두 라이브러리가 필요하다.

 

  * SDFat 라이브러리: 아두이노 SDFat 라이브러리는 아두이노 기기에 꽂혀 있는 SD 카드의 FAT16/FAT32 파일 시스템에 접근하도록 해주는 기능을 제공하는 라이브러리다.
  * MTP 라이브러리: 아두이노 MTP 라이브러리는 아두이노 기기에 꽂혀 있는 SD 카드에 호스트(Host) PC가 접근할 수 있도록 해주는 인터페이스 기능을 제공하는 라이브러리다.

 

  따라서 두 작업을 해주자.

 

  1) 아두이노 사용자 라이브러리에 SDFat 라이브러리 추가

  2) 아두이노 사용자 라이브러리에 MTP 라이브러리 추가 

 

  일단 두 라이브러리는 별도로 GitHub에 올려 놓았으니, 이를 받아줄 수 있도록 한다.

 

  https://github.com/ndb796/Teensy-MTP-Library

 

  이제 이 두 라이브러리 폴더를 아두이노 스케치북 위치에 저장해주면 된다. 여기에서 스케치(Sketch)란, 아두이노 IDE를 이용해 작성된 프로그램을 의미한다. 사용자 라이브러리 경로(스케치북 경로)는 어디일까? 바로 아두이노에서 [파일] - [환경설정]에 들어가면 된다.

 

  필자의 경우에는 C:\Users\dongbin\Documents\Arduino\libraries에 라이브러리를 넣어주면 된다.

 

 

  이제 해당 경로에 다음과 같이 MTP 라이브러리, SdFat 라이브러리 폴더를 놓아 두었다. 각 라이브러리 폴더에는 규격에 맞게 라이브러리의 내용이 구현되어 있다.

 

 

  이제 다음의 예제 소스코드를 아두이노 IDE에 넣고 실행할 수 있다.

 

/*
  This example demonstrates MTP with blinky using systick interrupt.

  This example tests MTP and SdFat
*/

#include <MTP.h>

MTPStorage_SD storage;
MTPD          mtpd(&storage);


volatile int  status = 0;
volatile bool sdfound = 0;
volatile int  count = 1;

void rtc_seconds_isr() {
    if (count-- == 0) {
        digitalWrite(LED_BUILTIN, status);
        Serial.println("I should be commented out");
        status = !status;
        if (sdfound)
            count = 2;
        else
            count = 1;
    }
}

void setup() {
    Serial.begin(19200);
    pinMode(LED_BUILTIN, OUTPUT);

    RTC_IER |= 0x10;  // Enable seconds IRQ from RTC peripheral
    NVIC_ENABLE_IRQ(IRQ_RTC_SECOND); // Enable seconds IRS function in NVIC
}

void loop() {
    if (SD.begin()) {
        sdfound = true;
        mtpd.loop();
    }
    else {
        sdfound = false;
    }
}

 

  다음과 같이 [스케치] - [업로드]를 눌러서 업로드를 진행할 수 있다. 업로드를 진행하면 경고 메시지가 나올 수 있지만, 다음과 같이 정상적으로 Teensy 프로그램이 업로드된다.

 

 

  이제 이 Teensy Board를 PC에 꽂으면 다음과 같이 MTP 디바이스로 인식하게 된다.

 

 

  만약 컴파일(Compile) 단계에서 다음과 같은 경고 메시지가 나온다면, 경고 메시지를 지우기 위해서는 어떻게 해야 되는지 알아보자.

 

 

  우리가 추가한 MTP.h 라이브러리 파일에서 OpenFileByIndex 함수 부분의 uint8_t mode = O_RDONLY를 oflag_t mode = O_RDONLY로 변경하면 경고 메시지가 사라진다.

 

 

  위와 같이 MTP.h 내용을 수정한 뒤에 다시 컴파일을 하면 다음과 같이 깔끔하게 컴파일이 진행된다.

 

 

※ Teensy에서 MTP 라이브러리가 동작하는 원리 ※

 

  이제 간단히 MTP 라이브러리의 동작 원리를 알아보자. MTP 라이브러리는 동작 과정에서 SDFat 라이브러리를 이용하며, 호스트 PC에서 Teensy Device에 접근하도록 했을 때 호스트 PC 입장에서는 마치 USB Mass Storage와 유사한 기능을 이용하는 것처럼 느끼게 해준다. (실제로는 Teensy의 MTP Interface를 거치는 것이므로, Teensy 입장에서는 공개하고 싶은 파일만 호스트 PC가 접근할 수 있도록 처리할 수 있는 것이다.)

  실제로 MTP 라이브러리의 코드 (MTP.h)를 뜯어 보면, USB 관련 헤더 (이 라이브러리는 아두이노 설치 폴더의 hardware/avr/cores 폴더에 구현되어 있다.)에서 USB 주요 기능을 가져와서 USB 패킷을 주고 받는 방식으로 동작하도록 구현되어 있다. (정확히는 usb_dev.h 파일을 참조한다.)

 

 

  아무튼 이렇게 다른 사람이 만들어 놓은 MTP.h 라이브러리가 있어서, 내 Teensy Board를 손쉽게 MTP 디바이스처럼 만들어 사용할 수 있었다. 이 밖에도 다양한 외부 라이브러리가 있으므로 필요한 것들은 찾아서 붙이면 된다. (만약 없다면, 직접 코어 라이브러리를 작성하면 될 것이다.)

728x90
반응형

728x90
반응형

USB(Universal Serial Bus)란?

  USB는 어떠한 주변기기(Device)라도 우리의 PC에 쉽게 붙여서 동작하도록 지원해주는 규격이다. 예를 들어 마우스, 키보드, 이어폰 등은 일반적으로 공통적으로 USB 프로토콜을 쓰고 있다.  또한 스토리지(Storage), 스마트 폰 등도 USB 규격을 이용해서 연결하도록 제공이 되는 것을 생각해보면 된다.

  USB 2.0 버전 이상에서는 초당 수십 MB 단위의 데이터를 송수신할 수 있으며, 하나의 PC에 매우 많은 USB 디바이스를 연결해도 문제가 없다. 우리는 흔히 컴퓨터를 이용할 때, PC에 마우스, 키보드, 이어폰을 모두 연결하여 사용하곤 한다. 그럼에도 불구하고 전혀 문제는 점을 떠올리면 된다.

  심지어 각 기기에 전원을 공급할 필요도 없다. USB를 꽂기만 하면, PC에서 마우스나 키보드에 전원도 공급해주기 때문이다. 또한 PC에 USB 포트의 개수가 적다고 하더라도, USB 허브를 별도로 구매해서 포트의 개수를 늘리면 그만이다. 이러한 장점들이 있기 때문에 USB는 두루 쓰이고 있는 것이다.

USB의 전원 공급

  앞서 USB는 꽂기만 해도 PC에서 USB 장치에 전원을 공급한다고 했는데, 이것이 가능한 이유는 USB에는 4가지 선이 있기때문이다. 2개의 선(D+, D-)은 호스트와 디바이스 간의 데이터를 주고 받기 위해 사용하고, 2개의 선(Vbus, GND)은 전원을 공급하기 위해 사용한다.

디바이스 클래스(Device Class)

  USB 디바이스를 식별할 때는 벤더(Vendor) ID와 프로덕트(Product) ID를 가지고 식별한다. 하지만, 별도로 클래스로 묶어서 이를 처리하는 경우가 대부분이다. 예를 들어 마우스, 키보드 등의 디바이스를 개발할 때는 처음부터 디바이스 드라이버를 다 작성할 필요는 없고, 이미 존재하는 HID (Human Interface Device) 클래스의 기능을 그대로 이용하면 된다.

  예를 들어서 Arduino나 Teensy 등을 이용해서 자체제작 키보드를 만들거나 할 수 있는데, 이 경우 HID 클래스의 기능을 그대로 이용해서 개발하는 것이 편할 것이다.

기본 용어 정리

  ▶ 패킷(Packet): 호스트와 디바이스간의 통신에서 가장 작은 통신 데이터 단위
  ▶ 트랜잭션(Transaction): 패킷들의 모임을 의미한다. SETUP 패킷, DATA 패킷, HANDSHAKE 패킷 세가지의 종류가 있다. 이렇게 3가지를 모두 묶어서 한 번씩 데이터가 오가는데, 이러한 패킷 묶음을 트랜잭션이라고 한다.

  ▶ 전송(Transfer): 트랜잭션의 모임을 의미한다. 예를 들어 Bulk Transfer는 한 번의 트랜잭션으로 끝날 수 없고, 여러 번 트랜잭션을 반복해야 한다. 이 경우 보내야 할 데이터가 크기 때문에 여러 프레임(Frame)으로 나누어서 전송하거나 할 수 있다.

USB 디스크립터(Descriptor)

  USB 디바이스(Device)에 대한 기본적인 정보는 디스크립터(Descriptor)가 가지고 있다. USB를 PC에 꽂으면, 설정(Configuration) 정보를 주고 받는데, 이 때 Descriptor 정보를 보내게 되는 것이다. 이로써 호스트는 연결된 디바이스의 종류를 알게 되고, 디바이스의 특성에 맞게 데이터의 전송 양이나 폴링 주기를 설정하게 된다.

  디스크립터(Descriptor)에는 여러 종류가 있다. USB 정보를 호스트 PC에 디스크립터 정보를 보내는 데에, 왜 이렇게 많은 종류가 필요한지 궁금할 수 있다. 이것은 USB가 다양한 기능을 지원할 수 있다는 점에서 기인한다. 실제로 하나의 USB 장치는 동시에 마우스이면서, 동시에 키보드이면서, 동시에 조이스틱이 될 수도 있다.

 

  Device Descriptor, Configuration Descriptor, Interface Descriptor, Endpoint Descriptor 이렇게 네 가지 종류가 있다고 보면 된다. 아래 그림과 같이 트리(Tree) 구조로 되어 있다. Device Descriptor는 오직 하나만 존재하고, 이는 여러 개의 Interface Descriptor (마우스, Stroage, 키보드 등)를 가질 수 있다. 또한 하나의 Interface는 여러 개의 Endpoint (데이터를 주고 받는 통로)를 가지게 된다.

 

 

  ▶ 디바이스 디스크립터(Device Descriptor): 디바이스에 대한 가장 기본적인 정보를 담고 있음

    * USB 디바이스는 하나의 Device Descriptor를 가진다.
    * ProductID와 VenderID 정보가 담겨 있다. 
    * 얼마나 많은 Configuration을 가지고 있는지에 대한 정보가 담겨 있다.
    * 클래스(Class) 정보가 담겨 있다.

 

  ▶ 환경설정 디스크립터(Configuration Descriptor): 환경 설정 관련 정보를 가지고 있음

 

    * USB 디바이스는 여러 개의 Configuration Descriptor를 가질 수 있다.

    * 인터페이스(Interface)의 개수, 전력 소비 정보 등의 정보가 담겨 있다.

    * 하나의 USB 디바이스는 일반적으로 하나의 Configuration을 가지고 있다.

    * 여러 개의 전원 공급망을 가진 특별한 USB 디바이스의 경우 여러 개의 Configuration이 존재하는 경우가 있다.

 

  ▶ 인터페이스 디스크립터(Interface Descriptor): 한 가지 기능에 대한 정보를 가지고 있음

 

    * 하나의 USB 디바이스는 여러 개의 기능을 제공할 수 있다. (마우스 + 키보드 + 스캐너)

    * 각 기능마다 하나의 인터페이스(Interface)를 할당한다.

    * 인터페이스 번호, 엔드포인트의 개수 등의 정보가 담겨 있다.

    * 하나의 인터페이스는 여러 개의 엔드포인트(Endpoint)를 가질 수 있다.

    * 예를 들어 마우스이면서 Mass Storage의 기능을 제공하려면 Interface는 2개가 될 것이다.

  ▶ 엔드포인트 디스크립터(Endpoint Descriptor): 하나의 엔드포인트에 대한 정보를 가지고 있음

 

    * 실제로 호스트와 디바이스간의 통신이 이루어지는 통로 (소켓과 유사함)

    * 통로라는 의미에서 파이프(Pipe)라고 말하기도 한다.

    * 엔드포인트(Endpoint)의 번호, 전송 타입(Transfer Type), 방향성 등의 정보가 담겨 있다.

    * 엔드포인트의 전송 타입: Control, Interrupt, Isochronous or Bulk와 같은 타입이 있다.

    * 기본적으로 엔드포인트 0번은 디폴트로 Control 타입으로 사용된다.

USB Enumeration

  USB Enumeration이란 새로운 디바이스(Device)가 Bus에 연결이 되었는지 감지한 뒤에 그 디바이스를 인식하고, 적절한 드라이버를 로드하는 작업을 의미한다. 이를 위해 당연히 적절한 USB Driver를 Host 쪽에서 가지고 있어야 한다.

 

  USB Device가 PC에 꽂히게 되면, Host Controller는 Device의 0번 엔드포인트에게 정보를 요청한다. (이 때는 임시 Address를 이용한다.) 이 때 호스트는 디바이스 디스크립터(Device Descriptor) 정보를 받게 된다. 이후에 해당 Device에게 적절한 Address를 할당하고, 그 Address를 이용하여 나머지 Descriptor 정보를 요청한다. 결과적으로 모든 Descriptor 정보를 받고 나면 Enumeration 과정이 종료된다.

728x90
반응형

728x90
반응형

USB 전송 형태(Transfer Type)

  USB 프로토콜을 제대로 이해하기 위해서 공부할 것들이 몇 가지 있다.

 

  그 중에서 꼭 알아야 하는 것은 바로 USB의 전송 형태(Transfer Type)이다. 기본적으로 USB 프로토콜은 호스트(PC)와 디바이스(USB 장치)와의 통신에 관한 것이다.

 

  구체적으로 그림과 함께 설명할 예정인데, 참고해야 할 점은 '회색(Gray)' 부분은 호스트(PC)가 보내는 패킷이고, '하얀색(White)' 부분은 디바이스(Device)가 보내는 패킷이다.

 

 

1. 등시성 전송(Isochronous Transfer)

 

  첫 번째로 알아 볼 USB 전송 타입은 등시성 전송 타입이다. 이는 데이터의 전송 시간을 보증할 때 사용하는 타입이다. 데이터에 오류가 있어도 재전송을 하지 않으며, 호스트(PC)에서는 등시성 전송을 위해 시간을 스케줄링한다.

 

  일반적으로 이어폰과 같이 실시간으로 데이터를 받아서 송출해야 하는 디바이스에서 사용된다. 생각해 보면, 이어폰처럼 실시간으로 데이터를 주고 받아야 하는 경우에서 데이터에 약간의 오류가 있다고 재전송을 시킬 수는 없을 것이다.

 

  아무튼 등시성 전송은 다음과 같이 토큰 패킷과 데이터 패킷으로 처리된다. 흔히 이어폰의 경우에는 호스트가 OUT 패킷을 보냄으로써 "나 지금 음악 스트림 보낼거야."라고 말한 뒤에, 이어폰 디바이스한테 DATA 패킷을 연달아 보내는 것이다. 여기에서 토큰(Token) 패킷이란, 데이터의 방향을 알려주기 위해 호스트가 디바이스에게 보내는 패킷이다.

 

  참고: OUT 패킷은 말 그대로 호스트 PC가 디바이스에게 보낼 데이터가 있다는 의미이다. 호스트 입장에서 받아야 할 데이터가 있다면 호스트가 먼저 IN 패킷을 보낸 뒤에, 디바이스로부터 데이터를 받게 된다.

 

 

2. 인터럽트 전송(Interrupt Transfer)

 

  작은 크기의 데이터를 전달할 때 사용하는 타입이다. 일반적으로 마우스와 같이 클릭할 때만, 일시적으로 호스트(PC)가 데이터를 읽어들이는 경우에서 사용된다. 예시로는 키보드, 마우스 등이 있다.

 

  인터럽트 전송은 말 그대로 비주기적인 형태의 전송이다. 인터럽트 요청은 디바이스에 의해서 차례대로 큐에 담기게 되고, 호스트가 USB 디바이스한테, "너 보내 줄 데이터 있니?"라고 물어보면, 그 때 큐에 담겨진 인터럽트 요청들이 디바이스에서 호스트로 보내진다.

 

  예를 들어 우리가 키보드를 PC에 꽂은 뒤에, 타자를 친다고 가정해보자. 우리가 키보드에 입력한 데이터들은 일시적으로 키보드 디바이스의 내부 메모리 큐에 담기게 되고, 호스트가 폴링(Polling)을 하게 되면 그제서야 호스트에서 우리가 입력했던 문자들을 받아들이게 된다. (여기에서 알 수 있듯이, 호스트 입장에서는 주기적으로 폴링을 해야 한다.) 어느 정도의 주기로 폴링을 할 지는 디바이스의 엔드포인트 디스크립터(Endpoint Descriptor)에 명시되어 있다.

 

  구체적인 과정은 다음과 같다.

 

  ▶ IN 토큰 패킷: 호스트가 데이터를 받는 경우이다. 호스트가 IN 패킷을 보내면, 디바이스의 큐에 데이터가 저장된 경우 데이터를 보내주게 된다. 데이터를 잘 받았으면 ACK를 보낸다. 디바이스의 큐가 비어있으면 (인터럽트 메시지가 없으면) 디바이스에서는 NAK를 보낸다. 그리고 오류가 발생한 상황에서는 디바이스가 STALL을 보내는데, 이러면 호스트가 IN 패킷을 다시 보낸다. 군더더기 없이 깔끔하다.

 

  ▶ OUT 토큰 패킷: 호스트가 데이터를 보내는 경우이다. 호스트가 디바이스로 데이터를 보내는 경우에는, OUT 패킷을 발행한 뒤에 데이터를 보낸다. 디바이스 입장에서는 데이터를 차례대로 받는데, 이는 엔드포인트 버퍼에 담기게 된다. 아직 이전 패킷을 다 처리하지 못해서 엔드포인트 버퍼가 비어 있지 않다면, 디바이스는 NAK를 보낸다. 마찬가지로 오류 상황일 때는 STALL을 보낸다.

 

3. 벌크 전송(Bulk Transfer)

 

  대량의 데이터를 신뢰성 있게 전달할 때 사용하는 타입이다. 데이터 패킷 전송 과정에서 오류가 발생하면 재전송을 요구하며, 등시성 전송과는 다르게 전송 속도는 보증하지 않는다. 대표적인 예시로는 USB 저장 장치(Mass Storage)가 있다.

 

  기본적으로 Bulk Transfer와 Interrupt Transfer는 사실상 같은 트랜잭션 형태를 보인다. 그림 자체도 비슷한 걸 확인할 수 있는데, 벌크와 인터럽트의 차이점은 인터럽트에서는 전송요구에 대한 시간의 주기를 설정할 수 있다는 것이다. 즉, 호스트가 주기적으로 폴링을 수행하도록 요구할 수 있다.

 

  예를 들어 우리가 마우스를 클릭했는데 0.2초 뒤에 클릭이 된 것처럼 처리가 된다면 매우 불편할 것이다. 반면에 대용량 파일을 보내는 과정에서 0.2초 정도의 딜레이는 큰 문제가 없을 것이다. 더불어 Bulk Transfer에서는 1번의 트랜잭션으로 데이터가 전부 전송되지 않을 수 있기 때문에, 데이터를 분할해서 트랜잭션을 반복한다.

 

 

4. 제어 전송(Control Transfer)

 

  USB 기기에게 명령을 내리거나 상태 관련 연산을 수행하기 위해 사용하는 타이다. 모든 USB 기기는 제어 전송을 위해 엔드포인트(Endpoint) 0번을 사용하며, 어떤 데이터를 보낼지 또한 USB 규격으로 정해져 있다. 제어 전송의 경우 모든 USB 기기가 사용하는 전송 타입이다. 기본적으로 처음에 USB 디바이스를 PC에 꽂았을 때부터, 제어 전송을 통해 디스크립터(Descriptor) 정보를 받게 되기 때문이다. 이러한 작업들을 수행하는 것이 바로 제어 전송(Control Transfer)이다.

 

  기본적으로 제어 전송은 3가지 단계로 구성된다. 차례대로 설정 단계(Setup Stage), 데이터 단계(Data Stage), 상태 단계(Status Stage)이다.

 

  1) 설정 단계(Setup Stage): 제어 전송에서 가장 기본적인 단계이다. 이 단계는 초기 설정을 수행하며 세 개의 패킷(Token, Data, Handshake)으로 구성된다. 먼저 토큰 패킷으로는 설정을 진행할 Address 정보와 Endpoit 번호가 담기게 된다. 이후에 정확히 어떤 내용을 설정할 것인지 데이터 패킷에 담아서 보낸다. 예를 들어, 처음에 USB 디바이스에 연결된 상태라면 Descriptor 정보를 보내달라는 내용을 데이터 패킷에 담아서 보낼 것이다.

 

 

  2) 데이터 단계(Data Stage): 데이터 단계는 필요하다면 존재할 수 있다. 만약 데이터 단계가 있다면, 설정 단계에서 '데이터 단계에서 얼마나 많은 패킷이 전달될 지' 미리 설정이 된다. 데이터 단계는 다수의 IN 토큰 (호스트가 데이터를 받는 경우)과 OUT 토큰 (호스트가 데이터를 보내는 경우)으로 구성되는 경우가 많다.

 

  예를 들어 '설정 단계'에서 디바이스에게 Descriptor 정보를 달라는 패킷을 보냈다면, 이 데이터 단계에서는 IN 토큰을 발행해서 디바이스로부터 Descriptor 정보를 받게 된다.

 

 

  3) 상태 단계(Status Stage): 제어 요청의 처리 상태를 보고하기 위해 사용되는 단계이다. 즉, 정상적으로 제어 전송이 완료되었는지를 확인하는 마지막 단계라고 할 수 있다. 

 

  데이터 단계에서 호스트가 IN 토큰을 보냈다면, 호스트 입장에서는 데이터를 모두 다 정상적으로 받았는지 궁금하다. 그래서 OUT 토큰과 길이가 0인 데이터 패킷을 하나 보내서, 디바이스한테 "너 데이터 다 보낸 거야?"라고 물어본다. 그래서 디바이스에서 데이터를 다 보냈다면 호스트에게 ACK를 보냄으로써 현재의 COMMAND가 종료되었음을 알린다. 혹은 NAK를 보내서 아직 더 처리할 게 남았다는 것을 알리게 된다.

 

  반면에 데이터 단계에서 호스트가 OUT 토큰을 보냈다면, 정상적으로 데이터가 다 보내졌는지 확인하기 위해서 IN 토큰을 하나 보내서 디바이스에게 정상적으로 통신이 완료된 건지 물어보는 것이다. 

 

  * 상태 단계에서 OUT 토큰을 보내는 경우는 다음과 같다. (데이터 단계에서 호스트가 IN 토큰을 보낸 경우)

 

 

  * 상태 단계에서 IN 토큰을 보내는 경우는 다음과 같다. (데이터 단계에서 호스트가 OUT 토큰을 보낸 경우)

 

 

USB 기기 클래스(Device Class)

  USB 기기 클래스에 따라서 사용하는 전송 형태(Transfer Type)에도 차이점이 있다. 앞서 언급했듯이, 마우스나 키보드와 같은 디바이스들은 인터럽트 전송 타입을 많이 사용할 것이다. USB 기기 클래스를 간략히 소개하면 다음과 같은 것들이 있다.

 

  * MSC (Mass Storage Class): USB 외부 저장장치에 대한 클래스로, Bulk Transfer를 사용한다.
  * ADC (Audio Device Class): 오디오 장치에 대한 클래스로, Isochronous Transfer를 사용한다.

  * HID (Human Interface Device): I/O 장치(키보드, 마우스) 같은 것에 대한 클래스로, Interrupt Transfer를 사용한다.

 

  이외에도 MTP (Media Transfer Protocol)과 같은 클래스도 있다. 이 클래스는 MSC (Mass Storage Class)의 대용으로 사용될 수 있다. 기본적으로 USB 시스템에서는 Host가 주도권을 가지게 되는데, MSC의 경우 호스트가 마운트를 하고 나면, 해당 USB 저장 장치에 대해서 절대적인 제어권을 가진다. MSC는 블록 인터페이스 수준에서 동작하기 때문이다.

  반면에 MTP는 논리적인 파일 수준의 송수신이 가능하다. 예를 들어 USB를 MTP로 제공할 때는, 특정 파일에 접근할 때는 암호를 입력하도록 하거나 할 수도 있다. 즉, MTP나 MSC나 모두 내부적으로 Bulk Transfer와 비슷한 기능을 이용하지만 목적 자체가 다르다는 점이 특징이다.

728x90
반응형

728x90
반응형

대회 링크: https://codeforces.com/contest/1345

A번 문제: https://codeforces.com/contest/1345/problem/A

 

[ 문제 해설 ]

 

  이 문제는 그림을 그려가면서 다양한 케이스들을 확인해 보면, 문제 풀이 아이디어를 빠르게 떠올릴 수 있다.

 

  행이나 열의 크기가 1이라면, 항상 퍼즐을 풀 수 있다. 그리고 행이나 열의 크기가 둘 다 2, 2일 때에도 항상 퍼즐을 풀 수 있다. 하지만 그 이외의 모든 경우에 대해서는 퍼즐을 풀 수 없다.

 

[ 정답 코드 ]

 

for _ in range(int(input())):
    n, m = map(int, input().split())

    # 행이나 열의 크기가 1이라면 풀 수 있음
    if n == 1 or m == 1:
        print("YES")
    # 행과 열의 크기가 모두 2일 때 풀 수 있음
    elif n == 2 and m == 2:
        print("YES")
    # 이외의 경우에는 모두 풀 수 없음
    else:
        print("NO")

 

B번 문제: https://codeforces.com/contest/1345/problem/B


  이 문제는 N장의 카드를 가지고 있을 때, 최대한 높은 층의 카드 쌓기를 반복적으로 수행하는 문제이다. 그래서 마지막에 몇 개의 카드 피라미드가 존재할 지 출력하면 된다.

 

  아래의 그림에서 볼 수 있듯이,

 

  1층짜리 피라미드: 2장 필요

  2층짜리 피라미드: 7장 필요

  3층짜리 피라미드: 15장 필요

 

 

  그래서, 예를 들어 N = 24라고 해보자.

 

  처음에 15장을 투자해 3층짜리 피라미드를 짓고, 9장이 남는다.

  그리고 7장을 투자해 2층짜리 피라미드를 짓고, 2장이 남는다.

  남은 2장을 투자해 1층짜리 피라미드를 짓고, 0장이 남는다.

 

  그래서 결과적으로 피라미드를 3개 지을 수 있게 된다.

 

[ 문제 해설 ]

 

  이 문제를 해결하기 위한 방법은 간단하다. 문제에서 요구하는 내용을 그대로 구현하면 된다. 이 때 피라미드는 층이 증가할수록 다음과 같이 카드가 필요하다는 특징이 있다.

 

  - 1층 피라미드: 2장

  - 2층 피라미드: 2장 + 5장

  - 3층 피라미드: 2장 + 5장 + 8장

  - 4층 피라미드: 2장 + 5장 + 8장 + 11장

  - 5층 피라미드: 2장 + 5장 + 8장 + 11장 + 14장

 

  즉, 층이 올라갈수록 '추가적으로 필요한 카드의 개수는 3장씩 증가'한다.

 

[ 정답 코드 ]

 

for _ in range(int(input())):
    n = int(input())
    result = 0

    # 남아있는 카드가 2장 이상이라면, 피라미드 만들기 수행
    while n >= 2:
        # 초기 상태
        summary = 0
        count = 2
        height = 0

        # 더 높이 쌓을 수 없을 때까지 쌓기
        while n >= summary + count:
           summary += count
           count += 3
           height += 1

        # 피라미드 하나를 완성했으므로, n에서 필요한 카드의 개수만큼 빼주기
        result += 1
        n -= summary

    print(result)

 

C번 문제: https://codeforces.com/contest/1345/problem/C


  이 문제는 비둘지깁의 원리같은 느낌의 문제다. 

728x90
반응형

728x90
반응형

대회 링크: https://codeforces.com/contest/1352

A번 문제: https://codeforces.com/contest/1352/problem/A

 

[ 문제 해설 ]

 

  이 문제는 먼저 각 자릿수를 확인하면 된다. 이 때, 0이 아닌 자릿수에 대하여 그 값들을 출력해주면 된다. 예를 들어 입력이 6009이라면, 6000과 9를 출력하면 된다. 소스코드는 다음과 같다.

 

[ 정답 코드 ]

 

for _ in range(int(input())):
    n = int(input())
    result = []

    power = 1
    # 각 자릿수를 확인하며
    while n > 0:
        # 0이 아닌 자릿수에 대하여
        if n % 10 != 0:
            # 그 값들을 각각 출력
            result.append((n % 10) * power)
        n //= 10
        power *= 10
  
    print(len(result))
    for i in result:
        print(i, end=' ')
    print()

 

B번 문제: https://codeforces.com/contest/1352/problem/B


  이 문제는 k개의 수를 더해서 n을 만들 수 있는지 물어보는 문제이다. 단, k개의 수는 모두 홀수이거나 모두 짝수여야 한다.

[ 문제 해설 ]

 

  문제에서 요구하는 대로 모든 수가 홀수이거나, 모든 수가 짝수인 경우 두 가지만 고려하면 된다.

  먼저 모든 수가 홀수인 경우, (k - 1)개의 수를 모두 1로 설정(가능한 작은 수)한 뒤에  '나머지 1개의 수'홀수이면서 조건을 만족시킬 수 시 있는지 확인하면 된다.  예를 들어 n = 7, k = 5인 경우에는 (k - 1) + 3 = 7로 n을 만족시킬 수 있다. 즉, 나머지 1개의 수를 3으로 설정하면 된다.

  그리고 모든 수가 짝수인 경우, (k - 1)개의 수를 모두 2로 설정(가능한 작은 수)한 뒤에  '나머지 1개의 수'짝수이면서 조건을 만족시킬 수 있는지 확인하면 된다. 예를 들어 n = 8, k = 3인 경우에는 (k - 1) * 2 + 4 = 8로 n을 만족시킬 수 있다. 즉, 나머지 1개의 수를 4로 설정하면 된다.

  따라서 두 가지 경우만 잘 고려해주는 코드를 작성하면 된다.

 

[ 정답 코드 ]

 

for _ in range(int(input())):
    n, k = map(int, input().split())

    # 모든 수가 홀수인 경우
    odd = n - (k - 1)
    if odd > 0 and odd % 2 == 1:
        print("YES")
        for i in range(k - 1):
            print(1, end=' ')
        print(odd)
        continue

    # 모든 수가 짝수인 경우
    even = n - (k - 1) * 2
    if even > 0 and even % 2 == 0:
        print("YES")
        for i in range(k - 1):
            print(2, end=' ')
        print(even)
        continue

    # 두 가지 케이스 모두 만족시킬 수 없을 때
    print("NO")

 

C번 문제: https://codeforces.com/contest/1352/problem/C


  n과 k가 주어졌을 때, n으로 나누어 떨어지지 않는 k번째 자연수를 찾으면 되는 문제다. 

 

  예를 들어 n = 3, k = 7이라고 하면

 

  1, 2, 4, 5, 7, 8, 10, 11, 13, ... 

  위와 같이 이어지므로, 7번째 수는 바로 10이 된다.

[ 문제 해설 ]

 

  답을 구하는 방법은 생각보다 쉽다. 구하고자 하는 k번째 자연수는 항상 k 이상이고, 그리고 2k 미만이 된다.

 

  생각해 보면, n = 2일 때는 1, 3, 5, 7, ... 이렇게 갈 텐데, 이 때에도 k번째 수는 2k보다 작은 2k - 1이 된다. 다시 말해 출력해야 되는 정답은 항상 k 이상 2k 미만의 수가 될 것이다. 그렇다면 k보다 얼마나 큰 수가 출력되어야 하는가?

 

  그것은 바로 k보다 (k - 1) // (n - 1)만큼만 커지면 된다. 즉, k + (k - 1) // (n - 1)이 정답이다. 답을 계산하는 방법은 굉장히 다양하지만, 이것보다 간단히 수식으로 표현할 수 있는 답은 없다.

 

[ 정답 코드 ]

 

for _ in range(int(input())):
    n, k = map(int, input().split())
    print(k + (k - 1) // (n - 1))

 

D번 문제: https://codeforces.com/contest/1352/problem/D

 

  왼쪽에서부터 오른쪽으로 과자를 먹는 사람과 오른쪽에서부터 왼쪽으로 과자를 먹는 사람이 있다. 

  이 때 한 차례씩 반복하면서 먹어나가는데, 이전 차례에서 상대방이 먹었던 양보다 더 많이 먹어야 하는 방식이다. 그래서 전체 몇 차례나 반복되었는지, 두 사람이 각각 얼마나 먹었는지를 출력하면 된다.

 

[ 문제 해설 ]

 

  이 문제는 문제에서 요구하는 대로 구현만 잘 해주면 된다. 최대한 깔끔하게 실수 없이 구현해서 정답 처리를 받으면 된다.

 

[ 정답 코드 ]

 

for _ in range(int(input())):
    n = int(input())
    data = list(map(int, input().split()))
    l = 0
    r = n - 1
    left_sum, right_sum = 0, 0
    left_res, right_res = 0, 0
    count = 0

    # 일종의 투 포인터(Two Pointers) 기법
    while l <= r:
        # 왼쪽에서 먹을 차례
        if count % 2 == 0:
            now_sum = 0
            while l <= r and now_sum <= right_sum:
                now_sum += data[l]
                l += 1
            left_res += now_sum
            left_sum = now_sum
        # 오른쪽에서 먹을 차례
        elif count % 2 == 1:
            now_sum = 0
            while l <= r and now_sum <= left_sum:
                now_sum += data[r]
                r -= 1
            right_res += now_sum
            right_sum = now_sum
        count += 1

    print(count, left_res, right_res)

 

E번 문제: https://codeforces.com/contest/1352/problem/E

 

  n개의 정수로 구성된 수열이 있을 때, 각 n개의 수에 대하여 그 수와 동일한 합을 가지는 '부분 연속 수열'이 존재하는지 찾으면 되는 문제이다.

  예를 들어 [3, 1, 4, 1, 5, 9, 2, 6, 5]가 있을 때 6번째 수인 9는 [3, 1, 4, 1]의 합과 같다.

 

[ 접근 방법 1 ]


  일단 이 문제는 투 포인터(Two Pointer)를 이용하여 해결할 수 있다. n개의 수 각각에 대하여 투 포인터 알고리즘을 돌리면 된다. 투 포인터 문제로 유명한 '합이 M인 부분 연속 수열 찾기' 코드를 그대로 쓰면 된다.

  단, 이 문제에서는 부분 연속 수열의 길이가 2 이상이 되라고 하였으므로 투 포인터 알고리즘을 길이가 2 이상인 경우만 찾도록 수정해서 이용하면 된다.

  코드포스 문제를 풀다 보면, 투 포인터 문제가 굉장히 자주 나오는 것 같다. 혹은... 내가 그냥 해법으로 투 포인터를 먼저 생각해서 그러는 거일 수도 있겠다. 근데 이게 가끔은 시간 초과를 받는 경우도 있으니 조심해야 한다.

 

for _ in range(int(input())):
    n = int(input())
    data = list(map(int, input().split()))
    result = 0

    for x in data:
        summary = 0
        end = 0

        for start in range(n):
            while summary < x and end < n:
                summary += data[end]
                end += 1
            if summary == x and end - start >= 2:
                result += 1
                break
            summary -= data[start]

    print(result)

 

  근데... 걱정했던 대로 위 코드는 시간초과를 받았다. 투 포인터를 이용할 때에도 사실 O(N^2)의 해법으로 시간 복잡도가 똑같기 때문에 괜찮을 줄 알았는데, 파이썬을 이용하고 있기 때문인지... 시간 초과를 받을 줄은 몰랐다. ㅠㅠ 시간 초과를 받은 케이스를 보니까 정말 간발의 차이로 시간 초과를 받았다. 0.5초만 더 널널했어도, 시간 초과를 받지 않았을 것 같다.

 

[ 접근 방법 2 ]

 

  아무튼 같은 O(N^2)이지만, 조금 더 빠른 해법은 모든 구간의 합을 하나의 배열에 기록해 놓는 방법이다. (계수 정렬 할 때 처럼) 모든 값들이 n (1 <= n <= 8000) 보다 작기 때문에 이 또한 가능하다. 시간 초과에 걸리지 않는, 정답 코드는 다음과 같다.

 

[ 정답 코드 ]

 

for testcase in range(int(input())):
    n = int(input())
    data = list(map(int, input().split()))

    # 모든 구간 합을 저장하기 위한 집합 자료형
    visited = set()

    # 길이가 2 이상인 모든 구간 합을 집합에 저장
    for i in range(n):
        summary = data[i]
        for j in range(i + 1, n):
            summary += data[j]
            if summary > n:
                break
            visited.add(summary)

    # 각 값을 확인하며, 계산할 수 있는 구간 합인 경우 카운트
    result = 0
    for x in data:
        if x in visited:
            result += 1

    print(result)

 

F번 문제: https://codeforces.com/contest/1352/problem/F

 

[ 문제 해설 ]


  이 문제도 구현 문제인데, 최대한 구현 실수가 발생하지 않게 깔끔한 아이디어로 푸는 것이 중요하다. 일단 가장 중요한 게 n1 = 0인 케이스이다. 이 때는 n0과 n2 둘 중에 하나는 0이 되어야 한다. 안 그러면 조건이 만족되지 않는다. 따라서 n1 = 0인 경우에는, 단순히 n0과 n2 중에 하나만 0이 아닌 값을 가진다는 것을 고려해서 풀면 된다.

  그리고 n1 = 0인 케이스가 아니라면, 다음과 같이 먼저 처리해서 문제를 해결할 수 있다.

  해결법은 바로 다음과 같다. 먼저 (n2 + 1)의 크기만큼 1을 출력한다. 그리고 n0의 크기만큼 0을 출력한다. 이후에 n1의 크기만큼 010101... 을 반복해서 출력하면 된다. 그러면 정확히 조건을 만족할 수 있다.

 

[ 정답 코드 ]

 

for testcase in range(int(input())):
    n0, n1, n2 = map(int, input().split())
    
    # n1가 0인 특이 케이스 처리
    if n1 == 0:
        if n0 > 0:
            print("0" * (n0 + 1))
        else:
            print("1" * (n2 + 1))
        continue

    # 일반적인 케이스 처리
    print("1" * (n2 + 1), end="")
    print("0" * n0, end="")
    for i in range(n1):
        if i % 2 == 0:
            print("0", end="")
        else:
            print("1", end="")
    print()

 

G번 문제: https://codeforces.com/contest/1352/problem/G

 

[ 문제 해설 ]


  이 문제도 간단한 아이디어를 떠올리면 간단히 풀 수 있다. 필자는 대회 당시에는 매우 복잡하게 푼 것 같은데, 실제로는 매우 간단하게도 문제를 해결할 수 있었다.

  홀수를 먼저 내림차순으로 출력한 뒤에 4와 2를 출력하고, 다시 모든 짝수를 오름차순으로 차례대로 출력하면 된다. 이렇게 대칭을 이루도록 출력하면 간단하게 해결된다.

  예를 들어 n = 11이라고 하면,

  [ 11 9 7 5 3 1 ] [ 4 2] [6 8 10]로 출력하면 된다.

  위 출력 결과를 보면 인접한 모든 수들은 2 이상, 4 이하로 차이가 난다.

 

[ 정답 코드 ]

 

for _ in range(int(input())):
    n = int(input())
    # 4보다 작은 경우, 만들 수 없음
    if n < 4:
        print(-1)
        continue
  
    # 모든 홀수를 먼저 내림차순으로 출력
    for i in range(n, 0, -1):
        if i % 2 == 1:
            print(i, end=' ')
    # 4와 2를 출력
    print(4, 2, end=' ')
    # 모든 짝수를 오름차순으로 출력
    for i in range(6, n + 1, 2):
        print(i, end=' ')
    print()

 

728x90
반응형

728x90
반응형

  코드포스의 경우 다른 사람의 소스코드를 해킹(Hack)할 수 있는 기능이 제공된다. 사실 처음에는 알고리즘 대회인데 해킹 시스템이 왜 있는지 궁금했다. 해킹은 다른 사람의 소스코드를 지적하는 의미가 되기도 하고, 알고리즘 대회 자체가 가지고 있는 채점 데이터 셋의 오류를 지적하는 의미가 되기도 한다.

 

  일단 코드포스에서는 대회 도중에 해킹(Hacking)하는 경우와, 대회가 끝난 뒤에 12시간 동안 오픈 해킹(Open Hacking)을 하는 경우가 있다. 방법은 기본적으로 유사하다. 일단 상대방의 소스코드를 확인한 뒤에 문제가 있다고 판단이 되면, 소스코드에서 제대로 처리하지 못할 입력(Input)을 만들어서 입력하면 된다.

 

  내 코드를 잠금(Lock) 했거나, 오픈 해킹 기간일 때는 다음과 같이 다른 사람들의 소스코드를 확인할 수 있다. 기간 안에는 이러한 소스코드에 해킹을 시도할 수 있다.

 

 

  다른 사람의 소스코드를 확인한 뒤에 [hack it!] 버튼을 눌러서 해킹을 시도하면 된다.

 

 

  해킹을 시도할 때는 입력 문자열을 직접 넣거나, 입력 문자열이 담긴 파일을 업로드해서 제출하면 된다.

 

 

  나는 한 번 자핵을 해보았다. 내가 낸 소스코드에 문제가 있는 것 같아서, 오픈 해킹 기간 때 내 소스코드를 직접 공격해보았다. 아무튼 해킹에는 성공했다.

 

  해킹에 성공한 경우 다음과 같이 "Successful hacking attempt"라는 메시지가 나온다. 해킹에 실패한 경우 "Unsuccessful hacking attempt"라고 나오며, 입력 자체가 잘못된 경우에는 "Invalid input"이라는 메시지가 나온다.

 

 

  해킹에 성공한 경우, 해킹을 당한 쪽은 다음과 같은 메시지가 출력된다.

 

 

  다음과 같이 스탠딩(Standing)에서는 "해킹 성공 횟수 : 해킹 실패 횟수" 정보가 출력된다.

 

 

  해킹 시스템은 상당히 재미있는 것 같다. 해킹 시스템이 있기 때문에, 채점 데이터셋은 더욱 견고해진다. 실제로 간당간당하게 시간 초과나 메모리 초과를 벗어난 코드들은 채점 데이터가 조금 더 추가되면, 운에 따라서 오답 코드로 처리되기도 한다. 나는 최근에 Pypy로 문제를 풀고 있는데, C++에서는 정답 처리가 될 법한 코드가 가끔씩 TLE를 받기도 한다.

 

[ 해킹용 입력 데이터 만드는 예제 코드 ]

 

import random

f = open("test.txt", 'w')
# The number of test cases
f.write('1\n')
# Input: N
f.write('10000\n')
for i in range(10000):
    # Make random data.
    f.write(str(random.randrange(1, 1001)) + ' ')
f.close()
728x90
반응형

728x90
반응형

  나는 최근에 디지털 카메라에 있는 동영상을 옮기기 위해서 SD 카드를 컴퓨터에 꽂았다. 그러다가 어느 순간에 보니까, 동영상 파일 몇 개가 사라져 있었다. 그리고 당황스러운 점은, 아래와 같이 "USBC族Q"라는 이름을 가지는 파일이 생성되어 있었다. 그냥 깨진 이름일 뿐 그다지 유의미한 이름은 아닌 것 같다.

 

  내 생각에는 디지털 카메라의 전원이 없어서 갑자기 종료가 되었거나, 아니면 SD 카드를 갑자기 컴퓨터에서 뽑거나, 혹은 SD카드 USB 리더기의 문제일 수도 있을 것 같다. 아무튼 이유가 무엇이든 데이터가 유실된 것으로 보인다. 데이터가 유실되는 과정에서 동영상 파일들이 하나의 파일로 합쳐진 게 아닐까 생각하고 있다. "USBC族Q"라는 이름을 가진 파일의 크기가 3GB인 것을 보면, 분명 이 파일이 기존의 동영상 파일들을 가지고 있을 것 같다.

 

  아무튼 확장자도 없고, 이 파일을 실행하는 것은 불가능해 보인다.

 

 

  그래서 데이터 복구 프로그램을 이용하기로 했다. 미디어 파일 (MP4, JPG 등)을 전문으로 복구해주는 프로그램이 필요한 상황인데, 어떤 것을 이용할 지 고민을 해보았다. 일단 혹시 모르니까, 현재 눈에 보이는 SD 카드 내부의 모든 파일들을 PC 내 별도의 폴더로 옮겨주었다. (일단 남아 있는 파일들은 최소한 안전하게 가지고 있어야 하기 때문이다.)

 

1. 레쿠바(Recuva)

 

  삭제된 파일을 복구하기 위한 유명한 복구 프로그램이다. 물론 나의 경우에는 파일을 삭제한 것이 아니라 파일의 메타 데이터에 문제가 생긴 것으로 판단이 들지만, 일단 가장 유명한 게 이것이기 때문에, 이를 사용해보기로 했다.

 

  ▶ 레쿠바 다운로드: https://software.naver.com/software/summary.nhn?softwareId=MFS_116447

 

 

  설치 프로그램을 다운로드 받아서 [Install] 버튼을 클릭하여 설치를 진행할 수 있다.

 

 

  설치가 완료되면 [Run Recuva] 버튼을 눌러서 레쿠바를 실행할 수 있다.

 

 

  레쿠바를 실행하면 다음과 같이 설정 진행 창이 나온다.

 

 

  복구하고자 하는 파일의 종류를 기록해준다.

 

 

  이후에 어떤 저장장치에서 파일을 찾을 건지 설정할 수 있다. 여기에서 나의 SD 카드 드라이브의 경로를 넣어 주었다.

 

 

  이제 복구를 해보자. [Enable Deep Scan]에 체크하여, 가능한 많은 파일들을 찾아낼 수 있도록 하자.

 

 

  스캔이 끝나고 나면, 다음과 같이 복구할 수 있는 파일들의 리스트가 등장한다. 다만, 필자의 경우에는 삭제했던 파일들은 복구가 가능한 경우가 많았지만, 갑자기 사라져 버린 파일들에 대해서는 레쿠바(Recuva)가 찾지 못했다. 아마 삭제 자체를 하지는 않았기에, SD 카드에 그대로 남아 있는 영역이라서 레쿠바가 찾지 못하는 것 같다.

 

 

2. 이지어스 데이터 복구 (EaseUS Data Recovery)

 

  그래서 다른 프로그램을 찾아보기로 했다. 그냥 인터넷에서 검색하다가 알게 된 소프트웨어인데, 일단 이것도 한 번 받아서 사용해보기로 했다.

 

  ▶ 설치 경로https://www.easeus.co.kr/data-recovery-solution/recover-video-files-from-dashcam-memory-card.html

 

  다음과 같이 [다운로드] 버튼을 눌러서 설치 프로그램을 다운로드 할 수 있다.

 

 

  설치를 진행해보자. 설치를 진행한 뒤에 보니까, 특정 용량 이상으로 복구하기 위해서는 유료 결제를 해야한다고 한다.

 

 

  아무튼 설치 이후에 디지털 카메라용 SD 카드를 선택해서 스캔을 해보았다.

 

 

  다만 엄청나게도 [손실된 파일] 영역으로, 내가 잃어버린 파일들이 모두 찾아지는 것을 확인할 수 있었다. 심지어 복구를 해보았더니, 영상이 잘 살아나는 것을 확인하였다. 역시 유료 프로그램이라서 더 성능이 좋은 것일까?

 

  그런데, 500MB 이상으로 복구하기 위해서는 유료 결제를 하라고 한다. 일단 시험 공부를 하러 가야 해서, 여기에서 잠깐 접고 나중에 무료 복구 프로그램이 있는지 더 찾아보려고 한다.

 

 

3. 체크디스크(CHKDSK) 명령 혹은 드라이브 검사 기능

 

  일단 위에서 소개한 이지어스 소프트웨어는 상당히 좋은 솔루션이지만, 유료이기 때문에 다른 방법들을 찾아보았다.

 

  윈도우(Windows) 운영체제는 기본적으로 체크디스크 명령을 지원한다. 이걸 사용하면 자동으로 손실된 파일들이 .CHK 확장자를 가지는 파일로 복구된다는 이야기를 들어서, 한 번 시도해보았다. 다음과 같이 [내 PC]로 이동해서 저장장치를 우클릭하여 [속성(R)]에 들어간다.

 

 

  다음과 같이 [도구] - [검사(C)] 버튼을 눌러서 검사를 진행한다.

 

 

  나는 드라이브에 오류가 없다고 나왔지만, 그래도 [드라이브 검사 및 복구] 버튼을 눌렀다.

 

 

  그랬더니 성공적으로 복구가 되었다는 메시지가 나왔다.

 

 

  근데 정작 DCIM 폴더로 들어가 보니까, 기존에 존재하던 105__04 폴더 자체가 사라졌다. 무언가 잘못된 것 같다는 직감이 들었다. 하지만 침착하게 해결 방법을 찾아 보았다.

 

 

  검색을 해보니까 체크디스크(CHKDSK) 명령을 한 이후에는 일부 파일들이 자동으로 복구가 되기도 하는데, 그 복구가 된 파일은 FOUND.000 폴더에 들어가게 된다는 것이다. 또한 해당 폴더는 '숨김 폴더'라서 숨김 항목을 볼 수 있도록 체크해야 한다. 하지만, 필자의 경우에는 어이없게도 숨김 항목들을 확인해도 FOUND.000이 보이지 않았다.

 

 

  속은셈 치고, USB 드라이브의 루트 폴더에서 'FILE'이라고 검색해보았다. 그랬더니 FOUND.000 폴더는 안 보이지만, 그 안에 있는 파일들은 보이게 되었다!

 

 

  이제 파일을 우클릭하여 [파일 위치 열기(I)]를 해서 폴더를 열어보았다.

 

 

  이제 FOUND.000 폴더에 있는 모든 복구된 파일들이 보이게 되었다. 이 파일들은 기본적으로 확장자 정보를 가지고 있지 않다. 그래서 추가적인 작업이 필요한데 나의 경우에는 이 파일들이 모두 동영상 파일(.mp4)이다. 그래서 그냥 확장자만 .mp4로 바꾸어주었더니 정상적으로 동작하게 되었다.

 

 

  그래서 다음과 같이 동영상 파일(.mp4)로 변경하여 실행했더니 정상적으로 동작하게 되었다.

 

 

  또한 동영상 파일의 메타 정보도 남아 있어서, '미디어 작성 날짜'도 확인할 수 있다.

 

 

4. 테스트디스크 (TestDisk)

 

  앞서 설명한 이지어스의 경우 유료 프로그램이기 때문에, 무료 프로그램을 검색하다가 TestDisk를 찾았었다. 결국 이걸 사용하지 않고도 해결하긴 했지만, 이런 무료 프로그램도 있다는 것을 기록해 놓고자 한다. 아래 링크에서 다운로드가 가능하다.

 

  ▶ 설치 경로https://www.cgsecurity.org/wiki/TestDisk_Download

 

 

728x90
반응형