[카테고리:] 생활코딩

  • wav를 mp3로 변환

    ffmpeg을 사용하여 간단한 스크립트를 작성했다. 다 좋은데 ffmpeg을 반복하면 stdin로 무엇을 받아들인다. 파일을 제대로 못 읽는다. -nostdin 옵션과 </dev/null을 주었는데 무엇때문인지 모르겠으나 잘 된다.

    #!/bin/bash
    
    echo "wav 파일을 mp3로 변환하는 스크립트"
    echo "파일 이름은 그대로 유지"
    echo "확장자를 mp3로 변경"
    
    echo "인자로 filelist를 입력"
    
    
    cat $1 |\
    	while read CMD;
    		do
    			echo $CMD;
    			
    			directory=$(dirname "$CMD");
    			filename=$(basename -s ".wav" "$CMD"); 
    			fileindex=$(echo $filename | cut -d ' ' -f1);
    			number=$(echo $filename | cut -d' ' -f2);
    			#echo $directory;
    			#echo $filename;
    			#echo $number;
    			#echo $directory"/"$fileindex$number".mp3";
    			ffmpeg -nostdin -y -i "$CMD" $directory"/"$fileindex$number".mp3"; < /dev/null;
    
    		done
    

    아래 사이트 참조했다.

    https://stackoverflow.com/questions/21634088/execute-ffmpeg-command-in-a-loop
    https://stackoverflow.com/questions/6121091/get-file-directory-path-from-file-path/6121114
    https://askubuntu.com/questions/919788/convert-mp3-file-to-wav-using-the-command-line
    http://bahndal.egloos.com/595136
  • Xbox 360 패드 아날로그 노브 바꿈

    Xbox 360 패드 아날로그 노브 바꿈

    5년넘게 사용하던 xbox 360패드 아날로그 노브?가 떨어져 나갔다. 카운터 스트라이크 GO를 마우스+키보드로 해야 킬수를 쉽게 올리는데 액박패드로 했다. 가뜩이나 잘 죽는데, 불량 아날로그 노브로 더 잘 죽는다. 이번 기회에 바꿔보기로 했다.

    11번가에서 패드 소모품을 따로 팔고있는 사람을 찾았다. 2개 3,000원에 구매했다.

    드라이버로 플라스틱 하우징을 분리했다. 볼트 7개 풀러야 하우징을 분리할 수 있다. 6개는 보여 쉽게 뺐는데, 스티커에 가려진 한 개는 어렵게 뺐다. 볼트 연결된 하우징을 무리하게 뜯어내다 뽀갤 뻔했다.

    기판, 진동모터, 스위치 및 아날로그 버튼 등으로 구성되어 있다. 왼쪽, 오른쪽 트리거는 얼마나 눌렸는지 수치로 표시된다. 내부 구조를 보면 스프링이 트리거를 원래 위치로 밀어주고, 얼마나 눌렸는지는 엔코더가 확인한다. 노브를 교체하고 다시 하우징을 조립한다. 패드 스위치와 별개로 카스 고에서 너무 잘 죽는다.

  • 노트북 한스타 패널 재활용

    노트북 한스타 패널 재활용

    내가 가졌던 노트북은 CQ61 presario이다. 정말 오래된 모델이다. 지금 사용하지 않는 노트북이다. 여기 LCD 패널을 떼어내어 확장 모니터로 사용할 생각이다. 노트북은 아직 잘 동작하는 듯 하다. 과감히 본체를 뜯어버리고, lcd 패널을 확인하니 대만? HANNSTAR 회사 제품이었다. 데이터시트는 아래와 같다.

    • 16인치 디스플레이로 가로 16: 세로 9.
    • LVDS 인터페이스.
    • 1366 by 768 해상도 지원.
    • 최대 4.0V logic Supply Voltage. 공급 전압 3.3V
    • 40핀 사용.

    여기 참조.

    기존 ad 보드를 뜯었기때문에, auction에서 만능 ad 보드를 구매했다. 판매자에게 물어보니 내가가진 패널을 사용할 수 있음을 알았다. 결선 틀림, 케이블 누락을 방지하기위해 단품보다 세트를 구매했다.

    파워 모듈이 받은 보드세트에 없었다. 구매 옵션에 없었지만 별도로 구매를 했어야했다. pcb에 12V로 기록되어 있어 이를 믿고 전에샀던 외장하드 드라이브 파워를 쓰기로했다. 기존 노트북에 붙어있던 40핀 lsvd? 케이블을 떼어냈다. 패널에 테이프로 붙어있었는데, 떼어보니 핀 커버까지 뜯겨나갔다. 새로온 보드 케이블을 연결하고 다시 조립했다.

    드디어 켰다. 문제가 무엇인지 모르겠으나, 패널이 지원하는 해상도로 동작하지 않았다. 왜 그런지 아직도 모르겠다. 구매처에 연락해보니 내가 가진 패널이 다른 사람들에게 많이 사용되는 제품이라했다. 해상도 또한 노트북 기본 설정이라 한다. 노트북 분해전 켜지 않았는데 패널 불량으로 의심된다. 특히 패널 케이스를 움직일시점 깜박임이 심해졌다. 절연 테잎으로 붙인 lsvd 케이블을 떼어내고 글루건으로 떡칠했다.

    삽질을 하다보니 주파수 75hz, 해상도 낮음 설정이 모니터를 동작시켰다. 다만 노이즈가 보이고 해상도가 낮아 눈아플 지경이다. 처음 꿈은 2축 모니터 암도 구매하여 피벗구성이었다. 그러나 지금 상태로 여기에 지출하는 한푼도 아깝다. 결국 테이프로 옆 모니터와 책상에 고정했다.

    만능 AD 보드가 대부분 패널을 구동시키는데, 깔끔하고 이쁘게 동작시키지 않는다. 중국제 싸구려 보드 특성으로 추측된다. ad 보드 개발 능력도 디스플레이 제작사 경쟁력이다. 회사 영업비밀에 해당할 것이다. 이런 성능을 나같은 일반인이 조정함은 쉽지 않다. 그냥 완성된 제품을 사는게 가격, 시간을 적게 쓴다. 이왕 산 제품 삼만원 버린셈 치고 그냥쓰다 버려야겠다. 이 모니터가 부서지면 좀 좋은 완제품을 사야겠다. 특히 패널을 어느 회사를 사용하는지 확인해야겠다. 엘지, 삼성은 전용 보드를 팔긴 팔았다.

    구매한 ad 보드로 좌우 여백을 맞출 수 없다. 여가 조정하려면 롬 라이터로 정확한 정보를 기록해야 하는데, 이 작업에 비용, 시간을 들여야한다. 케이스는 노트북 케이스 그대로 사용했다.

    삽질 결과, 노트북 패널 Contrast를 조정하면 1366 by 768 해상도를 사용할 수 있다. Contrast 0이면 모니터가 깜박이고, 어느수치 이하로 내려가면 잘 보인다.

  • 디지털 액자 개선

    디지털 액자 개선

    출장기간 남는 시간을 보내기 위해, 전에 만들던 디지털 액자를 다시 손보기로 했다. 전에 제작한 프로그램은 다음 문제점을 가지고 있다.

    1. 서버가 저장한 파일 이름을 받을 수 없음.
    2. 간혹 200개 중 몇 개 빼먹고 다운로드.
    3. 앱이 하루 중 특정 시각 파일을 받기 때문에, 앱이 정지되면 다음날까지 기다려야 함.

    1, 2 번을 수정했고 3번도 할 수 있으나 너무 많이 뜯어 고쳐야 하므로 안했다. socket을 열어 단순 파일만 받았으나, text를 전송하여 1. 전체 파일 개수 전송, 2. i번째 파일 이름, 크기 전송, 3. i번째 파일 내용 전송으로 바꿨다. 이 socket을 이용하여 앱에 특정 버튼을 만들어 서버에서 파일을 업데이트, 전송하게 할 수 있다. 대략 아래와 같이 구성했다.

    socket 으로 파일을 보낸 후 다음에 다시 쓰기위해 close 안했다. 이렇게 하면 받는 쪽이 얼마나 받을지 모르기 때문에, 크기를 전송했다.

    https://stackoverflow.com/questions/4886293/socket-input-stream-hangs-on-final-read-best-way-to-handle-this

    파일 전송 후, 바로 텍스트를 보내면 40개 정도 파일을 보내고 한없이 기다린다. 이 경우 다시 무엇인가 전송하도록 해줘야 하는데, 귀찮고 어려워 그냥 딜레이를 썼다. 이 물건을 더 뜯어 고치고 싶진 않다. 담엔 무엇을 해야 하나?

    서버 코드

    package sender;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class Main {
    	public static void main(String[] args) {
    
    		ServerSocket serverSocket = null;
    //		final String FILE_TO_SEND = "/home/now0930/tempPhoto/1234.jpg";
    //		byte[] myFileByteArray;
    		FileInputStream fis;
    		BufferedInputStream bis;
    //		File myFileToSend;
    		File myPhotoDirectory;
    		File[] myFiles;
    //		int i = 0;
    		String responderStr;
    		int action = 0;
    		final int DEFAULT_BUFFER_SIZE = 1000000;
    
    		boolean myDirectoryWasUpdated = false;
    		boolean ended = false;
    		int fileIndex = 0;
    		/*
    		 * try { serverSocket = new ServerSocket(9998); System.out.println(getTime() +
    		 * "서버가 준비되었음.");
    		 * 
    		 * } // try catch (IOException e) { e.printStackTrace(); } // catch
    		 */
    
    		// myFileToSend = new File(FILE_TO_SEND);
    		// myFileByteArray = new byte[(int)myFileToSend.length()];
    
    //		while (true) {
    		// 서버에서 실행 방법..
    		// script 실행 분.
    		// 서버가 특정 디렉토리에 특정 시각에 jpg file을 교체, 기존 파일을 삭제
    		// 종료 후, updated란 파일을 만듦.
    		// 특정 시각에 cron이 실행
    
    		// java 실행 분..
    		// 디렉토리에서 updated를 찾음..
    		// updated란 파일을 찾으면,
    		// socket.accept()로 일정시간 기다린 후,
    		// 응답.
    		// 파일 1회 전송후 process 종료.
    		// updated 파일 삭제
    
    		// updated 파일이 없으면
    		// 프로세스 종료..
    
    		// file 입출력..
    		// 디렉토리의 파일을 리스트로 만드는 부분.
    		// directory의 파일 찾기
    
    		myPhotoDirectory = new File("/home/now0930/tempPhoto");
    		myFiles = myPhotoDirectory.listFiles();
    		System.out.println("출력" + myFiles.length);
    
    		myDirectoryWasUpdated = false;
    		// updated 파일 확인..
    		for (int j = 0; j < myFiles.length; j++) {
    			if (myFiles[j].getName().equals("updated")) {
    				myDirectoryWasUpdated = true;
    				System.out.println("파일이 업데이트 되었음");
    				break;
    			}
    		} // for
    
    		// 파일이 업데이트 되지 않으면, while를 빠져 나감..
    		if (myDirectoryWasUpdated) {
    
    			try {
    				serverSocket = new ServerSocket(9998);
    				System.out.println(getTime() + "서버가 준비되었음.");
    				Socket socket = serverSocket.accept();
    				System.out.println(getTime() + socket.getInetAddress() + "로부터 연결이 들어옮");
    				InputStreamReader responder = new InputStreamReader(socket.getInputStream());
    				BufferedReader bfResponder = new BufferedReader(responder);
    				OutputStream out = socket.getOutputStream();
    				PrintWriter responderToClient = new PrintWriter(socket.getOutputStream());
    				String[] temp;
    				// 폴더의 파일 리스트 전송
    				System.out.println(getTime() + "서버가 대기중");
    				while (true) {
    					responderStr = bfResponder.readLine();
    					System.out.println(responderStr);
    					Pattern patFilename = Pattern.compile("send [0-9]{1,3} filename");
    					Pattern patFileContents = Pattern.compile("send [0-9]{1,3} filecontents");
    					Pattern patClose = Pattern.compile("close");
    					Matcher matFilename = patFilename.matcher(responderStr);
    					Matcher matFileContents = patFileContents.matcher(responderStr);
    					Matcher matClose = patClose.matcher(responderStr);
    					if (responderStr.equals("how many files has you?")) {
    						action = 1;
    					} else if (matFilename.find()) {
    						// 파일 인덱스를 세부 판단.
    						temp = responderStr.split(" ");
    						fileIndex = Integer.parseInt(temp[1]);
    						// action 4: client에 END를 보내고 소켓 닫음.
    						// updated를 지움
    						// action 2: client로 파일을 보냄.
    						action = (fileIndex >= myFiles.length) ? 4 : 2;
    
    					} else if (matFileContents.find()) {
    						action = 3;
    					} // match fileContents
    
    					switch (action) {
    					// 1: how many files have you?
    					case 1:
    						responderToClient.println("FileList: " + myFiles.length);
    						responderToClient.flush();
    						System.out.println("파일 갯수 보냄.");
    						break;
    					// send ??? filename
    					case 2:
    						System.out.println("정규식 감지됨");
    //						temp = responderStr.split(" ");
    //						fileIndex = Integer.parseInt(temp[1]);
    
    						// updated 파일을 보내지 않고, 그림 파일만 보냄.
    						// 파일 이름과 크기를 보냄.
    						// 크기를 보내야 받는쪽에서 얼마나 받을지 앎. 이후 판단.
    						if (myFiles[fileIndex].getName().contains("jpg") || myFiles[fileIndex].getName().contains("png")
    								|| myFiles[fileIndex].getName().contains("JPEG")
    								|| myFiles[fileIndex].getName().contains("JPG")) {
    							responderToClient.println("Filename: " + myFiles[fileIndex].getName() + ", FileSize: "
    									+ myFiles[fileIndex].length());
    							System.out.println("Filename: " + myFiles[fileIndex].getName() + ", FileSize: "
    									+ myFiles[fileIndex].length());
    							responderToClient.flush();
    						} else {
    							responderToClient.println("Filename: this is no image file");
    							responderToClient.flush();
    						}
    						break;
    					// send ??? filecontents
    					case 3:
    						/*
    						 * if (fileIndex >= myFiles.length) myFileByteArray = null; else myFileByteArray
    						 * = new byte[(int) myFiles[fileIndex].length()];
    						 */
    						// fis = new FileInputStream(myFileToSend);
    						// myFiles.length 가 0일 경우, myFiles[i]가 arrayOutOfBoundsException이 있음..
    
    						/**
    						 * if(myFiles.length !=0 && myFiles[i].exists()&& //updated란 파일을 안보내게 제외..
    						 * myFiles[i].getName()!="updated" && //확장자가 jpg만 보냄..
    						 * myFiles[i].getName().matches(".*\\.jpg")){
    						 **/
    						int readBytes;
    						byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
    						fis = new FileInputStream(myFiles[fileIndex].getPath());
    						bis = new BufferedInputStream(fis);
    						// bis.read(myFileByteArray,0,myFileByteArray.length);
    						// bis.read(myFileByteArray, 0, myFileByteArray.length);
    						while ((readBytes = fis.read(buffer)) > 0) {
    							out.write(buffer, 0, readBytes);
    							out.flush();
    						}
    						System.out.println(getTime() + myFiles[fileIndex].getPath() + "를 보냅니다.");
    						System.out.println(fileIndex + "번째 파일 전송 완료.");
    						// out, socket을 계속 사용하기 위해 닫지 않음.
    						break;
    
    					case 4:
    						// 보낼 파일을 가지고 있는지 확인.
    						// 마지막 파일이면 client로 END를 보내고 updated 파일 삭제.
    						if (fileIndex >= myFiles.length) {
    							responderToClient.println("End");
    							responderToClient.flush();
    							// App으로 END를 보내고 updated 파일 삭제.
    							ended = true;
    							// 파일 삭제 확인..
    							// j값을 기억하고 있다, 나중에 삭제..
    							for (int j = 0; j < myFiles.length; j++) {
    								if (myFiles[j].getName().equals("updated")) {
    									myDirectoryWasUpdated = false;
    									myFiles[j].delete();
    									System.out.println("파일이 삭제되었음");
    									break;
    								} // if
    							} // for
    
    						} // if fileIndex..
    						// switch, case break;
    						break;
    
    					}// switch
    					//switch문 실행시 다시 readline을 하지 않기 위해, 여기에서 강제 브레이크
    					if (ended) {
    						// close socket
    						socket.close();
    						System.out.println("Socket 닫힘");
    						// while break
    						break;
    					}
    				} // while
    
    			} // try
    			catch (IOException e) {
    				e.printStackTrace();
    			} // catch
    
    			catch (Exception e) {
    				e.printStackTrace();
    
    			} // catch
    
    		} // if myDirectory is updated?
    
    	}// main
    
    	private static String getTime() {
    		// TODO Auto-generated method stub
    		SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
    		return f.format(new Date());
    	}// getTime
    
    }
    

    클라이언트 코드(안드로이드 앱, Receiver 클래스)

    package tk.now0930.photoframev2;
    
    import android.content.Context;
    
    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.ConnectException;
    import java.net.Socket;
    import java.util.Calendar;
    import java.util.GregorianCalendar;
    import java.util.Locale;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.TimeUnit;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * Created by now0930 on 17. 9. 23.
     */
    
    public class LongTermTaskReceive {
        Timer myScheduler;
        TimerTask mLongTermTaskReceive;
        Calendar currentTime;
        public static final int ServerPort = 9999;
        String FileToReceive;
        byte[] myByteArray;
        File file;
        FileOutputStream fos;
        BufferedOutputStream bos;
        int bytesRead;
        int current = 0;
        private static int fileIndex = 0;
        long passedCheck, displayCheck;
        Context myContext;
        static int state = 0;
    
        LongTermTaskReceive(Context from) {
            this.myContext = from;
            currentTime = ((PhotoFrame) myContext).getCalendar().getInstance();
            myScheduler = ((PhotoFrame) myContext).getTimerRecive();
            fos = null;
            bos = null;
    
            mLongTermTaskReceive = new TimerTask() {
                @Override
                public void run() {
                    //매 턴 시각을 받기위해, run안에도 설정.
                    currentTime = ((PhotoFrame) myContext).getCalendar().getInstance();
                    //passedCheck>0 이면 지정 시각이 지났음..
                    passedCheck = currentTime.getTimeInMillis() - Constants.mReceiveTimeStop.getTimeInMillis();
                    //display할 시간인 지 확인..
                    //app이 충돌함..
                    displayCheck = currentTime.getTimeInMillis() - Constants.mShorttermTimeStart.getTimeInMillis();
    
                    if (displayCheck < 0) {
                        try {
                            String ServerIP = "192.168.1.73";
                            System.out.println("S:Connecting");
                            Socket socket = new Socket(ServerIP, 9998);
                            //파일 이름, 요청하기 위해 연결 설정.
                            PrintWriter askToServer = new PrintWriter(socket.getOutputStream());
                            InputStream in = socket.getInputStream();
                            String deciderStr;
                            InputStreamReader decieder = new InputStreamReader(socket.getInputStream());
                            BufferedReader bfDecieder = new BufferedReader(decieder);
                            //정규표현식을 사용하기 위해 Matcher, Pattern 설정.
                            String[] fileToAccept;
                            String fileNameTmp = "";
                            String fileSizeTmp = "";
                            int fileIndex = 0;
                            int i = 0;
                            while (true) {
                                switch (state) {
                                    //처음 파일 갯수요청
                                    //보냈을 때 바로 readline 실행.
                                    //같이 실행하지 않으면 한없이 기다릴 수 있음.
    
                                    case 0:
                                        askToServer.println("how many files has you?");
                                        askToServer.flush();
                                        deciderStr = bfDecieder.readLine();
                                        Pattern patFilelist = Pattern.compile("FileList: ");
                                        Matcher matFilelist = patFilelist.matcher(deciderStr);
                                        if (matFilelist.find()) {
                                            fileToAccept = deciderStr.split(" ");
                                            fileIndex = Integer.parseInt(fileToAccept[1]);
                                            state = 1;
                                        }
                                        //파일 갯수 수신 대기
                                        // 서버가 전송한 메세지를 분석하는 부분..
                                        //다음에 어느 스테이트로 갈지 결정.
                                        //여기로 들어오면 항상 기다릴 수 있음.
                                        //전 스텝에서 메세지를 하나 보내야 됨.
                                        //여기로 들어오면 일단 다른 case로 나감.
                                        //i번째 파일 이름 요청, 받은 후 i 증가.
                                        break;
                                    case 1:
                                        askToServer.println("send " + i + " filename");
                                        askToServer.flush();
                                        deciderStr = bfDecieder.readLine();
                                        Pattern patFilename = Pattern.compile("Filename:( .*.(jpg|png|JPG|JPEG)), FileSize: ([0-9]{0,10})");
                                        Matcher matFilename = patFilename.matcher(deciderStr);
                                        Pattern patEnd = Pattern.compile("End");
                                        Matcher matEnd = patEnd.matcher(deciderStr);
                                        if (matFilename.find()) {
                                            fileNameTmp = matFilename.group(1);
                                            fileSizeTmp = matFilename.group(3);
                                            //fileSizeTmp 크기 버퍼를 만듦.
                                            //socket에서 오는 입력을 버퍼로 써주고, 마지막까지 읽으면 파일로 써줌.
                                            myByteArray = new byte[Integer.parseInt(fileSizeTmp)];
                                            System.out.println("filename is: " + fileNameTmp);
                                            System.out.println("filesize is: " + fileSizeTmp);
                                            state = 2;
                                        } else if (matEnd.find()) {
                                            state = 5;
                                            break;
                                        } else {
                                            i++;
                                            state = 1;
                                        }
                                        break;
                                    //이미 보내진 파일 갯수를 보고 파일 수신.
                                    case 2:
                                        //FileToReceive = "receivedFile" + fileIndex + ".jpg";
                                        askToServer.println("send " + i + " filecontents");
                                        askToServer.flush();
    
                                        file = new File(Constants.FileDirectory, fileNameTmp);
                                        fos = new FileOutputStream(file);
                                        //System.out.println("파일 출력 위치"+((PhotoFrame)myContext).getApplicationContext().getFilesDir());
                                        System.out.println("파일 출력 위치" + file.getAbsoluteFile());
                                        bos = new BufferedOutputStream(fos);
                                        bytesRead = in.read(myByteArray, 0, myByteArray.length);
                                        current = bytesRead;
                                        do {
                                            bytesRead = in.read(myByteArray, current, (myByteArray.length - current));
                                            if (bytesRead >= 0)
                                                current += bytesRead;
                                            //socekt이 끊기면 빠저나감.
    
                                            if (bytesRead == -1)
                                                break;
                                        } while (myByteArray.length > current);
                                        bos.write(myByteArray, 0, current);
                                        i++;
                                        //다음에 소켓을 사용해야 하므로 끊어주면 안됨
                                        //bos.flush();
                                        //in.close();
                                        //파일을 수신하고 있다고 메세지를 보냄..
                                        ((PhotoFrame) myContext).myHandler.sendEmptyMessage(1);
                                        System.out.println("message..파일 수신.");
                                        state = 1;
                                        //너무 빠르면 socket 전송을 잃어버림.
                                        //서버가 충분하게 읽을 수 있도록 적정 시간 지연.
                                        TimeUnit.SECONDS.sleep(1);
                                        break;
    
                                    //연결 종료.
                                    case 5:
                                        System.out.println("연결 종료됨.");
                                        in.close();
                                        //while문을 나가면 처음부터 다시 시작.
                                        //while loop를 유지하여 여기에서 close하고, state 6에서 대기.
                                        state = 6;
                                        break;
                                    case 6:
                                        TimeUnit.SECONDS.sleep(10);
                                        break;
                                }//switch
    
                            } //while
    
    
                        }   //try
    
                        catch (ConnectException e) {
                            e.printStackTrace();
                        } //catch, ConnectException
    
                        catch (IOException e) {
                            e.printStackTrace();
                        }//catch, IOException
    
                        catch (Exception e) {
                            e.printStackTrace();
                        }   //catch, Exception
    
                    }//display 시간 확인..
    
                    if (passedCheck > 0) {
                        System.out.println("message...Receive 타이머가 cancel..");
                        ((PhotoFrame) myContext).myTimerThread.setReceiveTimerFlagFLASE();
                        cancel();
                    }//if
    
    
                }//run
            };//TimerTask
            //특정 시각에 작업 시행..오후 8시 57분..
            myScheduler.schedule(mLongTermTaskReceive, Constants.mReceiveTimeStart.getTime(), TimeUnit.MILLISECONDS.convert(3, TimeUnit.SECONDS));
            System.out.println("ReceiveTime 시각은.." + Constants.mReceiveTimeStart.getTime());
        }//LongTermTaskReceive
    
    
    }

    안드로이드 전체 앱

  • ubuntu 18.04 optimus 설정

    ubuntu 18.04 optimus 설정

    https://medium.com/@agathver/nvidia-gpu-optimus-prime-and-ubuntu-18-04-woes-f52e7f850f3d

    https://askubuntu.com/questions/927199/nvidia-smi-has-failed-because-it-couldnt-communicate-with-the-nvidia-driver-ma

    다시 optimus와 기나긴 싸움을 시작했다. 다행히 이번에 좋은 사이트를 찾아 쉽게 했다. 맨 위 링크.

    핵심은 1. ubuntu가 지원하는 드라이버를 설치하고, 2. 커널에 드라이버를 올리지 않도록 nouveau를 blacklist에 추가함이다. 노트북 전력을 절약하려면 bbswitch를 설치하여 부팅시 외장 그래픽카드를 동작하지 않도록 해야한다. 그러나 내 노트북 배터리 충전이 안된다. 항상 외장 그래픽 카드를 살렸다. 우분투 18.04로 넘어오면서 내장 카드로는 일반 작업도 버겁다.

    7월 20일 업데이트.

    커널 5.2로 올리다 드라이버 버전 340을 설치했다 실패했다. 파일을 잘못 지우는 바람에 GUI로 안들어가 18.04.2를 설치했다. 과거와 다르게 비디오 램을 제대로 사용한다. 아마 nvidia 서비스를 블랙 리스트로 넣어서 그랬나 보다.