기존 FILE STREAM의 단점을 해결해 보려고 다시 세팅  하려 했으나 역시 책이 없으면 안되는  머리에.. 검색으로 남겨둡니다.

#원본 http://jgwk.tistory.com/14

오류 메시지
FILESTREAM 기능을 사용할 수 없습니다.


해결방법
1.시작 메뉴에서 모든 프로그램, Microsoft SQL Server 2008 R2, 구성 도구를 차례로 가리킨 다음 SQL Server 구성 관리자를 클릭합니다.
2.서비스 목록에서 SQL Server 서비스를 마우스 오른쪽 단추로 클릭한 다음 열기를 클릭합니다.
3.SQL Server 구성 관리자 스냅인에서 FILESTREAM을 사용할 SQL Server 인스턴스를 찾습니다.
4.해당 인스턴스를 마우스 오른쪽 단추로 클릭한 다음 속성을 클릭합니다.
5.SQL Server 속성 대화 상자에서 FILESTREAM 탭을 클릭합니다.
6.Transact-SQL 액세스에 FILESTREAM 사용 확인란을 선택합니다.
7.Windows에서 FILESTREAM 데이터를 읽고 쓰려는 경우 파일 I/O 스트리밍 액세스에 FILESTREAM 사용을 클릭합니다. Windows 공유 이름 상자에 Windows 공유의 이름을 입력합니다.
8.원격 클라이언트가 이 공유에 저장된 FILESTREAM 데이터에 액세스해야 하는 경우 원격 클라이언트가 FILESTREAM 데이터에 대한 스트리밍 액세스를 가질 수 있도록 허용을 선택합니다.
9.적용을 클릭합니다.
10.SQL Server Management Studio에서 새 쿼리를 클릭하여 쿼리 편집기를 표시합니다.
11.쿼리 편집기에서 다음 Transact-SQL 코드를 입력합니다.

   EXEC sp_configure filestream_access_level, 2 (실행)
   RECONFIGURE (실행)

http://technet.microsoft.com/ko-kr/library/cc645923.aspx

블로그 이미지

UART

,

USIM기변하여 사용을 하다가 일반 요금제로 바꿨습니다. (피쳐폰유저로 변신) 

데이터 사용을 하면 요금 폭탄을 맞을 수 있는 상황이라 114와 통화하여 

"무선인터넷 제한"서비스를 신청을 했습니다만 LTE 기기에 3G USIM를 넣으면 자동 해지 된다고 합니다.

이 글은 데이터 사용이 불안하여 3G나 LTE데이터를 사용하지 않고 MMS만 사용하기 위한 삽질의 내용입니다. 보통 데이터가 활성화 되어 있으니, MMS만 사용하려면 데이터 통신을 켜고 끄는 것이 불편해서 사용하는 방법입니다.

가장 좋은 방법은  APN를 변경을 하면 편하게 MMS만 사용할 수 있다고 하여  APN 모두 삭제후 변경하는 방법을 사용했었습니다.  하지만 뭔가 다른 글에서 사용한 방법으로는 안되어 이것저것 방법 찾기를 반복했습니다.  

해서 아래와 같이 하면 같은 기종(LG 뷰2)을 가진 분은  잘 될 것입니다. 따라서 해 보세요.  

그럼 시작합니다.

설정에서 "홈 - 시스템설정 - 무선 및 네트워크-추가설정 - 모바일 네트웍크 - 액세스 포인트 이름"  을  선택하시면 여러가지 APN 목록이 나옵니다.  모두 내용안으로 들어가셔서 설정들을 메모 하여 두시고(혹시 모르니까요.) 

그 중 맨 위에 있는 하나를  클릭하시고 아래로 스크롤 해보시면 "APN 유형"이 있습니다.

아마 디폴트로 default,xxxx,supl,xxx,mms,xxx 기타 등등이 있습니다.  

여기서 그냥 default를 nodefault로 하시고 나머지는 그냥 두세요.

그리고 백(back)버튼을 누르지 마시고 메뉴버튼을 누르면 저장메뉴가 나옵니다. 이를 선택하여 저장 하세요.

나머지 APN 목록에서 모두 이렇게 해주세요.  혹, "APN 유형"에 비여있으면 "nodefault,mms"만 넣어두세요. 같은 작업을 하시면 됩니다. "ims"도 있는데 손대지 않아도 됩니다.  

그럼 이후 부터 데이터 사용 활성화 되어 있어도, mms는 되면서 데이터 통신은 하지 않습니다 .

매우 만족합니다 .^_^&

방법 추가 : APN 수정해서 apn 항목만 mmsonly.sktelecom.com으로 하고 나머지는 디폴트로 하면 mms만 됩니다.

위 방법이 안될시 시도해 보세요. ^^

혹, 안되시는 분은 덧글 달아 주세요.

*** 안되는 부분이 다시 발생 했는데..  이유를 몰랐습니다.  한동안 고민했으나 오늘 확인 되었습니다. ***

 유심이 테스트를 한다고 다른 것을 끼워서 사용을 잠깐 했는데.. 이것을 인식하느라 LTE가 활성화 되었습니다.

이걸 모르고 LTE로 망접속을 하고 있는데, 나는 3G USIM으로 설정을 하고 테스트하고 있으니 될리가 없었습니다.

기존 3G든 LTE 유심이든 꺼내고 다시 끼우거나 다른 것으로 교체한 후 다시 SKT 3G USIM 사용시 반드시 "LTE 네트웍크 사용하지 않음"을  재 설정 해야 합니다.

 

## Vu2가 버젼업(4.4.2) 되면서 "APN유형"에서 mms가 빠져있습니다. 이럴 때는 추가 해주면 됩니다.

방법은 아래 글(http://uart2013.tistory.com/29)을 참조 하세요.

 

 

블로그 이미지

UART

,

이 글은 KT기기를 SKT 3G 유심으로 사용하는 이야기 입니다.

사용하다보면 KT기기는 가격 대비 매우 훌륭합니다.단지 필요없는 어플이 좀 깔려있다는 것 정도 입니다. 개인적인 사정으로 SKT를 떠날 수 없기에 KT 용 뷰2를 SK USIM를 사용하려 진행 했습니다.

KT LTE 기기 –> SK 사용은 3G 용으로 바뀐다는 것 정도 간혹 LTE도 혼용된다는 기기도 있습니만 제한이 있다고 합니다.

아무튼, 결론은 SKT 3G USIM 사용은 문제가 없다 입니다.  

제 경우 KT 뷰2를  해지 하여 공기계 상태로 하고 USIM 기변을 하려 했습니다.

이때 별 생각없이 3G  SK USIM을 빼어 보니 일반 유심이였습니다. 근데, 뷰2는 마이크로 유심입니다.

유심 사이즈가 문제가 되었습니다. 해결하려 인터넷 검색해보니 커팅기도 있고 칼가위 등 사용방법이 있더군요. 커팅기 구매를 하자니 비싸기도 하고 그냥 안되면 다시 사지란 생각으로 칼이나  가위로 잘라서 하는 사용기를 찾아서 따라 했습니다.

 전 잘 되었지만 잘안되는 분도 계실 것입니다. 
(아무튼 이렇게 해서 안되면 9천원 짜리 통합 유심을 구매하시여 하세요. ^^; 또는 대리점같은 곳에서 커팅기를 비치하여 사용할 수 있게 한 곳도 있답니다.)

끼우고 재부팅 몇번 하시면,  잘  됩니다. 백퍼센트 ..
일단 SK 망이 인식이 안되면 다른 이유가 있을 것 같습니다. USIM 락이라든가 뷰2 기기의 락등등 해결 방법은 검색으로 확인 해 보세요.

전 SKT망이 자동으로 인식되고  MMS도 잘 됩니다. 데이터 통신도 잘 됩니다.  
데이터 이동은 GOOGLE 의 각종 서비스를 사용하니 별 문제 없네요. 
문자,주소록 모두 옮겼습니다.

크게 중요하지는 않지만  휴대폰 하드웨어는 3G/LTE 겸용이나 사용하는 USIM는  3G USIM 이고 LTE를 사용할 수 없으니 "LTE 네트웍크 설정 사용하지 않음"  변경을 시도 했습니다. 인터넷 검색으로 방법을 찾아서 먼저 "*1232580#" 으로 다이얼 했습니다만 이것은 SKT용인가 봅니다. 기기 펌웨어 또는  업데이트 때문인지 다른 방식으로 바뀐 것인지 암튼 안되었습니다.  

추가 검색으로  찾아서 보니, "*147359#"를 다이얼패드에서 입력하면 "LTE 네트웍크 사용하지 않음"을  선택할 수 있습니다.

** 추가 사항**
LTE 사용으로 되어 있으면, 3G USIM 사용에서 MMS만 활성화 되지 않습니다.

 

블로그 이미지

UART

,

모달리스 대화 상자 제어하기란 속성을 변경한다는 것도 들어갑니다만 

여기서는 모달리스에서 어떤 이벤트가 발생시 특정처리해야 할 것을 이야기 합니다.

이전에 C++ 에서 모달리스 에게 자신의 포인터를 넘겨서 특정 처리를  했습니다만  C#에서는 이벤트를 등록하여 처리하도록 권하고 있습니다.

 

먼저 모달리스 폼 측 (UserForm : Form )

public event EventHandler  doEvent;  // 이벤트 선언

if( doEvent != null ) doEvent(this, new EventArgs());  // 이벤트호출

 

다음 모달리스 폼 호출 측

 

1. 처리 함수 정의

public void  DoEvent( object obj, EventArgs e)

{

     UserForm dlg = obj as UserForm;

     //dlg를 통하여 처리

}

 

2. 모달리스폼 호출시 정의

UserForm dlg = new UserForm();

dlg.Owner = this;

dlg.doEvent += new EventHandler(DoEvent);

dlg.Show();


블로그 이미지

UART

,

원본 : http://narsus.net/technotes/1300

Visual C++를 사용하다 보면 여러가지 파일들이 자동으로 생성되는데,
이들 중 다음 파일들은 항상 자동 생성될 수 있으므로 백업시 삭제하여도 무방하며
CVS와 같은 소스관리 프로그램에는 추가되지 않도록 하는 것이 좋다.
# Visual C++에서 지워도 되는 파일들
*.pch *.mdp *.ncb *.clw *.obj *.aps *.cpl *.awk *.exp *.idb
*.opt *.pdb *.map *.res *.ilk *.scc *.bsc *.sbr *.tlb *.plg
*.lib *.dll *.exe
# 그러나, 다음 파일들은 지워서는 안된다.
*.mak, *.dsp, *.c, *.rc, *.rc2, *.ico, *.bmp, *.txt, *.def, *.hpj, *.bat, *.rtf,
*.odl, *.inf, *.reg, *.cnt, *.cpp, *.cxx, *.h, *.hpp, *.hxx, *.inl, *.tpl, *.vtp, *.mst
*--- 파일 확장자별 설명 ----------------------------------------------------------*
참고로, 아래의 설명은 MSDN 도움말에서 발췌한 것임을 밝혀둔다.
*--------------------------------------------------------------------------------*
.C/.CPP/.H/.HPP/.HXX
프로그램 소스 파일
.INL
인라인 함수 파일: 인라인 함수들에 대한 정의 포함
.RC or .RC2
윈도우 리소스 파일(Resource file)
.DEF
모듈 정의 파일(Module definition file)
.APS -- Binary version of the resource file:
This is the binary version of the current resource file. App Studio or the resource editor uses it for quick loading.
.BSC -- Browser database file:
A single .BSC file is created for each project. To use the Browser, you need to open this file in the Visual C++ Workbench. It is created from the .SBR files when the BSCMAKE tool is run.
.CLW -- Class Wizard status file:
This file keeps information about where message-handling functions are kept in your code. The format of this text file is undocumented, but it can be regenerated. For more information on how to regenerate this file, please click Contents on the Help menu in App Studio; then click "Using Class Wizard" and "Update Class Wizard when Code Changes."
.EXE or .DLL -- Executable or dynamic link library file:
This file is the final linked output file for the project. It contains executable code.
.ILK (versions 2.0 and later only) -- Incremental link information file:
The linker creates this file to allow incremental linking when possible. If you delete it, you will force the linker to perform a full link.
.OBJ -- Object module file:
This is the final output file from the compiler. The linker combines these files to create the final .EXE, .DLL, or .LIB file. The .OBJ files may have different formats in different versions of Visual C++ or in different vendor's compilers.
.PCH -- Precompiled header file:
These files can significantly speed up compile time. They are created when using the /Yc, /Yu, or /YX compiler options.
.PDB -- Program database file:
This binary file contains type and symbolic debugging information gathered over the course of compiling and linking the project. The file is for use with the Visual C++ debugger. Object files contain references into the .PDB file for debugging information. This design makes object files smaller. See the online reference under the /Zi switch for more information. When you use the /Z7 switch, this file is not created.
.SBR -- Source browser file:
This file is created for each source file compiled with either the /FR or /Fr switch. This file contains symbolic information used by the Microsoft Browser Database Maintenance Utility (BSCMAKE) to produce a browser database file (.BSC file).
.WSP -- Workspace information file (16-bit versions only):
This is a binary file containing information about the state of the WorkBench when it was closed. Such items as source files opened and their window positions are saved in this file.
.VCP -- Workspace information file (Visual C++ 2.x and later only):
This file is the Visual C++ version 2.x equivalent of the 16-bit versions' .WSP file.
.VCW -- Visual WorkBench Status file (16-bit versions only):
This file is created on a per-project basis. It works with the .MAK file to fully describe the project to the WorkBench.
.EXP -- Export file:
Export files contain information about exported functions and data items. When LIB creates an import library, it also creates an export file. You use the .EXP file when you link a program that both exports to and imports from another program, either directly or indirectly. If you link with an .EXP file, LINK does not produce an import library because it assumes that LIB already created one.
.LIB -- Library file:
These files could be standard library or import library files. Standard libraries contain objects and are created by the LIB tool. Import libraries contain information about exports in other programs and are created either by LINK when it builds a program that contains exports or by the LIB tool.
.MAP -- Map file:
A map file is a text file that contains information about the program being linked. The information includes the module name, the timestamp from the program file header (not from the file system), and a list of groups in the program with each group's starting address, length, group name, and class. It also contains a list of public symbols with each address, symbol name, flat address, and object file where the symbol is defined. A map file also includes the entry point of the program and a list of fixups.
.RES -- Compiled resource file:
The .RES file is created by the Resource Compiler (RC).
.HPJ -- Context-sensitive help project file:
This file appears when you use the Visual C++ AppWizard to create an MFC application that supports context-sensitive help. You need this file to create help files from the .RTF files and .BMP files generated by the AppWizard.
NCB -- Parser information file:
This file contains information generated by the parser used by the class view and component gallery. If the file is accidentally or deliberately deleted, it is automatically regenerated.
MDP -- Microsoft Developer studio Project file:
This file replaces Visual C++ version 2.x's .VCP file. The .MDP file contains more information about the project than does the .VCP file.
RCT -- Resource template file:
These files contain information on custom resources that can be used when you insert a resource. It can include menus, toolbars, bitmaps and any of the other resource types listed in the Insert Resource menu.
다음은 빌드 과정에서 임시로 생겼다가 사라지는두 가지 파일 들이다.
.CRF -- linker response file:
This file is created on the fly by the build process.
MSVC.BND -- copy of project .CRF file:
This file is created if the resources need to be bound to the executable. It is simply a copy of the project's .CRF file. There are some other files created depending on the features the project supports. For example, your project may also have one or more icon files with .ICO extensions, cursor files with .CUR extensions, or bitmap files with .BMP extensions. A project may also have a .REG file that has registry information for the project. Projects that support OLE may also have an .ODL file and .TLB files.

블로그 이미지

UART

,

오늘 갑자기 코딩을 하다가 보니 기존 4개의 함수를 순차적으로 부르고 있었으나 개수가 더 늘어날 수 있어서,

함수 포인터를 사용하고 싶었다. 책도 없고 기억도 가물한 상황 , 삽질을 해야 하나 귀찮기도 하여 검색했더니 훌륭한 정리 글을 볼 수 있었다.  아래 글... 보자.

 

출처 : http://zeph.tistory.com/155

함수 포인터 및 클래스 멤버함수의 함수포인터화

무슨 바람이 불었는지 갑자기 이런글이 쓰고 싶어져서 후다닥 써봤다;
틀린점이 많을지도...;ㅁ;
(사실 모 카페의 압박이..--;;)
///////////////////////////
< 함수 포인터 >
먼저 이 글은 포인터에 대한 이해를 필요로 한다.
포인터에 대한 기본지식이 있다고 가정하고 글을 쓰도록 하겠다.

int GetAreaEx( int x, int y )
{
    return x * y;
}

우선 이런 간단한 함수가 있다. 우리는 이 함수를 호출하기 위해 명시적으로
GetAreaEx( x, y );
이런식으로 기술해야 한다.
하지만 예를 들어 GetArea2, GetArea3, ..., GetAreaN 이런식으로 비슷한 함수가 존재하고
이를 상황에따라 다르게 호출해야 한다면 이 방식으로는 관리도 어려울 뿐더러 효율성도 떨어지고 코드량도 많이질 것이다.
또한 외부(스크립트 등)에서 어떤 특정한 함수를 호출하려 할때도 방법이 묘연할 것이다.
int (*GetArea)( int, int );
이 선언은 무엇일까?
언뜻보기에는 함수를 선언하는 것 같다.
이 선언은 함수에 대한 포인터를 선언한 것이다.
변수의 주소를 담는 포인터와 마찬가지로 함수포인터는 함수의 주소를 담는다.

GetArea = GetAreaEx; // 함수포인터 GetArea에 GetAreaEx()의 주소를 담는다
int nArea = (*GetArea)( x, y ); // (*GetArea)( x, y ); 로 GetAreaEx()함수를 호출하고 리턴받은 값을 nArea에 대입

이런식으로 GetAreaEx를 호출할 수 있다.
유의할점은 *GetArea를 꼭 ()로 감싸주어야 한다는 사실이다.
빼먹으면 컴파일러가 함수포인터를 통한 호출로 인식하지 못한다.
int (*GetArea[])( int, int ) = { GetAreaEx, GetArea2, GetArea3, ..., GetAreaN };
이것은 함수포인터 배열을 정적으로 선언한 것이다. 이렇게 배열로 기능이 비슷한 함수들을 묶어놓았다.

void CallFunc( int nState, int x, y )
{
    int nResult = (*GetArea[nState])( x, y );
}

그리고 그 함수들을 상황에 맞게 호출한다.
만약 함수포인터를 쓰지 않는다면

void CallFunc( int nState, int x, int y )
{
    int nResult;
    switch( nState )
    {
         case STATE_EX:
              nResult = GetAreaEx( x, y );
         break;
         case STATE_2:
              nResult = GetArea2( x, y );
         break;
         case STATE_3:
              nResult = GetArea3( x, y );
         break;
    }
}

위와 같이 기술해야 할 것이다.
두 방식의 차이점과 함수포인터의 이점을 알 수 있겠는가
그렇다면 함수포인터 배열을 동적으로 할당하는 방법은 없을까?
다음과 같은 방법으로 할당할 수 있다.

int (**GetArea)( int, int ); // 함수포인터의 포인터
GetArea = new (int (*[N])( int, int )); // N은 배열의 크기

그리고 다음과 같이 사용하면 된다.

GetArea[0] = GetAreaEx;
GetArea[1] = GetArea2;
GetArea[2] = GetArea3;
...
int nResult = (*GetArea[nState])( x, y );

물론 사용후 delete [] GetArea; 해서 해제하는것을 잊으면 안된다.
< 클래스 멤버함수의 함수포인터화 >
함수포인터는 함수의 주소값을 담는다고 했다.
그렇다면 클래스 멤버함수의 주소값도 단순히 함수포인터에 담아서 호출할 수 있지 않을까?
int (*func)();
func = CFunc::GetArea;

하지만 이 방법은 GetArea()멤버함수가 static으로 선언되었을 때만 가능하다.
static으로 선언되지 않은 멤버함수(멤버변수를 건들여야 하는 멤버함수)를 이 방법으로 담으려 한다면 컴파일 에러가 뜰 것이다.
여기에 다음과 같은 해결방법이 있다.
첫번째 방법은

class CFunc
{
public:
    static int GetArea( CFunc * cls, int x, int y );
};

위와 같이 선언하고 호출할때 해당 인트턴스의 포인터를 넘겨줘서

int GetArea( CFunc * cls, int x, int y )
{
    int a = cls->GetZ();
}

이런식으로 멤버변수를 읽거나 쓸수 있겠지만 이 방식으로는 한계가 있다.
Get, Set 같은 public 외부함수로 억세스하지 않으면 private나 protected안에 선언되어 있는
멤버변수는 건드릴 수 없다.
두번째는 멤버함수의 소속을 명시화하는 방법이다.

int (CFunc::*func)( int, int );
func = CFunc::GetArea;
CFunc A;
(A.*func)( x, y );

위와 같은 방법으로 해결가능하다. 물론 호출할 인스턴스가 명확해야 한다.
세번째는 클래스 안에 함수포인터를 멤버변수로 두고 별도의 함수포인터를 컨트롤하는 멤버함수를 만드는 방법이 있다.
이 방법이 멤버함수 관리가 가장 쉬우며 효율적이다.

class CFunc
{
public:
    int (CFunc::*pFunc)( int, int );
    int GetArea( int x, int y );
    void CallFunc( void ) { (this->*pFunc)( x, y ); } // CallFunc 함수호출시 자체 오버헤드를 줄이기 위해 inline
    CFunc();
    ~CFunc() {}
};
CFunc::CFunc()
{
    pFunc = GetArea;
}
int CFunc::GetArea( int x, int y )
{
    return x * y;
}

위와 같다면 CallFunc(); 로 GetArea 호출이 가능해진다.
지금은 단순히 한개의 멤버함수 호출만 할뿐 의미가 없다. 이제 실제 효율적으로 쓰이게 배열을 써보자.

class CFunc
{
public:
    int (CFunc::**pFunc)( int, int );
    int GetArea( int x, int y );
    void CallFunc( int nState, int x, int y ) { (this->*pFunc[nState])( x, y ); }
    CFunc();
    ~CFunc();
};
CFunc::CFunc()
{
// init
    pFunc = new (int (CFunc::*[10])( int, int )); // 동적할당, 10에는 원하는 멤버함수 갯수만큼
// 0번은 남겨둔다.
    pFunc[1] = GetArea;
    pFunc[2] = GetAreaEx;
    pFunc[3] = GetArea2;
    pFunc[4] = GetArea3;
    ...
    pFunc[9] = GetArea9;
}
CFunc::~CFunc()
{
    delete [] pFunc; // 해제
}
int CFunc::GetArea( int x, int y )
{
    return x * y;
}

자, 이제 함수하나의 호출로 상황에따라 여러 멤버함수를 호출할 수 있는 기반이 마련되었다.

CFunc A;
A.CallFunc( nState, x, y );

이렇게...
어떠한가. 함수포인터의 위력이 느껴지는가?
< STL을 이용한 함수포인터 관리 >
우리는 지금까지 함수포인터를 동적으로 배열을 할당해서 써왔다.
함수 포인터를 STL(Standard Template Library)을 써서 관리해보자.
클래스의 멤버함수의 함수포인터화에서 3번째 방법을 조금 개선시켜 보겠다.
단순히 인덱스(숫자)를 이용한 관리라면 deque정도가 괜찮을듯 싶으나,
만약 함수의 이름을 문자열로 호출하고 싶다면 map을 써볼 수 있다.
(만약 FuncCall( "GetArea", x, y ); 이런식으로 멤버함수를 호출하고 싶다면)
map은 내부적으로 트리구조를 가지고 있다.
그래서 따로 정적/동적으로 배열을 할당하지 않아도 입력된 값을 비교해서 스스로 자신의 크기를 늘린다.
mapValue["GetArea"] = 99;
이런식으로 []안에 숫자 뿐만아니라 비교할 수 있는 모든 것이 들어갈 수 있다.
먼저 map을 사용하기 위해

#include < map >
using namespace std;

를 선언한다. map은 표준 네임스페이스를 사용하므로 std의 이름공간을 활용한다.
map< []안에 들어갈 타입, 입력될 데이터타입, 비교 논리 > mapFunctor;
선언방법은 이렇게 되는데 비교 논리는 첫번째 인수가 클래스이고 안에 비교오퍼레이터가 있다면 생략가능하다
자, 이제 해보자.

struct ltstr
{
    bool operator() ( const char * s1, const char * s2 ) const
    {
         return strcmp( s1, s2 ) < 0;
    }
};
class CFunc
{
public:
    typedef int (CFunc::*_Func)( int, int );
    map< const char *, _Func, ltstr > mapFunctor;
    int GetArea( int x, int y );
    void CallFunc( const char * szFuncName, int x, int y )
    {
         (this->*mapFunctor[szFuncName])( x, y );
    }
    CFunc();
    ~CFunc();
};
CFunc::CFunc()
{
// init
    mapFunctor["GetArea"] = GetArea;
    mapFunctor["GetAreaEx"] = GetAreaEx;
}
CFunc::~CFunc()
{
// map 클리어
    mapFunctor.clear();
}
int CFunc::GetArea( int x, int y )
{
    return x * y;
}

char * 대신 string을 사용한다면 string안에 내부적으로 비교 오퍼레이터함수가 있기 때문에
map< string, _Func > mapFunctor;
이렇게 선언하고 사용할 수 있을 것이다.
이제 A.CallFunc( "GetAreaEx", x, y ); 란 호출로 GetAreaEx를 호출할 수 있다.
이 방식은 여러가지로 응용가능한데 스킬명에 의한 화면효과 호출이라던지
C로 미리 작성된 내부 함수를 외부 스크립트로 호출한다던지 할때 유용하게 쓰일 수 있다.
(스크립트 호출일 경우 함수이름을 인덱스화 해서 deque를 쓰는게 속도상 더 유리할 듯 하다)
< Caution >
- 귀차니즘의 관계로 클래스내에 GetAreaEx, GetArea2 등과 같은 멤버함수를 모두 기술하지는 않았습니다.
- 예제 소스는 컴파일해보지 않은 소스들이므로 오타나 잘못된 점이 있을 수도 있습니다. 지적 바랍니다.
- VS 2005 에서 에러가 납니다만, 몇가지를 수정해주시면 제대로 됩니다.
- 이 강좌는 제가 그동안 겪고 배우고 또 여기저기서 수집한 자료를 바탕으로 쓴 강좌입니다. 틀린부분이 있을 수도 있으니
그런 부분은 지적 바랍니다.
- 글의 이동은 자유지만 출처는 명시해 주시기 바랍니다.

블로그 이미지

UART

,

RC 모터에 대하여 이전에 글을 올렸습니다. -

토요일부터 지금까지 계속 테스트 중에 있습니다.

일단 결론은 RC모터는 일정회전을 만들어야 힘이 생긴다.이고

이에 따라 감속비가 가장 많은 센터크랭크로 구현하는 것이 가장 적절하다.

앞으로 센터크랭크에 도전을 해야 하겠습니다. 하지만, 시간이 허락하면 할 생각이구요.

또한 후륜허브킷은 자출용으로 부족함이 없다는 결론도 내렸습니다.

효율(속도조절 등)은 센터크랭크보다는 더 떨어질 것 같으나 일정한 힘을 낼 수 있어 자출상에서 큰 무리가 없어 보입니다.

추가로 전차에서 사용하는 기능을 구현했는데요. 기존 상용전차에서 사용하는 기능 중 몇가지를

비슷하게 넣어봤습니다.

상용전차에서 주로 사용하는 기능은

1. 스로틀 (오트바이처럼 당기면 달리는 기능)

2. PAS (패달로 돌리면 동작하여 달리는 기능)

3. 브레이크(브레이크 레버를 잡으면 제어기를 통해 모터의 동작을 중지시키는 기능)

4. 크루즈( 장거리에 유용한 기능으로 어떤조건(?)에 따라 스로틀이나 PAS 조작없이 동작을 일정하게 연속적으로 달리게 하는 기능)

5. 사이클링 레벨 (배터리 상황이나 어떤 조건에따라 단계를 나누어 모터에 들어가는 힘을 조정하는 기능)

인 것 같습니다. 더 많은 기능이 있을 것 같습니다만 .. 아는 것이 이것 밖에 없네요.

유용한 기능이 있으면 덧글로 알려 주세요. ^^;

아무튼 현재 비슷하게 구현을 했습니다.

아래 사진은 대충 표기하는 기능에 대하여 표기 했습니다.

두가지 버튼을 누름으로 변경이 됩니다.

ONOFF 버튼은 MODE( 배터리 용량의 LED표기 )를 변경합니다.

처음 상태는 OFF 상태이고 이때는 어떤 입력도 받아 드리지 않습니다.

한번씩 누를 때마다 스로틀,PAS,스로틀+PAS, OFF 로 상태가 순환 변경이 됩니다.

MODE 버튼은 레벨(사이클링 LED)를 1,2,3단계로 만듭니다. 최고 속도에 비례하여 스로틀이나 PAS의 힘을 조절하게 됩니다.

브레이크는 PAS에만 작동이 됩니다. 그럼 스로틀 + PAS일 때는 동작이 어떻하느야?

당연.. PAS에 대해서만 차단 동작을 합니다. 브레이크 차단시에도 스로틀르 당기면 동작합니다. 왜 PAS에만 동작하게 했냐면 자출을 하다보니 저속에서 힘이 필요할 때는 스로틀로 조절하기 위해서 입니다. .

 패달은 위험하든 속도를 줄이든 또는 출발시든 모터가 동작하게 되어 있기 때문에 브레이크 차단이 필요하구요. 이 기능이 가장 유용할 때는 사람들 많은 곳을 지날때 살짝 브레이크를 잡고 패달로만 지나가구요. 이후 브레이크 레버를 풀면 바로 동작하니 기동성이 좋습니다.

 크루즈기능은 토요일에 급하게만들어 봤습니다. 일정 입력이 7초간 지속 될때 사용자가 크루즈기능을 원하는 구나 생각하고 동작을 합니다. 동작일 때는 어떻게 표기할까 고민하다가 MODE LED(배터리 용량 1,2,3)를 모두 켜는것으로 했습니다. 눈에 확들어오구요. 크루즈 모드에 진입하면 스로틀을 풀어 두면 됩니다.

크루즈 동작 취소는 어떻게 할까 고민하다가, 브레이크 레버을 먼저 확인하여 해제하거나 스로틀의 값을 변경하면 꺼지도록 했습니다. 브레이크 레버 살짝 잡았다 풀면 되구요. 아래 동영상에서는 살짝 스로틀를 돌려서 해지 하였습니다.

테스트시 상당히 편하더군요. ㅎㅎ

 

사이클링 레벨은 1,2,3에서 PAS와 스로틀의 힘이 다르게 했습니다. 기본적으로 스로틀이 더 강하게 만들어 두었습니다. PAS는 사람의 힘이 들어가는 것이고 스로틀은 임의 모터힘만 지원이니 강하게 해야 될 것 같았습니다.

그리고 주행 동영상을 올려야 하는데.. 싸구려 블랙박스가 상태가 좋지 않으니 원... 아무튼 간단한 동작 동영상을 올려 봅니다.

그리고 컨트롤러를 자작하시는 분은 위 5가지 기능을 지원하는 형태로 하면 좋겠습니다. 상당히 유용한 기능들입니다. ^^

크루즈기능은 마지막에 있으니 재생바를 당겨서 보세요. 그리고 패달은 돌릴 때 손이 잘 보이지 않아서 오해 하실 수 있습니다. 제 전차는 BB볼트를 빡빡하게 조여서 임으로 돌리지 않으면 돌지 않아요. 패달이 회전하고 있으면 손으로 돌리고 있는 것입니다. ^^

그리고 이상하게 휴대폰에서 찍은 동영상은 AVC코덱이필요하다하여 편집을 못하고 그대로 올릴 수 밖에 없네요. 또 아이와 와이프의 목소리도 들어가고 RC고유한 소음도 방에서 하다보니 더욱 크게 들립니다.

약간 보시기 불편할 것 같습니다. 이상하더라도 이해해 주세요. ^^

 

RC모터 E-BIKE 컨트롤러 자작
블로그 이미지

UART

,

블로그에 글을 써서 올리는 것이 아이가 방학이 끝나갈 무렵  밀린 일기를 몰아쓰는 꼴입니다.

하지만, 미룰 수 없어서 이제는 이야기를 풀어봅니다.

전기자전거의 구성은 크게 배터리(충전기,배터리), 모터(DC,BLDC), 모터제어기(컨트롤러, 핸들스로틀, PAS 등) 및 브라켓(모터장착 기구물) 으로 나눕니다.

배터리 종류 - 리튬이온, 리튬폴리머, 리튬인산철, 납(산) 등이 있습니다. 

리튬이온(폴리머)는 거의 같게 취급합니다. 장점은 가볍고 고용량이 저장됩니다. 단점은 안점성이 다른 것(인산철 등)에 비하여 떨어집니다. 관리를 조금만 잘 못하면 바로 아웃됩니다. 중요한 가격이 비쌉니다.


리튬인산철는 리튬이온의 단점을 보안한 것으로 그나마 안정적이며, 가격도 싼편입니다. 

단점은 무겁다(리튬이온에 비해서) 정도입니다.


납(산) 는 일반 자동차에서 사용하는 배터리와 같는 특성을 가집니다. 장점은 가격이 싸다. 단점은 너무 무겁다. 자전거용으로는 개인적으로 적합하지 않다입니다만 저가형 전동자전거에 많이 사용합니다. 

전압은 전동 자전거의 경우 24V와 36V를 주로 사용합니다. 요즘 보통 36V를 많이 사용합니다. 가능하면 36V를 구매하세요.

모터 종류 – DC모터, BL(BRUSH LESS) DC모터 로 크게 나뉩니다.  DC모터는 브러쉬가 있어 우리가 주변에 많이 쓰는 모터입니다. 장점은 가격이 착하다, 제어구조가 단순하다. 단점은 수명이 짧고(BLDC에비해서), 열에 약하며, 효율이 떨어집니다.  BLDC 모터는 장점은 수명이 길고, 효율이 좋습니다. 단점은 비싸고 제어구조가 복잡합니다. (제어기가 반드시 필요합니다.)

모터제어기 - 속도조절을 위해 사용하는 것입니다. 우선 스로틀(오트바이의 그립을 생각하시면 됩니다.) 로 속도조절을 하게됩니다. PAS란 것도 사용합니다. 패달을 밟으면서 스로틀처럼 모터의 속도를 조절하는 형태입니다.  상당히 유용합니다. PAS에는 또 필요한 것이 있습니다. 바로 브레이크입니다. 즉, 브레이크 레버를 잡으면 모터제어기에 신호를 보내서 더이상 모터가 돌지 않도록 하는 것입니다.

모터가 장착되는 브라켓의 위치에 따라  크랭크형과 허브형이 있습니다.
허브형은 BLDC모터로 허브에 기어부분이 내장된 형태입니다. 장점은 조용하다 및 깔끔하다는 것이구요.  단점은  내장된 기어비만 사용하기때문에 힘이 고정되어 있습니다. 또한 가격이 비쌉니다. 
크랭크형은 주로 체일을 프리휠로 돌려서 구동하는 형태입니다. DC모터도 사용되며 요즘 가능하면 BLDC모터를 적용되어 가고 있습니다. 

크게 보면이 위와 같이 4가지 입니다.  나머지 세부적인 것들이 있습니다.

일단 저는 DC모터에 DC모터제어기, 그리고 인산철 배터리 및 크랭크 중앙 하단형으로 먼저 진행했습니다.

전기자전거에서 가장 비싼 부분이 뭘까요?

 

답은 배터리 입니다. 

배터리 가격은 보통 30~50만원 정도 생각하면됩니다. 전체 가격의 50%가 넘습니다.  저는 중국에서 나름 저렴하다고 생각한 인산철 24V 40Ah를 구매했습니다.

배터리 내용은 추후에 별도의 글로 두겠습니다. 할 이야기가  많습니다.

 

자, 구성을 볼까요..아래 사진은 테스트를 위해서 구성한 것입니다. 이렇게 안하면 장착 후 다시 분해해서 무엇이 문제인지 확인해야 하니까요.

위에서 부터 모터, SMPS(배터리대용), 바로 밑에 모션컨트롤러, 배터리잔량계, 왼쪽 원형모양은 PAS, 바로아래 브레이크, 우측 아래에는 스로틀(버튼2개짜리)입니다 .

문제는 킷형태로 세트구매를 하면 컨넥터가 맞습니다만, 각각 개별 구매를 해서 컨넥터가 맞지 않습니다. 해서 모두 교체 작업을 할 수 밖에 없었습니다.  컨넥터 비용도 만만치 않습니다. ㅠㅠ

일단  이번 글은 여기 까지 하겠습니다. 다음 글에서 더 많은 내용을 올려 보겠습니다.

블로그 이미지

UART

,

 

새해 항상 신년계획을 세웁니다.

그 중 하나가  AVR프로그램을 활용하는 곳을 찾는 것인데..

"DC모터드라이버를 자전거에 적용해보자" 라고 시작한 프로젝트입니다.

일단 DC모터드라이버인데..  정작 중요한 자전거를 모릅니다.

자전거를 중학교 이후에 타고 다닐 만한 일도 없어서 자전거부터 공부하자 생각합니다.

자전거로 출퇴근을 해볼까?  힘들 땐데.. 이 때 인터넷 검색을 하다가 알게 됩니다.

네이버 카페 "자전거로 출퇴근하는 사람들 " 과  "전기자전거로 달리는 사람들" 가입 후 조금씩

자전거에 대하여 알아 갑니다. 전기 자전거가 무엇인지도 감을 잡아 갑니다.

알아 갈 수록 DC모터 드라이버는 문제가 아닙니다.

먼저 자전거구매, 20년 되었다는 MTB를 마음씨 좋은 분이 2만원에 주십니다.  하지만  너무 헤어져

알루미늄 프레임을 제외하고 모두 바꿔야 겠다는 생각을 합니다.

수리하기 위해 자전거의 수리공구를 구매해야 겠다고 돈을 좀 씁니다. ㅠㅠ

바퀴타이어와 각종 플라스틱, 나사등은 모두 싹아서 못습니다. 나사는 어디서 구할 수있을 지 하는 마음으로 그냥 사용합니다. 타이어 구매, V 브레이크 구매, 구리스, 안장, 기어속선, 브레이크 속선, 강철선을 자르는 커터기, 크랭크 분해를 위해 크랭크 분리공구, 프리휠 분리공구등 구매, 몽키, 스패너 세트, 랏쳇, 복스알 등등을 구매합니다.

그리고 분해 시작..  거실을 점령하여 와이프의 눈총을 좀 받지만 건강을 챙기자는 명분이 있어서 한동안 괜찮았습니다. 

기름이 누렇다 못해 타르수준까지 갔습니다.  분해, 청소, 구리스칠까지 하니 바퀴는 잘 굴려 갑니다. 

이제 전기 자전거로 만들어야 하는데.. 공부에 들어 갑니다. 

시간이 흐른 뒤에  내용을 채우니 힘이 드네요. 아무튼 다음에  전동화에 대하여 이야기 하겠습니다.

블로그 이미지

UART

,

아래 글을 보고 오픈소스에 대하여 생각했던 내용과 겹쳐서  올려 봅니다.


원문링크


----------------------------------- 원문 ----------------------------------------

내가 오픈소스라는 문화를 처음 접했던 것은 90년대 말이었던것 같다.

(사실 리차드스톨만이 GNU선언이란 것을 한 것은 85년 3월이라고 한다.

GNU는 "GNU is Not Unix"라는 말의 약어란다. 나름 재귀형 문장이다.)

당시 뉴스를 통해 외국에서 벌어지는 기술자들의 캠페인으로 이해하게 되었다.

당시 내 머릿속에 떠오르는 느낌은 이랬다. "저게 무슨 개소리야!"

"새우깡을 공짜로 팔라고 그래봐라! 어디 그게 가능한 논리냐?"

"기계 돌리면 기계값 들었으니까 돈 받아쳐묵어야 하고,

단지 고가의 기계없이 사람만 썼대도 그럼 인건비는 하늘에서 떨어지냐?"라고 말이다.

그러나 이제는 이해를 한다. 그래서 다른 분들께 내가 깨달은 논리를 설명코자 이 글을 쓴다.

일단, 오픈소스를 제대로 이해하려면 그 철학을 이해해야 한다.

물론 그 철학은 GNU선언시 계획되었을 수도 있고, 오픈소스를 운용하면서 자연스럽게 도달한 논리일 수도 있다. 어쩌면 지금부터 쓰는 글은 나만의 논리일 수도 있다. 내가 맞춘 단추다.

우선, 살아있는 코드와 죽은 코드의 차이점을 이해해야 한다.

코드, 프로그래밍, 알고리즘... 알고리즘은 무엇인가? 간단명료하다.

바로 일을 해결하는 과정, 그 절차이다. 그것은 인간적 경험의 산물이며 작업의 지침서이다.

그렇다면 소프트웨어란 무엇인가? 바로 특정 하드웨어를 가지고 목적이 있는 일을 처리하기 위한 동작의 지침서이다. 즉, 코드란 스스로 살아움직이는 부분 같은 것은 애초부터 제로인

하나의 완벽한 무생물이다. 소프트웨어가 하는 모든 일은 철저히 계획된 인간의 지시절차 이 외에 그 어떤것도 아닌 것이다. 어떠한 소프트웨어는 살아있는 것처럼 착각을 일으키지만

실상 원래 죽은 것이다.

그런데 그런 코드가 곁에 개발자란 인간이 붙어있으면 생명을 가질 수 있게 된다.

수많은 오픈소스 엔진들을 보면 대부분 그들의 히스토리와 수많은 업데이트/패치들에

감탄을 금할 수 없게 된다. 패치로그를 보면 "무슨 버그가 있었는데 고쳤다."부터,

"사용자 편의성을 개선했다.", "새로운 자료형을 지원한다.", "불합리한 기능을 중단한다.",

"구성을 효율적으로 개편한다.", "타엔진과의 연동을 지원한다.", "알고리즘을 개선하였다.",

"새로운 플랫폼을 지원한다"등 수많은 상황이 존재함을 알 수 있다.

내가 구구절절 이렇게 나열한 것은 이유가 있다.

소프트웨어를 잘 모르는 사람들이 코드를 이렇게 생각하기 때문이다.

"그거 처음에만 잘 짜놓으면 계속 잘 쓸 수 있는거 아냐?"

위의 내용들을 다시 한번 보라. 패치는 단순히 버그만 잡는 것이 아니라,

인간과 세상의 변화에 일일이 "반응"하고 있다. 이것이 바로 살아있다는 것이다.

더 이상 자신을 변화시켜 줄 개발자가 사라진 그것.

즉, 죽은 코드들은 결국 나의 작업에 해를 입힌다. 세상이 발전한 만큼 나도 발전해야

먹고 사는 것인데, 고리타분해진 알고리즘을 내포한 그것은 결국 내 발목을 잡는다.

하드웨어는 항상 발전하고 그 발전의 원동력은 창의적인 개편이 항상 따르는 법인데,

(예를 들면 CPU/GPU간 병렬처리라든지, 네트워크자원을 통한 분산처리, 새로운 명령어셋트의 도입)

그것은 가끔 개발의 규칙이 송두리채 바뀜을 의미하게 된다.

마치 메모리를 아끼던 패러다임에서 모든 일을 메모리 중심적으로 하는 변화라든지,

CPU의 병렬처리의 가속을 위한 작업순서 재구성의 필요성, 네트워킹이 너무 느려서 최대한 데이터량을 아끼던 패러다임에서 차라리 CPU의 분산컴퓨팅을 위해 데이터량을 훨씬 더 쓰는

방법으로 발상을 바꾼다던지, 랜덤엑서스가 IO보다 중요했던 상황에서의 개별파일 중심적인 리소스에서 IO의 부하가 더 큰 이슈가 된 통합파일 중심적 리소스시스템의 도입이라던지,

CPU의 발전으로 대량의 통연산을 제공하는 새로운 명령어의 등장이나 또는 새로운 CPU에서 더이상 제공하지 않는 명령어가 생김으로 인한 어셈블리 코드의 변화라던지 등등해서

그것이 어떤 코드이건간에 시대의 변화와 발맞추지 못하면 그 코드는 언제든지 비효율적이고 고리타분한 작업지침으로 전락할 수 있는 것이다.

그렇기에 코드는 원개발자 1인만 항상 바라보고 있다가 그 개발자가 다른 업무를 맡게되어 찬밥신세가 되면 금방 죽어버리는 원통한 팔자에서 전 세계의 개발자들에게 오픈되어 마치 스스로

배포와 재생산, 개선과 개편을 거듭하는 스스로 살아있는 무언가가 되어야 하는 것이다.

또한 전 세계의 모든 개발자가 동일한 문제의 해결을 놓고 씨름하는 어처구니 없는 저효율성을 극복하고 누군가가 풀어낸 문제는 후발주자는 간단히 건너뛰고 그 열정을 다음 문제의 해결을 위해 써서 다른 후발주자를 위해 길을 여는 상부상조의 아름다운 시스템이 되어야 한다는 것이다.

또한 그렇기에 국내의 일부 업체들이 오픈소스를 도입해놓고 그 결과물을 다시 오픈하진 않는 행위는 재배포의 강제공개같은 몇가지 라이센스 법적 문제를 논외로 하고서라도 오픈소스의 장점을 10%정도만 가지는 것이라 할 수 있는 것이다.

오픈소스의 장점은 누군가 만들어 놓은 결과물을 가져다 쓰는 것이 아니라 내 품에만 안고 있으면 결국 찬밥먹고 죽어버릴 소중한 코드들에게 강력한 생명을 부여하는 것이다.

그때의 그 리눅스가 오늘의 그 리눅스는 아닌 것이다. 아마 초대 오픈소스인 리눅스는 수많은 탈피와 변태를 거쳐 어제도 오늘도 새롭게 태어나고 있는 영원불멸의 생명체인 것이다.

물론 그 영광은 초기 설계자와 공식배포처인 회사에게 돌아갈 것이며, 또한 그 코드를 이해하고 수정하며 기여했던 개발자들에게 열정을 쏟은 만큼 지분이 돌아갈 것이니 초안자와 공식배포처는 놀고 먹지 않은 다음에야 가장 큰 지분자임은 두말 할 필요도 없다.

물론 지분이란 단어는 주식같은 물질적 지분이 아니라 각자 돌아갈 자기몫의 잠정적인 기대치를 말한다.

(바로 이어서 쓸 오픈소스의 수익구조를 보면 이해할 수 있다.)

그렇다면 오픈소스는 어떻게 돈을 버는가?

가장 중요한 대목이고 오랫동안 이해가 안갔던 핵심적인 부분이었다.

사람이 돈을 쓰는 데는 2가지 목적으로 나뉜다.

바로 "재화의 구매"가 그 첫번째요, 두번째는 "권리의 구매"이다.

첫번째는 단순히 새우깡을 사는 것이다. 시간이란 요소가 들어가지 않는다.

두번째는 보험같은 것이다. 실제로 받을지는 몰라도 상황에 따라 보장받을 수 있는 권리를 산 것이다.

식별적인 특징은 첫번째와 달리 시간이란 요소가 들어간다는 점이다. 오픈소스의 수익구조는 권리의 판매이다.

애컨데 유지보수보장이다. 또한 문제가 발생했을 때, 능동적 대처에 대한 보장이다.

초기 넘어간 엔진은 무료지만, 그것을 도입, 운용하는 데 필요한 권리는 유료인 것이다.

물론 자사의 사원이 해당 오픈소스를 많이 연구한 탓에 유지보수를 신청하지 않아도 된다고 한다면, 그 사원은 원개발자 대신에 일거리를 받은 셈인데, 그렇게 된 이유는 과거 자신이 해당 오픈소스를 이해하고 연구하는데 열정을 쏟았기 때문인 것이다. 열정은 수익으로 돌아왔다.

그것은 오픈소스에 기여한 만큼 그에겐 지분이 있었던 것이다.

또한 오픈소스는 쉽게 유명해지고, 오픈소스들의 노하우풀을 통해 쉽게 발전을 하고,

쉽게 표준화된다. 오픈소스 도입역량이 높은 개발자는 사실 세계 최고의 코드를 언제든지

소환할 수 있는 소환사 또는 연금술사가 되는 것이고, 오픈소스를 도입한 회사는 해당 기술에 대하여 명맥이 끊김을 걱정하지 않고 자사만의 기술에 머물러 사원을 뽑을 때마다 원점에서 교육을 시켜야 하는 번거로움과 아까운 비용대신, 언제든지 구할 수 있는 예비 인력풀을 보유하게 되는 것이다.

그렇다면 오픈소스를 도입한 회사는 자신만의 기술이 하나도 없어 경쟁력이 도태되지 않냐고? 오픈소스를 도입한 것이지. 하나부터 열까지 모든 기술을 까라고 한 적은 없다.

그것이 클라이언트적 기술역량이든, 기획적 역량이든, 비지니스모델적 역량이든지

회사는 언제든지 오리지널리티를 보유할 수 있다. 다만, 살아있어야 하는 코어한 기술부분만을 추려내어 오픈소스에 참여, 해당 기술은 발전적 무한한 에너지를 얻는 것이다.

바로 그런 의미에서 가장 도입여건이 좋은 회사가 바로 게임회사가 아닐까 싶다.

성공하는 게임회사가 꼭 자체 물리엔진을 보유해야 하는 것은 아니다. 오픈소스인 BOX2D로 엔진을 개발해도 재미있는 게임을 만드는 데는 아무런 상관이 없다. 또한 자체 개발한 기술도 오픈소스화 하여 새로운 오픈소스 브랜드를 형성하고 축적한다면 결국 팔만한 자체기술을 개발하여

언리얼엔진 같이 컨텐츠 이외에 엔진수익원을 확보하려던 소기의 목적도 달성할 수 있을 것이다.

엔진은 무료지만, 엔진과 연동되는 툴도 필요할테니 말이다. 또한 유지보수의 해결도 필요할 것이다.

현재 서비스되고 있는 오픈소스가 아닌 수많은 엔진을 생각해 보라.

그들도 결국 유지보수비용으로 상용엔진을 팔고 있음을 알 수 있다. 왜 판매금액 차이에 차등을 주면서 어떤 등급은 신속한 메일답변이 가능하다고 하고, 어떤 등급은 프로젝트내내 기술지원을 약속받고, 어떤 등급은 확장기능 제공을 포함하겠는가? 결국 매월 또는 매년 내는 돈은 유지보수 잘 해 달라고 주는 돈이다.소프트웨어는 한번 빌드되면 복사하는 데 비용이 들지 않는다. 실물재화와 다른 점이다.

결국 돈을 정당하게 받을 수 있는 "명분"은 한 카피 복사해 줬다고 생색내는 비용이 아니라 실제로 일을 해주던 안해주던 막연한 불안감에서 해방시켜주는 생명보험같은 권리의 판매비용이다.

그게 바로 현 시점에서 먹히는 비즈니스모델인 것이다.

결국 오픈소스 엔진도 같다.

오히려 초반 도입가격이 0원이라는 훌륭한 마케팅도구 덕분에 실제로 유지보수 신청건수는 비약적으로 늘어날 수 있다. 오픈소스를 무료로 도입했다고 해도 그것은 운용하고 커스터마이징하고 내부기술화하고 적절한 패치를 해주는 것은 보통 일이 아니며 그것을 위해 고급인재 단 한사람을 뽑아도 쉽게 엔진비용을 넘어서기 때문이다. 오픈소스 엔진의 원개발자는 항상 많은 유지보수를 하고 있기 때문에 대부분 비슷한 일이라 새로운 유지보수계약을 하여도 큰 부담도 없고 해소가 되지만, 유지보수비용 지급하기 싫어서 뽑은 자기 회사 고급인재는 매일이 삽집의 연속일 수 있다.

그러다가 관련된 일을 알만하면 퇴사나 이직을 선택할 지 모르는 것이다.

그러니 회사는 차라리 원개발자랑 일종의 보험계약을 하는 것이다.

만약 내가 만든 기막힌 엔진을 저렴한 5백만원에 팔면 초기비용의 부담으로 아무도 도입하려 하지 않겠지만, 1년 개발서포트/유지비용의 명목으로 1천만원을 선택 제시한후, 무료로 오픈소스 형태로 배포된 엔진은 누구나 쉽게 도입하여 개발사들이 잘 쓰다가 결국 커스터마이징에 1명을 붙여도 4천만원이 훌쩍 넘긴다는 사실을 깨닫고 연간 1천만원짜리 유지보수 비용을 지불할 것이다.

결국 5백만원인 일회성 초기수익을 포기했더니, 죽을 때까지 연간 1천만원씩 벌 수 있게 된 셈이다.

결국 오픈소스의 놀라운 힘이다.

블로그 이미지

UART

,