9-3-라.룩업 테이블

임의의 날짜가 주어졌을 때 이 날짜 다음의 날짜, 즉 내일을 구하는 예제를 만들어 보자. 내일이란 굉장히 쉽게 구할 수 있을 것 같지만 날짜라는 정보의 구조가 간단하지 않기 때문에 생각보다 훨씬 더 어렵다. 오늘 날짜가 m월 d일이라고 했을 때 대부분의 경우는 d만 1증가시키면 된다. 그러나 오늘이 월말일 경우는 d는 1이 되고 m은 1증가해야 하는데 예를 들어 3월 31일의 내일은 3월 32일이 아니라 4월 1일이다.

월이 바뀔 때도 m이 무조건 1증가되기만 하는 것은 아니다. 13월이라는 것은 없으므로 12월 다음은 1월이 되어야 한다. 오늘이 월말이라는 것을 알아 내려면 매 달마다 몇일까지 있는지를 조사해야 한다. 3월은 31일까지 있지만 4월은 30일까지밖에 없다. 이런 정보를 조사할 때도 배열을 사용할 수 있다. 다음 예제는 배열로 이 문제를 풀어본 것이다.

: PrintTomorrow

#include <Turboc.h>

void PrintTomorrow(int m, int d)

{

static int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};

if (d > days[m] || m < 1 || m > 12) {

printf("입력한 날짜가 틀렸습니다.\n");

} else {

d++;

if (d > days[m]) {

d=1;

m++;

if (m == 13) {

m=1;

}

}

printf("내일은 %d월 %d일입니다.\n",m,d);

}

}

void main()

{

int mon,day;

printf("오늘 날짜(월 일)을 공백으로 구분하여 입력해 주세요 : ");

scanf("%d%d",&mon,&day);

PrintTomorrow(mon,day);

}

PrintTomorrow 함수는 날짜를 전달하면 이 날짜의 내일을 조사하여 출력한다. 매월의 마지막 날에 대한 정보를 days라는 배열로 작성해 놓고 days의 첨자로 m을 사용하면 m월의 날 수를 쉽게 조사할 수 있다. 이런 식으로 값의 참조를 위해 사용하는 배열을 룩업 테이블(Lookup Table)이라고 한다. 만약 배열을 사용하지 않는다면 switch case문이나 여러 개의 조건문을 가지는 if문을 구성해야 할 것이다.

if (m==1 || m==3 || m==5 || m==7 || m==8 || m==10 || m==12) {

// 31일까지 있음

} else if (m==4 || m==6 || m==9 || m==11 {

// 30일까지 있음

} else {

// 28일까지 있음

}

조사 대상이 12개 정도이고 비슷한 값들을 가진다면 이 정도 조건문으로도 문제를 일단 해결할 수 있겠지만 만약 100개 정도의 불규칙한 값을 조사해야 한다면 이런 방법은 한계가 있다. 아무리 값이 많아도 또 값이 불규칙해도 룩업 테이블을 작성하면 아주 빠른 속도로 원하는 값을 찾을 수 있을 뿐만 아니라 이후 값을 수정하기도 편리하다. 값을 선택하는 기준이 정수라면 이 정수값을 첨자로 하는 룩업 테이블을 작성하고 정수를 첨자로 넣기만 하면 배열을 통해 원하는 값을 바로 찾을 수 있다.

룩업 테이블은 보통 한 함수만 사용하는데다 읽기 전용인 경우가 많으므로 static으로 선언하는 것이 좋다. 만약 static으로 선언하지 않고 단순 지역 배열로 선언한다면 함수가 호출될 때마다 이 배열을 매번 초기화해야 하는데 이는 엄청난 실행 속도의 저하를 가져온다. 배열의 크기가 크면 클수록 초기화 속도는 느려지는데 이럴 때 static 기억 부류를 사용하면 딱 한 번만 초기화하므로 속도에 유리하다.

다음 예제는 룩업 테이블의 또 다른 사용예인데 전혀 규칙성이 없는 난수중 하나를 선택한다. 발생 가능한 난수 목록을 배열에 미리 작성해 놓고 난수로 배열 첨자를 고르는 방식이다. 실행할 때마다 룩업 테이블에 있는 정수중 하나가 선택되어 출력될 것이다.

: RandTable

#include <Turboc.h>

void main()

{

int arRand[]={2,9,14,19,27};

int Num;

randomize();

Num=arRand[random(sizeof(arRand)/sizeof(arRand[0]))];

printf("생성한 난수 = %d\n",Num);

}

이런 방법을 쓰는 대신 원하는 난수를 포괄하는 범위에서 수를 하나 생성하고 조건문으로 원하는 난수 중 하나가 맞는지 점검하는 방법을 쓸 수도 있다. while문으로 조건에 맞는 난수가 나올 때까지 루프를 돌리면 언젠가는 원하는 값이 나오기는 하겠지만 루프를 여러 번 돌아야 하므로 비효율적이고 난수를 고르는 시간이 일정하지 않다. 룩업 테이블은 첨자만 난수로 선택하므로 단 한 번에 원하는 값을 고를 수 있고 난수의 목록을 편집하기도 편리하다.

다음 예제의 Congratulation 함수는 게임의 시도 회수에 따라 축하 메시지를 출력하는데 시도 회수가 적을수록 높은 점수를 부여한다. 회수별로 메시지를 다르게 출력하기 위해 switch case문을 사용했다.

: GameMessage1

#include <Turboc.h>

void Congratulation(int count)

{

switch (count) {

case 1:

puts("축하합니다. 최고 성적입니다.");

break;

case 2:

puts("대단한 성적입니다.");

break;

case 3:

puts("참 잘 하셨습니다");

break;

case 4:

puts("보통이 아니군요.");

break;

case 5:

puts("보통입니다.");

break;

case 6:

puts("조금 더 노력하셔야겠습니다.");

break;

case 7:

puts("정말 못하시는군요.");

break;

case 8:

puts("수준 이하입니다.");

break;

default:

puts("다음부터 절대로 이 게임을 하지 마세요.");

break;

}

}

void main()

{

Congratulation(3);

}

이 예제는 기능상의 문제는 전혀 없지만 길다란 switch case문이 왠지 비효율적으로 보인다. 시도 회수인 count로부터 메시지만을 구하는 룩업 테이블을 작성하면 출력문을 훨씬 간단하게 구성할 수 있으며 또한 메시지를 편집하거나 추가하기도 편리하다. 다음 예제는 똑같은 동작을 하되 룩업 테이블로 바꿔 본 것이다.

: GameMessage2

#include <Turboc.h>

void Congratulation(int count)

{

static char *Message[]={"",

"축하합니다. 최고 성적입니다.",

"대단한 성적입니다.",

"참 잘 하셨습니다",

"보통이 아니군요.",

"보통입니다.",

"조금 더 노력하셔야겠습니다.",

"정말 못하시는군요.",

"수준 이하입니다.",

"다음부터 절대로 이 게임을 하지 마세요.",

};

if (count >= 9) count=9;

puts(Message[count]);

}

void main()

{

Congratulation(3);

}

count를 첨자로 하는 문자열의 배열을 작성했는데 이 룩업 테이블도 물론 static으로 선언해야 한다. count가 0인 경우는 없으므로 빈 문자열로 초기화해 미사용으로 남겨 두었다. 메시지 문자열들이 한 곳에 모여 있으므로 소스가 훨씬 더 짧아지고 보기에도 좋다. 만약 count와 메시지가 일대일로 대응되지 않고 일정 범위별로 대응된다면 같은 메시지를 배열에 계속 나열할 필요없이 2차 룩업 테이블을 만든다. 예를 들어 1~3회는 상, 4~8까지는 중, 9~12까지는 하로 범위를 나누어 메시지를 다르게 출력하고 싶다면 다음과 같이 수정한다.

: GameMessage3

#include <Turboc.h>

void Congratulation(int count)

{

static char *Message[]={

"잘 하셨습니다.",

"보통입니다.",

"못 하는군요.",

};

static int arMes[]={0,0,0,0,1,1,1,1,1,2,2,2,2};

if (count >= 12) count=12;

puts(Message[arMes[count]]);

}

void main()

{

Congratulation(8);

}

count를 arMes 룩업 테이블에 넣어 몇 번째 메시지인가를 먼저 선택하고 이 값을 Message 배열의 첨자로 넣어 실제 메시지를 고르는 것이다. count로부터 최종 메시지가 선택되는 과정은 다음과 같다.

이렇게 하면 메시지를 출력하는데 필요한 최소한의 정보만 유지할 수 있으며 편집하기도 쉽다. count에 따른 메시지를 변경하려면 arMes배열을 편집하고 최종 메시지 문자열을 변경하려면 Message 배열을 편집하기만 하면 된다.

PrintTomorrow2

PrintTomorrow 예제는 년도에 대한 고려는 하지 않는데 년도까지 계산에 포함하면 윤년을 고려해야 한다. 윤년이란 4로 나누어 떨어지되 100으로는 나누어 떨어지지 않는 년도인데 1904년은 윤년이지만 1900년은 윤년이 아니다. 또한 100으로 나누어 떨어지는 년도라도 400으로 나누어 떨어지면 윤년이 되는데 2000년은 윤년이다. 윤년에는 2월달이 29일까지 있으므로 룩업 테이블에서 읽은 값 중 2월의 값을 수정한 후 사용해야 한다. 년, 월, 일 정보를 모두 입력받아 윤년까지 고려해서 내일 날짜를 출력하는 예제를 작성하라.

'Computer Science' 카테고리의 다른 글

안드로이드 구조분석 wiki  (3) 2010.01.10
안드로이드 wiki  (0) 2010.01.10
EMACS 메뉴얼  (0) 2010.01.03
안드로이드 프로그래밍 개요  (0) 2010.01.03
iPhone Coding Tutorial &#8211; In Application Emailing  (0) 2009.12.25

A Tutorial Introduction to GNU Emacs

Introduction and History

What GNU Emacs Is

GNU Emacs is a free, portable, extensible text editor. That it is free means specifically that the source code is freely copyable and redistributable. That it is portable means that it runs on many machines under many different operating systems, so that you can probably count on being able to use the same editor no matter what machine you're using. That it is extensible means that you can not only customize all aspects of its usage (from key bindings through fonts, colors, windows, mousage and menus), but you can program Emacs to do entirely new things that its designers never thought of.

Because of all this, Emacs is an extremely successful program, and does more for you than any other editor. It's particularly good for programmers. If you use a common programming language, Emacs probably provides a mode that makes it especially easy to edit code in that language, providing context sensitive indentation and layout. It also probably allows you to compile your programs inside Emacs, with links from error messages to source code; debug your programs inside Emacs, with links to the source; interact directly with the language interpretor (where appropriate); manage change logs; jump directly to a location in the source by symbol (function or variable name); and interact with your revision control system.

Emacs also provides mail readers, news readers, World Wide Web, gopher, and FTP clients, spell checking, and a Rogerian therapist, all of which are also useful for programming. But in this d0cument we'll concentrate on the basics of Emacs usage for programmers.

What GNU Emacs Is Not

First and foremost, GNU Emacs is not a WYSIWYG word processor. This is primarily because it's designed as a programmer's editor, but Emacs is also used to edit d0cuments by people who use non-WYSIWYG typesetters like TeX and Troff.

Actually, this is about the only thing I can think of that GNU Emacs is not.

Varieties of Emacs

Emacs is actually the name of a family of text editors that are either descended from or inspired by one another. The original Emacs was written in the programming language of the text editor TECO, and ran on DEC PDP-10s and -11's. Early on it inspired other Emacsen for Multics, and Lisp Machines.

The first Emacs for Unix machines was Gosling Emacs, which later went commercial as Unipress Emacs. GNU Emacs was written by Richard Stallman, the main author of the original TECO Emacs.

For an editor to be called "emacs" the main requirement is that it be fully extensible with a real programming language, not just a macro language. For GNU Emacs, this language is Lisp. Other Emacsen have used TECO, Scheme, a dialect of Trac called Mint, interpreted C-like languages, etc.

GNU Emacs itself runs on a large number of Unix machines, and under VMS, DOS/Windows, and OS/2, among others. GNU Emacs is currently at version 19.29; at Library Systems we have this version installed. On the AIT machines (quads, ellis, kimbark and woodlawn) the default emacs is version 18.57: a major revision behind. Version 18 is probably 92% compatible with version 19; 19 mostly adds new functionality. But some important commands were changed slightly. (However, an unsupported version of Emacs v19 is available as /usr/unsupported/gnu/bin/emacs19.)

Theory and Practice of Keyboards and Character Sets

I find that, for beginners, the most confusing thing about Emacs is the keyboard and character set. It's important to understand that, as a portable program, Emacs can't always know about all the keys on your keyboard. All Emacs commands are 8-bit ASCII characters. Some keyboards, however, have keys which don't correspond well to any particular ASCII characters. This is especially true of PC and Macintosh keyboards, when connected to a Unix machine through the intermediary of some telecommunications program, where the only data that flows between your PC and the Emacs running on the Unix box are 8-bit ASCII bytes.

For example, the typical PC keyboard has keys labelled PAGE UP and HOME, arrow keys, function keys, etc. Not only do these keys have no official ASCII values, but they generate no ASCII characters at all. The PC can distinguish between them by means of scan codes, but what happens when you're connected to a Unix machine via a telecommunications program and you type one of these keys?

Any of the following things can happen, depending on the telecommunications program:

  1. No ASCII character is sent at all;
  2. One ASCII character is sent, but it's an arbitrary one likely to be different under another telecommunications program;
  3. Some escape sequence is sent.

The characters generated by different keys can vary even within the same telecommunications program depending on what terminal emulation is chosen. In fact, the telecommunications program can even change the characters sent by keys that do have official ASCII characters associated with them (control-@ is a common problem).

Finally, the operating system and even terminal concentrators can muddy things further. Emacs (by default only) expects that the full ASCII character set is available. But the OS or some mux may be usurping some of your characters. The best examples are control-S and control-Q, which are sometimes used for flow control. These are important Emacs commands and you should make sure that neither your telecommunications program nor your terminal concentrator are grabbing them (Emacs can handle the OS). Other examples are nulls, sometimes swallowed up whole, and characters with the high-order bit set, sometimes stripped, or -- worse -- used for parity. Any internationalized system (like modern Unixes) work best with 8-bit no parity data channels anyway.

There's nothing Emacs can do about any of the above: it only sees 8-bit ASCII characters given to it by the operating system. But if you understand your telecommunications program, you won't have any problems with Emacs and keystrokes.

Note: Emacs actually can use special keys like the arrow keys under certain circumstances (like under X or when running natively under DOS, where Emacs understands keyboard events). But I recommend not using these keys even if they work, so that you can use Emacs from any terminal.

Notation

In the rest of this d0cument I use the standard Emacs notation to describe keystrokes:
C-x
For any x, the character Control-x.
M-x
For any x, the character Meta-x (see below for more details on Meta characters).
C-M-x
For any x, the character Control-Meta-x.
RET
The return key (C-m actually).
SPC
The space bar.
ESC
The escape key, or, equivalently, C-[

Emacs Command Structure

For Emacs, every keystroke is actually a command, even simple keystrokes like the letters A and z: printing characters are commands to insert themselves. Non-printing characters are editing commands, which might move the cursor, scroll some text, delete or copy text, etc.

Every command has a long name, which you can look up in the d0cumentation, like kill-line, delete-backward-char, or self-insert-command. These commands are bound to keystrokes for convenient editing. We call such a pairing of keystroke and command a key binding, or binding for short.

The set of all bindings make up the Emacs command set. However, Emacs is an extensible, customizable editor. This means that:

  • Bindings can be different in different modes by virtue of extensibility
  • Bindings can be different for different users by virtue of customizability

In this d0cument I describe the standard Emacs key bindings.

Simple Keys

There are 95 different printable ASCII characters, and they are all bound to self-insert-command so that they insert themselves as text when typed. For editing commands, Emacs uses all the control characters: C-a, C-b, etc. But this is only 32 more characters, and Emacs has more than 32 editing commands.

The 128 characters in the upper half of ASCII are not taken yet, but how do you type them? Emacs uses a Meta key, which works exactly like a Control key or a Shift key in that it generates no character by itself, but rather modifies another character on the keyboard. The Meta key actually generates the same character that the key it's used with generates, but with the high-order bit set. This gives us access to characters such as M-a, M-b, etc. (There's also M-A, which is a distinct character, but to minimize confusion the uppercase metacharacters are equated to the corresponding lowercase metacharacter.)

What about the control characters with the high-order bit set? These are valid metacharacters as well; they are notated C-M-a, etc. To key them you hold down Control and Meta simultaneously and strike the desired key. Because both Control and Meta are shift keys, C-M-a is the same key (and the same ASCII character) as M-C-a. But for consistency we always write the former.

Prefix or Compound Keys

The Control and Meta keys plus the printing characters give us 256 possible keystrokes, or 160 editing commands after eliminating the self-inserting characters. But Emacs has many more than 160 commands! To handle this we also use prefix commands. A prefix command is a keystroke that, when typed, waits for another character to be typed, making a pair of keystrokes bound to one command. Each prefix command adds another 256 keystrokes that we can bind commands to. Prefix commands often group together commands that are somehow related.

The standard prefix commands are:

C-c
Used for commands that are specific to particular modes, so they are free to be used for different commands depending on context. These are the most variable of Emacs commands.
C-h
Used for Help commands.
C-x
This prefix is used mostly for commands that manipulate files, buffers and windows.

These prefixes give us another 768 keystrokes, for a total 928. But Emacs has far more than 928 commands! To handle this, you can bind one of the subcommands of a prefix command to another prefix command, like C-x 4 for example, or C-x v, each such binding yielding another 256 keystrokes. A number of these two-character prefixes exist, but they're rather specialized, and don't contain a full set of 256 commands (usually there are only three or four, and the prefix is just used for a mnemonic grouping). There are even three character prefixes, but most people won't admit to using them.

Using Extended Commands

But now we're entering a sort of rarefied atmosphere: even an Emacs geek like myself doesn't really use all these key bindings. Some Emacs commands are used very rarely, and, when you need it, it's easier to look up the long name of the command (using Info, Emacs' online searchable help system) and type it directly.

There's one Emacs command that can be used to execute any other command by typing it's long name: M-x. When you type M-x Emacs prompts you for the name of any command, and then executes it.

The ESC Prefix

There's one other prefix command that's both very important and completely redundant: the ESC prefix.

Not all keyboards provide a Meta key that sets the high order bit. On a PC running Emacs natively, the ALT key is used for Meta. But when using a PC to talk to a Unix box via some telecommunications program -- well, you guessed it -- the ALT key may not work for this.

But if you have no Meta key, all is not lost. You just use the ESC prefix. M-a becomes ESC a; C-M-f becomes ESC C-f (remember the equivalence of C-M-f and M-C-f and this will make sense).

There's only one trick: ESC is not a shift key. It's actually an ASCII character, not a key modifier. This means that you don't try to hold down ESC at the same time as the other key: use it as a prefix character and type it separately and distinctly. If you lean on it it's likely to autorepeat (like any other key) and you'll get very confused.

A true Meta is a wonderful thing for Emacs (it makes typing much faster), but I used ESC for years with no trouble.

Too Many Commands?

How does anyone remember all these commands? Simple: you don't. Every Emacs user knows a different set of commands. I've used Emacs for 20 years (starting with the original TECO Emacs), and I learn useful new Emacs commands all the time. Often I notice another Emacs user doing something and I have no idea how they've done it, so I ask and learn some Emacs command that I just never came across, or never developed as a habit.

Some Emacs users just learn the basics and are completely happy. Most users learn the basics and then some advanced commands that suit their needs. Some users are constantly learning new commands to speed their editing. A few users progress to writing their own totally new Emacs commands.

Files, Buffers and Windows

Emacs has three data structures (actually four) that are intimately related, and very important to understand:
File
A file is the actual Unix file on disk. You are never editing this file. Rather, you can read a copy into Emacs to initialize a buffer, and write a copy of a buffer out to a file to save it.
Buffer
A buffer is the internal data structure that holds the text you actually edit. Emacs can have any number of buffers active at any moment. Most, but by no means all, buffers are associated with a file. Buffers have names; a buffer that has been initialized from a file is almost always named for that file, and we say that the buffer is visiting the file. This means, in particular, that when you save the buffer, it's saved to the proper file. At any given time exactly one buffer is selected: this is the buffer that your hardware cursor is in, and this is where commands you type take effect (including self-insert commands). Buffers can be deleted at will; deleting a buffer in no way deletes the file on disk (though you may lose any editing changes you made if you don't save first).
Window
A window is your view of a buffer. Due to limited screen real-estate, you may not have room to view all your buffers at once. You can split the screen, horizontally or vertically, into as many windows as you like (or at least have room for), each viewing a different buffer. It's also possible to have several windows viewing different portions of the same buffer. Windows can be created and deleted at will; deleting a window in no way deletes the buffer associated with the window. Each window has its own Mode Line, but there's still only one minibuffer.
Frame
A frame is like a window, but is treated as a separate entity under a windowing system like X. I won't be discussing frames.

Commands to Manipulate Files

C-x C-f
find-file. This is the main command used to read a file into a buffer for editing. It's actually rather subtle. When you execute this command, it prompts you for the name of the file (with completion). Then it checks to see if you're already editing that file in some buffer; if you are, it simply switches to that buffer and doesn't actually read in the file from disk again. If you're not, a new buffer is created, named for the file, and initialized with a copy of the file. In either case the current window is switched to view this buffer.
C-x C-s
save-buffer. This is the main command used to save a file, or, more accurately, to write a copy of the current buffer out to the disk, overwriting the buffer's file, and handling backup versions.
C-x s
save-some-buffers. Allows you to save all your buffers that are visiting files, querying you for each one and offering several options for each (save it, don't save it, peek at it first then maybe save it, etc).

Commands to Manipulate Buffers

C-x b
switch-to-buffer. Prompts for a buffer name and switches the buffer of the current window to that buffer. Doesn't change your window configuration. This command will also create a new empty buffer if you type a new name; this new buffer will not be visiting any file, no matter what you name it.
C-x C-b
list-buffers. Pops up a new window which lists all your buffers, giving for each the name, modified or not, size in bytes, major mode and the file the buffer is visiting.
C-x k
kill-buffer. Prompts for a buffer name and removes the entire data structure for that buffer from Emacs. If the buffer is modified you'll be given an opportunity to save it. Note that this in no way removes or deletes the associated file, if any.
C-x C-q
vc-toggle-read-only. Make a buffer read-only (so that attempts to modify it are treated as errors), or make it read-write if it was read-only. Also, if the files is under version control, it will check the file out for you.

Commands to Manipulate Windows

C-v
scroll-up. The basic command to scroll forward (towards the end of the file) one screenful. By default Emacs leaves you two lines of context from the previous screen.
M-v
scroll-down. Just like C-v, but scrolls backwards.
C-x o
other-window. Switch to another window, making it the active window. Repeated invocation of this command moves through all the windows, left to right and top to bottom, and then circles around again. Under a windowing system, you can use the left mouse button to switch windows.
C-x 1
delete-other-windows. Deletes all other windows except the current one, making one window on the screen. Note that this in no way deletes the buffers or files associated with the deleted windows.
C-x 0
delete-window. Deletes just the current window, resizing the others appropriately.
C-x 2
split-window-vertically. Splits the current window in two, vertically. This creates a new window, but not a new buffer: the same buffer will now be viewed in the two windows. This allows you to view two different parts of the same buffer simultaneously.
C-x 3
split-window-horizontally. Splits the current window in two, horizontally. This creates a new window, but not a new buffer: the same buffer will now be viewed in the two windows. This allows you to view two different parts of the same buffer simultaneously.
C-M-v
scroll-other-window. Just like C-v, but scrolls the other window. If you have more than two windows, the other window is the window that C-x o would switch to.

Fundamental Concepts

It's probably more important to understand these fundamental Emacs concepts than it is to understand any of the actual editing commands. The editing commands are details: you can learn them easily on your own if you get the groundwork right.

Entering and Exiting

To enter Emacs, you just say:
    emacs
when it comes up, you won't be editing any file. You can then use the file commands to read in files for editing. Alternatively, you can fire up Emacs with an initial file (or files) by saying:
    emacs foo.tcl

To exit Emacs, use the command C-x C-c (which is bound to save-buffers-kill-emacs). It will offer to save all your buffers and then exit.

You can also suspend Emacs (in the Unix sense of stopping it and putting it in the background) with C-x C-z (which is bound to suspend-emacs). How you restart it is up to your shell, but is probably based on the fg command.

Self Inserting Commands

Once you've got Emacs running, you can type into it. There's no need for any special insert mode or anything like that: remember, printing characters insert themselves because each one is bound to self-insert-command.

The Screen

The Mode Line

The Emacs screen is completely devoted to the text of your file, except for one line near the bottom of the screen: the Mode Line. This line is informational: you can never move into it. It's almost always in reverse video or otherwise highlighted. It displays important information (which may change), including:
  • The state of the buffer, one of modified (indicated by a pair of asterisks), unmodified (hyphens), or read-only (indicated by a pair of % signs).
  • The name of the file you're editing (it will be *scratch* if you're not editing any file).
  • The major mode (in parens).
  • The amount of the file that you can see on the screen:
    All
    You can see all of the file.
    Top
    You can see the top of the file.
    Bot
    You can see the bottom of the file.
    Percentage
    NN% indicates the percentage of the file above the top of the window.

The Minibuffer

The blank line below the mode line is the minibuffer. The minibuffer is used by Emacs to display messages, and also for input when Emacs is prompting you to type something (it may want you to type yes or no in answer to a question, the name of a file to be edited, the long name of a command, etc).

The minibuffer is also known as the echo area, because Emacs echoes keystrokes here if you're typing really slowly. To see this, type any multi-character keystroke (like, ESC q) with a long pause between the keystrokes.

Strange Messages

Emacs will occasionally print messages in the minibuffer of its own accord, seemingly unrelated to what you're doing. The two most common messages are "Mark set" and "Garbage collecting...". The former means that Emacs has set the mark for you as a result of your last command; automatic mark setting is a convenient feature of some commands; see The Mark and The Region. The latter means that Emacs' lisp engine is reclaiming storage. You can just ignore it and keep typing, if you like: Emacs won't lose your characters.

Funny Characters

When your file contains control characters or characters with the high-order bit set, Emacs displays them as a backslash followed by three octal digits (where the digits give the ASCII value of the character). You'll notice that there's no ambiguity here: Emacs can tell the difference between a funny character and the four characters backslash digit digit digit. (You can't move the cursor between the digits of a funny character.) Note that if your terminal or windowing system is known to be able to display an 8-bit character set, like ISO Latin-1, Emacs will display those characters rather than the octal digits.

Long Lines

Emacs doesn't break lines for you automatically, unless you ask it to. By default it lets lines be as long as you type them. More importantly, it doesn't mess with long lines in files that you may read in. (Some editors, like old versions of vi, truncate long lines.)

It may seem annoying to have to hit return at the end of long lines, but this is actually just the default for certain modes. The reason for this is that Emacs is a programmer's editor, and any editor that will insert line breaks without your telling it to isn't safe for editing code or data. In modes oriented towards text, Emacs does insert line breaks for you automatically.

Eight Bit Clean

Emacs is eight bit clean, meaning you can edit binary files without corruption. (Some editors, like old versions of vi, corrupt certain characters, notably nulls and characters with the high bit set.)

Interrupting and Aborting

Sometimes Emacs will do something that you don't understand: it will prompt you for some information, or beep when you try to type, or something equally confusing. This just means that you've typed some command unwittingly (hitting a random function key is a good way to demonstrate this).

When this happens, you just need to type C-g (which is bound to keyboard-quit). This is the ASCII BEL character, and so C-g is sort of mnemonic for ringing the bell, which is what it does. But it also does something very important: it interrupts what Emacs is doing. This will get you out of any questions that Emacs may be asking you, and it will abort a partially typed key sequence (say if you typed C-x by mistake).

Because Emacs is fully recursive, you may occasionally need to type C-g more than once, to back out of a recursive sequence of commands. Also, if Emacs is really wedged (say, in a network connection to some machine which is down), typing three C-g's quickly is guaranteed to abort whatever's wedging you.

Help

Emacs has extensive online help, most of which is available via the help key, C-h. C-h is a prefix key. Type C-h twice to see a list of subcommands; type it three times to get a window describing all these commands (a SPC will scroll this window). Some of the most useful help commands are:
C-h a
command-apropos. Prompts for a keyword and then lists all the commands with that keyword in their long name.
C-h k
describe-key. Prompts for a keystroke and describes the command bound to that key, if any.
C-h i
info. Enters the Info hypertext d0cumentation reader.
C-h m
describe-mode. Describes the current major mode and its particular key bindings.
C-h p
finder-by-keyword. Runs an interactive subject-oriented browser of Emacs packages.
C-h t
help-with-tutorial. Run the Emacs tutorial. This is very helpful for beginners.

Info

Emacs has a builtin hypertext d0cumentation reader, called Info. To run it, type C-h i or M-x info RET. It has it's own tutorial, which you should run the first time through by typing h. The tutorial assumes you understand about as much about Emacs as is covered in this d0cument.

Infinite Undo with Redo

One of the most important Emacs commands is undo, invoked with C-_ (control underbar). C-_ is a valid ASCII character, but some keyboards don't generate it, so you can also use C-x u -- but it's more awkward to type, since it's a two-character command.

The undo command allows you to undo your editing, back in time. It's handy when you accidentally convert all of a huge file to uppercase, say, or delete a huge amount of text. One keystroke changes everything back to normal.

We say Emacs has infinite undo because, unlike some editors, you can undo a long chain of commands, not just one previous one, even undoing through saves. We say Emacs has redo because you can reverse direction while undoing, thereby undoing the undo.

Once you get used to this feature you'll laugh at any editor that doesn't have it (unless you're forced to use it...). It's very important to get comfortable with undo as soon as possible; I recommend reading the undo section of the manual carefully and practising.

Backups and Auto Save Mode

Emacs never modifies your file on disk until you tell it to, but it's very careful about saving your work for you in a number of ways.
Backup files.
Emacs always saves the previous version of your file when you save. If your file is named foo, the backup will be called foo~ (note the squiggle). Although it is off by default, Emacs will keep any number of previous versions for you, named foo.~1~, foo.~2~, etc. You can decide how many versions are to be kept. (But Unix provides more powerful tools for managing multiple versions of files.)
Auto-Save files.
Emacs also, by default, auto-saves your file while you're editing it. The auto-save file for a file foo is called #foo#. If Emacs (or the system) were to crash before you could save your edits, you can recover almost all of it from this file. Auto-saving happens (by default) every 300 characters, or when a system error is encountered.

Completion

To save you typing, Emacs offers various forms of completion: this means Emacs tries to complete for you partially typed file names, command names, etc. To invoke completion, you usually type TAB.

Giving Commands Arguments

Many Emacs commands take arguments, exactly the way a procedure or function takes arguments in a programming language. Most commands prompt you for their arguments: e.g., a command to read in a file will prompt you for the filename.

There's one kind of argument that's so commonly accepted that there's a special way to provide it: numeric arguments. Many commands will interpret a numeric argument as a request to repeat that many times. For example, the delete-char command (bound to C-d), which normally deletes one character to the right of the cursor, will delete N characters if given a numeric argument of N. It works with self-inserting commands too: try giving a numeric argument to a printing character, like a hyphen.

To give a command a numeric argument of, say, 12, type C-u 12 before typing the command. If you type slowly, you'll see:

C-u 1 2-
in the echo area. Then type C-d and you'll have given delete-char an argument of 12. You can type any number of digits after C-u. A leading hyphen makes a negative argument; a lone hyphen is the same as an argument of -1. If you begin typing a numeric argument and change your mind, you can of course type C-g to abort it.

Since one often isn't interested in precisely how many times a command is repeated, there's a shorthand way to get numeric arguments of varying magnitudes. C-u by itself, without any subsequent digits, is equal to a numeric argument of 4. Another C-u multiplies that by 4 more, giving a numeric argument of 16. Another C-u multiplies that by 4 more, giving a numeric argument of 64, etc. For this reason C-u is called the universal-argument.

Note that commands aren't required to interpret numeric arguments as specifying repetitions. It depends on what's appropriate: some commands ignore numeric arguments, some interpret them as Boolean (the presence of numeric argument -- any numeric argument -- as opposed to its absence), etc. Read the d0cumentation for a command before trying it.

Quoting Characters That Are Bound As Commands

Sometimes one needs to insert control characters into a file. But how can you insert an ESC, say, when it's used as a prefix command? The answer is to use the command quoted-insert, which is bound to C-q. C-q acts like a prefix command, in that when you type it it waits for you to type another character. But this next character is then inserted into the buffer, rather than being executed as a command. So C-q ESC inserts an Escape.

C-q can also be used to insert characters by typing C-q followed by their ASCII code as three octal digits.

Disabled Commands

Some commands that are especially confusing for novices are disabled by default. When a command is disabled, invoking it subjects you to a brief dialog, popping up a window displaying the d0cumentation for the command, and giving you three choices:
  • Space to try the command just this once, but leave it disabled,
  • Y to try it and enable it (no questions if you use it again),
  • N to do nothing (command remains disabled).
You're very likely to encounter one particular disabled command: M-ESC (aka ESC ESC), because it's very easy to type two escapes in a row when using the Escape prefix.

Motion and Objects

One of the main things one does in an editor is move around, in order to apply editing commands. Emacs provides many motion commands, which are arranged around textual objects: for each textual object, there is typically a motion command that moves forward over such an object and backward over it (or you can think of this as moving to the beginning and to the end).

All these motion commands take numeric arguments as repetitions.

The most basic textual object is the character. Emacs understand many other objects, sometimes depending on what mode you're in (a C function textual object probably doesn't make much sense if you're not editing C source code).

The exact definition of what makes up a given textual object is often customizable, but more importantly varies slightly from mode to mode. The characters that make up a word in Text Mode may not be exactly the same as those that make up a word in C Mode for example. (E.g., underbars are considered word constituents in C Mode, because they are legal in identifier names, but they aren't considered word constituents in Text Mode.) This is extremely useful, because it means that you can use the same motion commands and yet have them automatically customized for different types of text.

Characters

C-f
forward-char. Moves forward (to the right) over a character.
C-b
backward-char. Moves backward (to the left) over a character.
The f for forward and b for backward mnemonic will reoccur.

Words

M-f
forward-word. Moves forward over a word.
M-b
backward-word. Moves backward over a word.
Note the f/b mnemonic. Also, as another mnemonic, note that M-f is like a "bigger" version of C-f.

Lines (vertically)

C-n
next-line. Moves down to the next line.
C-p
previous-line. Moves up to the previous line.
When moving by lines, the cursor tries to stay in the same column, but if the new line is too short, it will be at the end of the line instead. This is very important: Emacs doesn't insert spaces at the ends of lines (end of line is unambiguous).

Lines (horizontally)

C-a
beginning-of-line. Moves to the beginning of the current line.
C-e
end-of-line. Moves to the end of the current line.
E for end, A for the beginning of the alphabet.

Sentences

M-a
backward-sentence. Moves to the beginning of the current sentence.
M-e
forward-sentence. Moves to the end of the current sentence.
Note the mnemonic relation between C-a / M-a and C-e / M-e.

Paragraphs

M-{
backward-paragraph. Move to the beginning of the current paragraph.
M-}
forward-paragraph. Move to the end of the current paragraph.

Pages

C-x [
backward-page. Moves to the beginning of the current page.
C-x ]
forward-page. Moves to the end of the current page.
Pages are separated by formfeed characters (C-l) in most modes.

Buffers

M-<
beginning-of-buffer. Moves to the beginning of the buffer.
M->
end-of-buffer. Moves to the end of the buffer.

S-Expressions (balanced parentheses)

An S-expression (sexp for short) is the name for balanced parentheses (and the text they enclose) in Lisp. In Emacs, this useful notion is available in most modes; it's especially useful for editing programming languages. The characters that Emacs recognizes as parens are usually regular parentheses (aka round brackets), square brackets, and braces (aka curly brackets), but it depends on the mode (for some languages, angle brackets may act as parens).

But sexps are more than just balanced parens: they're defined recursively. A word that doesn't contain any parens also counts as a sexp. In most programming language modes, quoted strings are sexps (using either single or double quotes, depending on the syntax of the language). The sexp commands move in terms of all these units.

These commands may seem confusing at first, but for editing most programming languages they're fantastic. Not only do they move you around quickly and accurately, but they help spot syntax errors while you're editing, because they'll generate an error if your parens or quotes are unbalanced.

C-M-b
backward-sexp. Moves backward over the next sexp. If your cursor is just to the right of a left paren, C-M-b will beep, because there's no sexp to the left to move over: you have to move up.
C-M-f
forward-sexp. Moves forward over the next sexp. Same deal if your cursor is just to the left of a right paren.
C-M-u
backward-up-list. Move backward up one level of parens. In other words, move to the left paren of the parens containing the cursor, skipping balanced sexps.
C-M-d
down-list. Move down one level of parens. In other words, move to the right of the next left paren, skipping balanced sexps. E.g., if your cursor is sitting on the return type of a C function declaration, C-M-d moves to the inside of the formal parameter list.

Functions

Since functions are such an important unit of text in programming languages, whether they're called functions, subroutines, procedures, procs, defuns or whatever, Emacs has commands to move over them. Like the sexp commands, these commands work appropriately in most programming language modes. Emacs calls this generic notion of function or procedure defun, again after Lisp.
C-M-a
beginning-of-defun. Move to the beginning of the current defun.
C-M-e
end-of-defun. Move to the end of the current defun.
Note the mnemonic analogy with lines and sentences.

Deleting, Killing and Yanking

Emacs' deletion commands are also based on the textual objects above. But first, a terminological distinction: Deletion means to remove text from the buffer without saving it; most deletion commands operate on small amounts of text. Killing means to save the removed text, so that it can be yanked back later someplace else.

Killed text is saved on the kill ring. The kill ring holds the last N kills, where N is 30 by default, but you can change it to anything you like by changing the value of the variable kill-ring-max. The kill ring acts like a fifo when you're killing things (after the 30th kill, kill number one is gone), but like a ring when you're yanking things back (you can yank around the ring circularly). kill-ring-max doesn't apply to the amount of text (in bytes) that can be saved in the kill ring (there's no limit), only to the number of distinct kills.

Characters

C-d
delete-char. Deletes the character to the right of (under, if the cursor is a block that covers a character) the cursor.
DEL
delete-backward-char. Deletes the character to the left of the cursor.
Remember, Emacs does not use C-h (aka Backspace) for deletion, but for help! Depending on your cultural background, this may well be the single hardest thing to learn about Emacs. Why does Emacs make this choice? Well, since there's no need for two commands to delete one character backward, and since DEL (aka Delete) can only be mnemonic for deletion while C-h is a nice mnemonic for help, the choice was made. Me, I've never used C-h to delete, so it suits me fine.

Words

M-d
kill-word. Kills to the end of the word to the right of the cursor (forward).
M-DEL
backward-kill-word. Kills to the beginning of the word to the left of the cursor (backward).

Lines (vertically)

It doesn't seem too intuitive to kill lines vertically by analogy with C-n and C-p; I know of no such commands.

Lines (horizontally)

C-k
kill-line. Kills to the end of the current line, not including the newline. Thus, if you're at the beginning of a line it takes two C-k's to kill the whole line and close up the whitespace.
C-u 0 C-k
kill-line. Kills to the beginning of the current line, not including the newline.
You might think that C-u -1 C-k would be used to kill to the beginning of the line, and it does, but it includes the newline before the line as well.

Sentences

M-k
kill-sentence. Kills to the end of the current sentence, including any newline within the sentence.
C-u -1 M-k
kill-sentence. Kills to the beginning of the current sentence, including any newlines within the sentence.

Paragraphs

The commands forward-kill-paragraph and backward-kill-paragraph exist, but are not bound to any keys by default.

Pages

There are no commands to kill pages (but see The Mark and the Region).

Buffers

The command kill-buffer doesn't kill all the text in the buffer, but rather the entire buffer data structure; see The Mark and the Region.

S-Expressions (balanced parentheses)

C-M-k
kill-sexp. Kills the sexp after the cursor.
C-u -1 C-M-k
kill-sexp. Kills the sexp before the cursor.
The command backward-kill-sexp exists, but is not bound to any key by default.

Functions

There are no commands to kill functions (defuns) (but see The Mark and the Region).

Extending Kills

If you kill several times in a row, with any combination of kill commands, but without any non-kill commands in between, these kills are appended together in one entry on the kill ring. For example you can kill a block of text as several lines by saying C-u 6 C-k, which kills (as one kill) 6 lines.

Yanking

Once you've killed some text, how do you get it back? You can yank back the most recently killed text with C-y (yank). Since Emacs has only one kill ring (as opposed to one per buffer), you can kill in one buffer, switch to another and yank the text there.

To get back previous kills, you move around the kill ring. Start with C-y to get the most recent kill, and then use M-y to move to the previous spot in the kill ring by replacing the just-yanked text with the previous kill. Subsequent M-y's move around the ring, each time replacing the yanked text. When you reach the text you you're interested in, just stop. Any other command (a motion command, self-insert, anything) breaks the cycling of the kill ring, and the next C-y yanks the most recent kill again.

Copying and Moving Text

Emacs has no need for special commands to copy or move text; you've already learned them! To move text, just kill it and yank it back elsewhere. To copy text, kill it, yank it back immediately (so it's as if you haven't killed it, except it's now in the kill ring), move elsewhere and yank it back again. For commands to copy and move arbitrary regions of text, as opposed to textual objects, see The Mark and The Region.

Searching and Replacing

Emacs has a variety of unusual and extremely powerful search and replace commands. The most important one is called incremental search. This is what the command isearch-forward, bound to C-s, does: it searches incrementally, one character at a time, as you type the search string. This means that Emacs can often find what you're looking for before you have to type the whole thing. To stop searching, you can either hit RET or type any other Emacs command (which will both stop the search and execute the command). You can search for the next match at any point by typing another C-s at any point; you can reverse the search by typing C-r; and you can use DEL to delete and change what you're searching for.

isearch-backward, bound to C-r, works the same way, but searches backward. (Use C-r to search for the next match and C-s to reverse the search.)

Occasionally you may want to search non-incrementally (though I rarely do). You can do this by typing C-s RET text RET, where text is the text to search for.

Much more useful is word search, which lets you search for a sequence of one or more words, regardless of how they're separated (e.g, by any number and combination of newlines and whitespace). To invoke word search, type C-s RET C-w word word word RET.

Emacs can also search incrementally (or not) by regular expressions; this is an extremely powerful feature, but too complex to describe here.

Replacement

Emacs' most important command for replacing text is called query-replace (bound to M-%). This command prompts you for the text to replace, and the text to replace it with, and then searches and replaces within the current buffer. query-replace is interactive: at each match, you are prompted to decide what to do; you have the following options:
SPC
Perform this replacement.
DEL
Don't perform this replacement.
RET
Terminate query-replace without performing this replacement.
ESC
Same as RET.
.
Perform this replacement but then terminate the query-replace.
!
Perform this replacement and all the rest in the buffer without querying (ie unconditionally).
There are many more subcommands, but they require more Emacs expertise to understand them.

There are also more replacement commands you should look into, including replace-string (simple unconditional replacement), replace-regexp and query-replace-regexp (which use regular expressions), and tags-query-replace, which replaces all identifiers in a collection of source code files.

query-replace and the other replacement commands are, by default, smart about case. For example, if you're replacing foo with bar and find Foo, Emacs replaces it with Bar; if you find FOO, Emacs replaces it with BAR, etc.

The Mark and The Region

Emacs can manipulate arbitrary chunks of text as well as distinct textual objects. The way this is done is to define a region of text; many commands will operate on this region.

The region is the text between point and mark. Point is actually the Emacs term for what we've been calling the cursor up to now. The mark, on the other hand, is set with a special command C-@ (set-mark-command). This sets the mark exactly where point is, but now you can move point elsewhere and you have: the region.

Each buffer has a distinct point and mark, and therefore a distinct region. (It's also possible for there to be no mark in a buffer, and therefore no region.)

The region is the same regardless of whether point comes first in the buffer or mark does; it makes no difference, just do what's convenient.

The region is normally invisible (but see C-x C-x). You'll get used to this. However, if you're running Emacs under a windowing system, you can make the region visible by executing M-x transient-mark-mode.

Many commands that move point a significant distance (like M-< and C-s, for example) leave the mark set at the spot they moved from. You'll see "Mark set" in the echo area when this happens.

When using Emacs under a windowing system like X, the mouse can be used to sweep out the region, but many Emacsers find it faster to keep their hands on the keyboard and use the familiar motion commands.

There are some special commands that are specifically designed to set the region around some interesting text.

M-@
mark-word. Sets the region around the next word, or from point to the end of the current word, if you're in the middle of one.
M-h
mark-paragraph. Sets the region around the current paragraph.
C-M-@
mark-sexp. Sets the region around the same sexp that C-M-f would move to.
C-M-h
mark-defun. Sets the region around the current defun.
C-x C-p
mark-page. Sets the region around the current page.
C-x h
mark-whole-buffer. Sets the region around the entire buffer.

So now you know how to define the region: what can you do with it?

C-x C-x
exchange-point-and-mark. Swaps mark and point. Repeated rapid execution of this command makes it easy to see the extent of the region.
C-w
kill-region. Kills the region. It goes on the kill ring, of course.
M-w
kill-ring-save. Saves the region to the kill ring without removing it from the buffer. This is exactly equivalent to typing C-w C-y.
C-x C-i
indent-rigidly. Rigidly indents the region by as many characters (columns) as you provide as a numeric argument (default is 1 column).
C-x C-l
downcase-region. Convert the entire region to lowercase. This command is disabled by default.
C-x C-u
upcase-region. Convert the entire region to uppercase. This command is disabled by default.
M-x fill-region
fill-region. Fills, i.e., justifies with a ragged right margin, all the paragraphs within the region.
There are many, many more.

Indentation

In programming language modes, Emacs uses the TAB key to indent a line automatically, in accordance with indentation rules for your programming language. For example, in C Mode Emacs understands if, while, do, for, functions, switch, etc and indents appropriately. Of course, there are no hard and fast rules for indentation in most languages, so Emacs allows you to customize the indentation for your own style.

Modes

The main way Emacs customizes commands for different kinds of text is through major and minor modes. Every buffer has a major mode, and may have zero or more minor modes. Sometimes Emacs chooses a major mode for you automatically, typically based on a file extension (e.g., files ending in .c will automatically be in C Mode; files ending in .tcl will automatically be in Tcl Mode). But you can always set the mode explicitly.

Some Major Modes

Fundamental Mode
The basic mode in reference to which all specialized modes are defined. Perfectly fine for editing any kind of text, just doesn't provide any special features.
Text Mode
For editing text. Has special commands for spell-checking, centering lines, etc.
Outline Mode
For editing a stylized type of outline. Implements folding of outline levels, etc.
Lisp Mode
For editing Common Lisp source code. Has an interactive link to a Common Lisp interpreter in another buffer.
Tcl Mode
For editing Tcl source code. Has an interactive link to a Tcl interpreter in another buffer.
C Mode
For editing C source code. Has special indentation, etc.
There are many other major modes, some very specialized (e.g., modes for editing sending email, reading Usenet news, browsing directories, browsing the World Wide Web, etc).

Further Information

GNU Emacs Frequently Asked Questions List

The GNU Emacs FAQ is very well done; I recommend it highly.

Info

Don't forget that the complete text of the GNU Emacs Manual is available via Info, Emacs' hypertext d0cumentation reader.

Usenet Newsgroups

Only a selection of some of the Emacs-related Usenet newsgroups.
gnu.emacs.help
Help for users' GNU Emacs problems, answered by your peers.
comp.emacs
General coverage of all Emacs-like editors.
gnu.emacs.announce
Announcements of new versions of GNU Emacs, etc.
alt.religion.emacs
Emacs as religion. Official home of the perennial flame wars.
gnu.emacs.sources
Postings of source code for new GNU Emacs programs.

Bibliography

  • Richard M. Stallman. GNU Emacs Manual. Cambridge, MA: Free Software Foundation, [n.d.]. The authoritative user's reference; also a fine introduction. The complete text is available on the Web and via Info.
  • Debra Cameron and Bill Rosenblatt. Learning GNU Emacs. Sebastopol, CA: O'Reilly and Associates, 1991. A good introduction. Covers version 18 only.
  • Michael A. Schoonover et al. GNU Emacs: Unix Text Editing and Programming. Reading, MA: Addison-Wesley, 1992.
  • Bill Lewis, Dan LaLiberte, and the GNU Manual Group. GNU Emacs Lisp Reference Manual. Cambridge, MA: Free Software Foundation, 1993. Covers version 19 Elisp. Only if you want to learn to program in Emacs Lisp. The complete text is available on the Web and via Info.
  • Richard M. Stallman. "EMACS: The Extensible, Customizable, Self-Documenting Display Editor". In Interactive Programming Environments, edited by David R. Barstow, Howard E. Shrobe, and Erik Sandewall. New York: McGraw-Hill, 1984. An interesting article on the design of Emacs. Predates GNU Emacs; covers the original TECO Emacs and Lisp Machines Emacsen.

Keith Waclena
The University of Chicago Library

This page last updated: Tue Feb 3 23:37:14 CST 2009

'Computer Science' 카테고리의 다른 글

안드로이드 wiki  (0) 2010.01.10
룩업 테이블  (0) 2010.01.09
안드로이드 프로그래밍 개요  (0) 2010.01.03
iPhone Coding Tutorial &#8211; In Application Emailing  (0) 2009.12.25
Introduction to MapKit in iPhone OS 3.0  (0) 2009.12.25

How to Program Google Android
By Reto Meier

So you saw the Android announcement and decided you wanted a piece of that US$10million in prize money huh? In the week since the SDK was released more than 4,300 people have joined the Android support forum posting more than 4,000 messages between them. Robert Scoble doesn't know a single developer playing with Android – perhaps Scoble doesn't hang around with many developers?

I wanted to give the SDK a good work-out so my application uses the GPS, the address book, and has a map.

The only way to judge an SDK is getting in there and writing an application that does something cool, so I'll take you through the development process for my first Android application: Where Are My Friends?

WamF shows how far away you are right now from all the people in your address book, plots you and them on a map, and draws lines between you and any friends nearby.

WamF is pretty simple but it makes use of some of the more interesting features of Android – Location Based Information (GPS etc), maps, the contacts manager, and the phone dialer. Total development time from hitting Download on the SDK page was about 14 hours (spread over two mornings and evenings).

My Android development is in Windows with Eclipse using the plugin, so I will assume you're doing the same.

Before I get started here's a bit on my background. I've mentioned before that I'm a C# .NET desktop applications developer in my real life. It's been almost 10 years since I've done anything with Java and I've never done any mobile phone development. With Android I develop in Windows with Eclipse using the Android plugin.

Let's start by downloading Eclipse and unzipping it into a new folder. Then download the Android SDK and unzip that into another new folder. Open Eclipse and create a new workspace for Android development.

Install the Android Plugin by selecting Help > Software Updates > Find and Install..., and in the dialog box choose Search for new Features to install. Select New Remote Site and enter https://dl-ssl.google.com/android/eclipse/. into the dialog box. Hit OK and accept all the prompts until it's installed. Restart Eclipse and you're almost ready to rock.

Select Window > Preferences... and select Android, then put the folder where you unzipped the SDK into the SDK Location text box. Hit Apply then OK and you're done.

The tutorial and exercises are useful. Do them.

Let's make sure everything's installed right by creating the Hello Android demo. The Android team have a detailed description of how to do this so I won't repeat it here. It's worth checking out the known bugs if you encounter any problems.

The Android d0cumentation is excellent; after you've finished the Hello Android project run through the exercises. They're easy to follow and give a good idea of how a 'real' application fits together.

Design a UI, leveraging one of the sample projects

Onto business. Step one should always be UI design. Figure out what it is you want to tell the user and what actions they'll need then develop an interface that will make this as intuitive as possible. To keep things simple I'm going to base my new project on the NotePad project used in the tutorial exercises.

I'll start by changing the resource strings to change the name of the app, and modifying the menu options .

Use the Location Based Services to figure out where we are and request updates when we move

Possibly the most enticing of the Android features are the Location Based Services that give your application geographical context through Location Providers (GPS etc). Android includes a mock provider called 'gps' that marches back and forth through San Fransisco. Alternatively you can create your own mock providers in XML.

You use the LocationManager to find your current position.

    locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); Location location = locationManager.getCurrentLocation("gps");

Iterate over the address book pulling out names, locations, and phone numbers

A less publicized feature of Android is the ability to share content between applications. We're going to use this feature to populate our List with our contacts' names and their current distance from our phone so we create an updateList method that we call after we've gotten our current location.

Use the ContentResolver to return a query that provides access to data shared using Content Providers. Queries are returned as cursors that provide access to the underlying data tables. The data we're interested in is accessed using the People content provider.

    Cursor c = getContentResolver().query(People.CONTENT_URI, null, null, null, null); startManagingCursor(c);

The Cursor is a managed way of controlling your position (Row) in the underlying table. We get access to the data by specifying the column that holds the information we're after. Rather than memorising the column index for each Content Provider we can use constants from the People class as a shortcut.

    int coordIdx = c.getColumnIndex(People.NOTES); int phoneIdx = c.getColumnIndex(People.PhonesColumns.NUMBER); int nameIdx = c.getColumnIndex(People.NAME);

Now iterate over the table using the cursor storing the results in arrays. You'll note that we're pulling our contacts' location from the Notes field. In reality we'd want to figure this out based on their address using a geocoding lookup.

    List listItems = new ArrayList();

    c.first();
    do {
      String name = c.getString(nameIdx);
      String coords = c.getString(coordIdx);
      String phone = c.getString(phoneIdx);

      ... [ Process the lat/long from the coordinates ] ...
      ... [ Storing their location under variable loc ] ...

      String distStr = String.valueOf(location.distanceTo(loc)/1000);
      name = name + " (" + distStr + "km)";
      listItems.add(name);

      numbers.add("tel:" + phone);
    } while(c.next());

Then we assign our list of strings to the array using an ArrayAdapter.

    ArrayAdapter notes = new ArrayAdapter(this, R.layout.notes_row, items);
    setListAdapter(notes);

Refresh our list when we move

Given the location sensitive nature of WamF it makes sense to update the display whenever we move. Do this by asking the LocationManager to trigger a new Intent when our location provider notices we've moved.

    List providers = locationManager.getProviders();
    LocationProvider provider = providers.get(0);
    Intent intent = new Intent(LOCATION_CHANGED);
    locationManager.requestUpdates(provider, minTime, minDistance, intent);

Intents in Android are like events in traditional event driven programming, so we're triggering a LOCATION_CHANGED event/intent every time we move by a minimum distance after a minimum time. The next step is to create an IntentReceiver (event handler), so create a new internal class that extends IntentReceiver and override the ReceiveIntent event to call our update method.

    public class myIntentReceiver extends IntentReceiver {
      @Override
      public void onReceiveIntent(Context context, Intent intent) {
        updateList();
      }
    }

We then have our activity listen for a LOCATION_CHANGED intent by registering the event handler and specifying the intent it should be listening for (LOCATION_CHANGED). Do this in the onCreate method or create a new menu option to start/stop the automatic updates.

    filter = new IntentFilter(LOCATION_CHANGED);
    receiver = new myIntentReceiver();
    registerReceiver(receiver, filter);

Keep your phone running light by registering / unregistering the receiver when the activity Pauses and Resumes – there's no point in listening for location changes if we can't see the list.

Set up a map activity and create an overlay to show where you are in relation to your friends

Half of the fun in having location sensitive information is drawing it on a map. Create a new activity class to display a map centered on our current location with markers at our friends locations. While we're at it we can draw a line from our position to each of our friends.

The map control itself is called a MapView, but we can only use a MapView in a MapActivity, so we'll change the inheritance of this activity to MapActivity.

    public class MyMapViewActivity extends MapActivity

To display the map we need to create a new MapView and set it as the content for our activity in the OnCreate method.

    MapView mapView = new MapView(this);
    setContentView(mapView);

This will make the MapView fill the entire screen, so use views like LinearLayout if we want to create a more complicated UI layout.

We'll want to get access to the OverlayController and MapController, so create global variables to store them and assign the references within the OnCreate method. We'll also be using the Location information, so get a reference to that too. With the references assigned set your map zoom and starting location using the MapController. When you're finished OnCreate should look something like this.

    protected void onCreate(Bundle icicle) {
      super.onCreate(icicle);
      MapView mapView = new MapView(this);
      mapController = mapView.getController();
      overlayController = mapView.createOverlayController();
      locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
      mapController.zoomTo(9);
      setContentView(mMapView);
      updateView();
    }

updateView is where we do the work. Start by getting our current location and convert the Lat/Long to a map Point, then centre the map on our current location.

    Double lat = location.getLatitude()*1E6;
    Double lng = location.getLongitude()*1E6;
    Point point = new Point(lat.intValue(), lng.intValue());
    mapController.centerMapTo(point, false);

The only thing left to do on our map is draw markers and link them up with lines. To do this you need to create a new class that extends Overlay, and add this using the OverlayController.

    MyLocationOverlay myLocationOverlay = new MyLocationOverlay();
    overlayController.add(myLocationOverlay, true);

The work in the Overlay class is done by overriding the draw method.

    protected class MyLocationOverlay extends Overlay {
      @Override
      public void draw(Canvas canvas, PixelCalculator calculator, boolean
      shadow) {
        ... [ draw things here ] ...
      }
    }

I start by drawing a 'marker' on my current location. There doesn't seem to be support for 'traditional' Google Maps markers but you can achieve the same thing by drawing on the map canvas; I chose to draw small circles as markers. First you need to use the PixelCalculator to convert your Lat/Long points to screen coordinates, then create a Paint object to define the colours and settings for your brush. Then paint your markers.

    int[] screenCoords = new int[2];
    calculator.getPointXY(point, screenCoords);
    RectF oval = new RectF(...);
    Paint paint = new Paint();
    paint.setARGB(200, 255, 0, 0);
    canvas.drawOval(oval, paint);

I add my friends locations the same way as before, iterating over my address book grabbing names and locations. I filter out anyone too far away (say 10km) and draw markers, names (drawText), and joining lines (drawLine) to those nearby.

Let's make a call

Now we know when we're close to our friends, what are we likely to want to do when we're close? Drop in! But we're polite so we'll call them first. Let's change our list item click function to call the friend we've clicked. We can do this by firing a DIAL_ACTION intent.

    Intent i = new Intent();
    i.setAction(DIAL_ACTION);
    i.setData(new ContentURI(numbers.get(position)));
    startActivity(i);

The phone dialer has registered an IntentReceiver filtered on DIAL_ACTION so it will react to this.

Android is an environment where the biggest limitation is your imagination

And that's it.

I've got a list of a dozen or so changes to make it a little more useful and a half dozen ideas for projects that might actually make it into the running for some of that prize money. My conclusion? Android is everything a development kit should be – an environment where the biggest limitation is what you can imagine.

'Computer Science' 카테고리의 다른 글

룩업 테이블  (0) 2010.01.09
EMACS 메뉴얼  (0) 2010.01.03
iPhone Coding Tutorial &#8211; In Application Emailing  (0) 2009.12.25
Introduction to MapKit in iPhone OS 3.0  (0) 2009.12.25
안드로이드 2.0 설치  (0) 2009.12.25

http://icodeblog.com/2009/11/18/iphone-coding-tutorial-in-application-emailing/

http://icodeblog.com/2009/11/18/iphone-coding-tutorial-in-application-emailing/

iPhone Coding Tutorial – In Application Emailing

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

IMG_0001A lot of applications you see have an email button. When you click it then it will leave the application and take you to the Mail application. It can get really annoying leaving the application and then going back in after your done sending the email. This is just a great way to show off your app and make your app look more professional and make it easier on the user by filling in the To and Subject for them. They are also able to change the From to whatever email then want you to receive an email from just like you can do in the Mail app. So todays tutorial is gonna show you how to email within your application. We will be using the MessageUI framework and we will also include an attachment in the email. Theres a screenshot to the left of how it will look.

So lets get started…

1. Create A New View Based Application
You can name yours whatever you want, in the tutorial I will be referring it as the NameViewControllers.

2. Import The Frameworks

The first thing we need to do is import the framework. So go to your Frameworks folder in the Files In Pain section on the left. Open the folder and right click one of the frameworks and click “Reveal In Finder.” Heres a screenshot on what you should do.

Screen shot 2009-11-18 at 7.58.04 PM

Go ahead and look for the “MessageUI.framework” and highlight it then drag it into your frameworks folder. Make sure that when you click Add on the thing that makes sure you want to import it that “Copy items into destination group’s folder (if needed)” is not check. Thats a very important step or you will have big time problems and you do this with any frameworks you would ever use in the future.

3. Implementing The Code

Now that we have imported the framework lets get into some coding. So go ahead and jump in the NameViewController.H and make an IBAction for a button. Then copy that code and paste it in the NameViewController.M with curly brackets. Also make sure to add the button in Interface Builder and link it up with a Touch Up Inside method. You guys are at the point to knowing how to hook up actions and dragging stuff into Interface Builder. After that we want to on the top of the NameViewController.h import the framework. So on the top do #import “MessageUI/MessageUI.h” and the reason why we do this is because we must import out MessageUI framework to make calls to the associated header files. Nowwe need to also put in the delegate protocols for this framework. @interface NameViewController: UIViewController do this code <MFMailComposeViewControllerDelegate, UINavigationControllerDelegate>. Heres the code here for the NameViewController.H

#import <MessageUI/MessageUI.h>

@interface MailComposerViewController : UIViewController

<MFMailComposeViewControllerDelegate,UINavigationControllerDelegate> {

}

-(IBAction)pushEmail;

@end


Now after your done with the .H jump into the .M viewcontroller. Now in your button action code do this:

-(IBAction)pushEmail {

MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];

mail.mailComposeDelegate = self;

if ([MFMailComposeViewController canSendMail]) {

//Setting up the Subject, recipients, and message body.

[mail setToRecipients:[NSArray arrayWithObjects:@"email@email.com",nil]];

[mail setSubject:@"Subject of Email"];

[mail setMessageBody:@"Message of email" isHTML:NO];

//Present the mail view controller

[self presentModalViewController:mail animated:YES];

}

//release the mail

[mail release];

}

//This is one of the delegate methods that handles success or failure

//and dismisses the mail

- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error

{

[self dismissModalViewControllerAnimated:YES];

if (result == MFMailComposeResultFailed) {

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Message Failed!” message:@”Your email has failed to send” delegate:self cancelButtonTitle:@”Dismiss” otherButtonTitles:nil];

[alert show];

[alert release];

}

}


What if we wanted to include an image attachment to the email? Well its quite simple. Just add this to the code right under the part where you set up the Recipient, Subject, and the Message.

UIImage *pic = [UIImage imageNamed:@"Funny.png"];

NSData *exportData =UIImageJPEGRepresentation(pic ,1.0);

[mail addAttachmentData:exportData mimeType:@"image/jpeg" fileName:@"Picture.jpeg"];

Now we are setting up the MailComposer in the first part of the code in the action. Then we call a didFinishWithResult method where we are setting up if the email fails or sends. Also it sets up a Cancel button for you so we have to call the dismiss method so that it works. In the attachment code just edit the imageNamed:@”" with your images name.That is basically it! The source code is below for the people that just doesn’t wanna copy and paste or type… I am just jking with you guys. Happy iCoding!

iPhone Tutorial – In Application Emailing

'Computer Science' 카테고리의 다른 글

EMACS 메뉴얼  (0) 2010.01.03
안드로이드 프로그래밍 개요  (0) 2010.01.03
Introduction to MapKit in iPhone OS 3.0  (0) 2009.12.25
안드로이드 2.0 설치  (0) 2009.12.25
소프트웨어기술경력증 수신  (0) 2009.11.07

http://icodeblog.com/2009/12/21/introduction-to-mapkit-in-iphone-os-3-0/

http://icodeblog.com/2009/12/21/introduction-to-mapkit-in-iphone-os-3-0/

Introduction to MapKit in iPhone OS 3.0

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

Introduction

Hello everyone. Welcome to another screencast. Today we will be looking into the MapKit, a new API’s made available by Apple in the iPhone OS 3.0 release. The MapKit allows simple access to the map seen in the maps application. Using GoogleMaps as its engine the map kit allows for a developer to make their own custom map interface to fit their own application. Today we will be reviewing the MapView as well as the Map Annotations that can be used to highlight points of interest in a map. We will create our own custom map app, along with custom annotations. Let’s dive in.

Skill Level Intermediate

This tutorial is one for people familiar with general Objective C development and introductory experience to the iPhone SDK. Knowledge of general Interface Builder usage and DataSource and Delegate methods are required.

Screencast

I film myself coding out the entire sample project for each post. I personally think going through the Screencast is the best way to learn. But feel free to look through the slides and text if that suites you better.

Introduction to Map Kit on iPhone OS 3.0 from Collin Ruffenach on Vimeo.

Source

iCodeBlogMap Source

Tutorial

Introduction to MapKit on iPhone OS 3.001

Introduction to MapKit on iPhone OS 3.002

Introduction to MapKit on iPhone OS 3.003

Introduction to MapKit on iPhone OS 3.004

Introduction to MapKit on iPhone OS 3.005

Introduction to MapKit on iPhone OS 3.006

Introduction to MapKit on iPhone OS 3.007

Introduction to MapKit on iPhone OS 3.008

Introduction to MapKit on iPhone OS 3.009

Introduction to MapKit on iPhone OS 3.010

Introduction to MapKit on iPhone OS 3.011

Introduction to MapKit on iPhone OS 3.012

Introduction to MapKit on iPhone OS 3.013

Introduction to MapKit on iPhone OS 3.014

Introduction to MapKit on iPhone OS 3.015

Introduction to MapKit on iPhone OS 3.016

Introduction to MapKit on iPhone OS 3.017

Introduction to MapKit on iPhone OS 3.018

Introduction to MapKit on iPhone OS 3.019

Introduction to MapKit on iPhone OS 3.020

Introduction to MapKit on iPhone OS 3.021

Introduction to MapKit on iPhone OS 3.022

iCodeBlogMapViewController.h

#import "iCodeBlogAnnotation.h"#import "iCodeBlogAnnotationView.h"@interface iCodeMapViewController : UIViewController{	IBOutlet UITableView *tableview;	IBOutlet MKMapView *mapView;	IBOutlet UIImageView *shadowImage;}@property (nonatomic, retain) IBOutlet UITableView *tableview;@property (nonatomic, retain) IBOutlet MKMapView *mapView;@property (nonatomic, retain) IBOutlet UIImageView *shadowImage;-(void)loadOurAnnotations;@end

Introduction to MapKit on iPhone OS 3.023

iCodeBlogAnnoation.h

typedef enum {
	iCodeBlogAnnotationTypeApple = 0,	iCodeBlogAnnotationTypeEDU = 1,	iCodeBlogAnnotationTypeTaco = 2} iCodeMapAnnotationType;@interface iCodeBlogAnnotation : NSObject{	CLLocationCoordinate2D coordinate;	NSString *title;	NSString *subtitle;	iCodeMapAnnotationType annotationType;}@property (nonatomic) CLLocationCoordinate2D coordinate;@property (nonatomic, retain) NSString *title;@property (nonatomic, retain) NSString *subtitle;@property (nonatomic) iCodeMapAnnotationType annotationType;@end

Introduction to MapKit on iPhone OS 3.024

Introduction to MapKit on iPhone OS 3.025

Introduction to MapKit on iPhone OS 3.026

iCodeBlogAnnoation.m

@implementation iCodeBlogAnnotation@synthesize coordinate;@synthesize title;@synthesize subtitle;@synthesize annotationType;-init{	return self;}-initWithCoordinate:(CLLocationCoordinate2D)inCoord{	coordinate = inCoord;	return self;}@end

Introduction to MapKit on iPhone OS 3.027

iCodeBlogAnnoationView.h

@interface iCodeBlogAnnotationView : MKAnnotationView{	UIImageView *imageView;}@property (nonatomic, retain) UIImageView *imageView;@end

Introduction to MapKit on iPhone OS 3.028

Introduction to MapKit on iPhone OS 3.029

Introduction to MapKit on iPhone OS 3.030

Images to Use

AppleMarker

SchoolMarker

TacosMarker



iCodeBlogAnnoationView.m

#import "iCodeBlogAnnotationView.h"@implementation iCodeBlogAnnotationView@synthesize imageView;#define kHeight 40#define kWidth  37#define kBorder 2- (id)initWithAnnotation:(id )annotation reuseIdentifier:(NSString *)reuseIdentifier{	iCodeBlogAnnotation* myAnnotation = (iCodeBlogAnnotation*)annotation;	if([myAnnotation annotationType] == iCodeBlogAnnotationTypeApple)	{		self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];		self.frame = CGRectMake(0, 0, kWidth, kHeight);		self.backgroundColor = [UIColor clearColor];		imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"AppleMarker.png"]];		imageView.frame = CGRectMake(kBorder, kBorder, kWidth - 2 * kBorder, kWidth - 2 * kBorder);		[self addSubview:imageView];	}	else if([myAnnotation annotationType] == iCodeBlogAnnotationTypeEDU)	{		self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];		self.frame = CGRectMake(0, 0, kWidth, kHeight);		self.backgroundColor = [UIColor clearColor];		imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SchoolMarker.png"]];		imageView.frame = CGRectMake(kBorder, kBorder, kWidth - 2 * kBorder, kWidth - 2 * kBorder);		[self addSubview:imageView];	}	else if([myAnnotation annotationType] == iCodeBlogAnnotationTypeTaco)	{		self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];		self.frame = CGRectMake(0, 0, kWidth, kHeight);		self.backgroundColor = [UIColor clearColor];		imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"TacosMarker.png"]];		imageView.frame = CGRectMake(kBorder, kBorder, kWidth - 2 * kBorder, kWidth - 2 * kBorder);		[self addSubview:imageView];	}	[imageView setContentMode:UIViewContentModeScaleAspectFill];	return self;}@end

Introduction to MapKit on iPhone OS 3.031

Introduction to MapKit on iPhone OS 3.032

iCodeBlogMapViewController.m

-(void)loadOurAnnotations{	CLLocationCoordinate2D workingCoordinate;	workingCoordinate.latitude = 40.763856;	workingCoordinate.longitude = -73.973034;	iCodeBlogAnnotation *appleStore1 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[appleStore1 setTitle:@"Apple Store 5th Ave."];	[appleStore1 setSubtitle:@"Apple's Flagship Store"];	[appleStore1 setAnnotationType:iCodeBlogAnnotationTypeApple];	[mapView addAnnotation:appleStore1];	workingCoordinate.latitude = 51.514298;	workingCoordinate.longitude = -0.141949;	iCodeBlogAnnotation *appleStore2 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[appleStore2 setTitle:@"Apple Store St. Regent"];	[appleStore2 setSubtitle:@"London England"];	[appleStore2 setAnnotationType:iCodeBlogAnnotationTypeApple];	[mapView addAnnotation:appleStore2];	workingCoordinate.latitude = 35.672284;	workingCoordinate.longitude = 139.765702;	iCodeBlogAnnotation *appleStore3 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[appleStore3 setTitle:@"Apple Store Giza"];	[appleStore3 setSubtitle:@"Tokyo, Japan"];	[appleStore3 setAnnotationType:iCodeBlogAnnotationTypeApple];	[mapView addAnnotation:appleStore3];	workingCoordinate.latitude = 37.331741;	workingCoordinate.longitude = -122.030564;	iCodeBlogAnnotation *appleStore4 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[appleStore4 setTitle:@"Apple Headquarters"];	[appleStore4 setSubtitle:@"The Mothership"];	[appleStore4 setAnnotationType:iCodeBlogAnnotationTypeApple];	[mapView addAnnotation:appleStore4];	workingCoordinate.latitude = 41.894518;	workingCoordinate.longitude = -87.624005;	iCodeBlogAnnotation *appleStore5 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[appleStore5 setTitle:@"Apple Store Michigan Ave."];	[appleStore5 setSubtitle:@"Chicago, IL"];	[appleStore5 setAnnotationType:iCodeBlogAnnotationTypeApple];	[mapView addAnnotation:appleStore5];	workingCoordinate.latitude = 32.264977;	workingCoordinate.longitude = -110.944011;	iCodeBlogAnnotation *tacoShop1 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[tacoShop1 setTitle:@"Nico's Taco Shop"];	[tacoShop1 setSubtitle:@"Tucson, AZ"];	[tacoShop1 setAnnotationType:iCodeBlogAnnotationTypeTaco];	[mapView addAnnotation:tacoShop1];	workingCoordinate.latitude = 32.743242;	workingCoordinate.longitude = -117.181451;	iCodeBlogAnnotation *tacoShop2 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[tacoShop2 setTitle:@"Lucha Libre Gourmet"];	[tacoShop2 setSubtitle:@"San Diego, CA"];	[tacoShop2 setAnnotationType:iCodeBlogAnnotationTypeTaco];	[mapView addAnnotation:tacoShop2];	workingCoordinate.latitude = 32.594987;	workingCoordinate.longitude = -117.060936;	iCodeBlogAnnotation *tacoShop3 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[tacoShop3 setTitle:@"El Ranchero Taco Shop"];	[tacoShop3 setSubtitle:@"Rocky Pointe, Mexico"];	[tacoShop3 setAnnotationType:iCodeBlogAnnotationTypeTaco];	[mapView addAnnotation:tacoShop3];	workingCoordinate.latitude = -34.594859;	workingCoordinate.longitude = -58.384336;	iCodeBlogAnnotation *tacoShop4 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[tacoShop4 setTitle:@"Taco Tequila Sangria S.A."];	[tacoShop4 setSubtitle:@"Buneos Aires, Argentina"];	[tacoShop4 setAnnotationType:iCodeBlogAnnotationTypeTaco];	[mapView addAnnotation:tacoShop4];	workingCoordinate.latitude = 38.240550;	workingCoordinate.longitude = -0.526509;	iCodeBlogAnnotation *tacoShop5 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[tacoShop5 setTitle:@"Albertsma Taco"];	[tacoShop5 setSubtitle:@"Gran Alacant, Spain"];	[tacoShop5 setAnnotationType:iCodeBlogAnnotationTypeTaco];	[mapView addAnnotation:tacoShop5];		workingCoordinate.latitude = 33.419490;	workingCoordinate.longitude = -111.930563;	iCodeBlogAnnotation *school1 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[school1 setTitle:@"Arizona State University"];	[school1 setSubtitle:@"Go Sun Devils"];	[school1 setAnnotationType:iCodeBlogAnnotationTypeEDU];	[mapView addAnnotation:school1];	workingCoordinate.latitude = 35.087537;	workingCoordinate.longitude = -106.618184;	iCodeBlogAnnotation *school2 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[school2 setTitle:@"University of New Mexico"];	[school2 setSubtitle:@"Go Lobos"];	[school2 setAnnotationType:iCodeBlogAnnotationTypeEDU];	[mapView addAnnotation:school2];	workingCoordinate.latitude = 40.730838;	workingCoordinate.longitude = -73.997498;	iCodeBlogAnnotation *school3 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[school3 setTitle:@"New York University"];	[school3 setSubtitle:@"New York, NY"];	[school3 setAnnotationType:iCodeBlogAnnotationTypeEDU];	[mapView addAnnotation:school3];	workingCoordinate.latitude = 51.753523;	workingCoordinate.longitude = -1.253171;	iCodeBlogAnnotation *school4 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[school4 setTitle:@"Oxford University"];	[school4 setSubtitle:@"Oxford, England"];	[school4 setAnnotationType:iCodeBlogAnnotationTypeEDU];	[mapView addAnnotation:school4];	workingCoordinate.latitude = 22.131982;	workingCoordinate.longitude = 82.142302;	iCodeBlogAnnotation *school5 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];	[school5 setTitle:@"India Institute of Technology"];	[school5 setSubtitle:@"Delhi, India"];	[school5 setAnnotationType:iCodeBlogAnnotationTypeEDU];	[mapView addAnnotation:school5];}

Introduction to MapKit on iPhone OS 3.033

iCodeblogMapViewController.m

- (iCodeBlogAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation{	iCodeBlogAnnotationView *annotationView = nil;	// determine the type of annotation, and produce the correct type of annotation view for it.	iCodeBlogAnnotation* myAnnotation = (iCodeBlogAnnotation *)annotation;	if(myAnnotation.annotationType == iCodeBlogAnnotationTypeApple)	{		NSString* identifier = @"Apple";		iCodeBlogAnnotationView *newAnnotationView = (iCodeBlogAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];		if(nil == newAnnotationView)		{			newAnnotationView = [[[iCodeBlogAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];		}		annotationView = newAnnotationView;	}	else if(myAnnotation.annotationType == iCodeBlogAnnotationTypeEDU)	{		NSString* identifier = @"School";		iCodeBlogAnnotationView *newAnnotationView = (iCodeBlogAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];		if(nil == newAnnotationView)		{			newAnnotationView = [[[iCodeBlogAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];		}		annotationView = newAnnotationView;	}	else if(myAnnotation.annotationType == iCodeBlogAnnotationTypeTaco)	{		NSString* identifier = @"Taco";		iCodeBlogAnnotationView *newAnnotationView = (iCodeBlogAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];		if(nil == newAnnotationView)		{			newAnnotationView = [[[iCodeBlogAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];		}		annotationView = newAnnotationView;	}	[annotationView setEnabled:YES];	[annotationView setCanShowCallout:YES];	return annotationView;}

Introduction to MapKit on iPhone OS 3.034

Introduction to MapKit on iPhone OS 3.035

iCodeBlogMapViewController.m

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return 3;}

Introduction to MapKit on iPhone OS 3.036

iCodeBlogMapViewController.m

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{	if(section == iCodeBlogAnnotationTypeApple)	{		return @"Apple Markers";	}	else if(section == iCodeBlogAnnotationTypeEDU)	{		return @"Schools";	}	else if(section == iCodeBlogAnnotationTypeTaco)	{		return @"Taco Shops";	}	return nil;}

Introduction to MapKit on iPhone OS 3.037

iCodeBlogMapViewController.m

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{	return 5;}

Introduction to MapKit on iPhone OS 3.038

Introduction to MapKit on iPhone OS 3.039

iCodeBlogMapViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    static NSString *CellIdentifier = @"Cell";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];	if (cell == nil)	{        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];    }	NSMutableArray *annotations = [[NSMutableArray alloc] init];	if(indexPath.section == 0)	{		for(iCodeBlogAnnotation *annotation in [mapView annotations])		{			if([annotation annotationType] == iCodeBlogAnnotationTypeApple)			{				[annotations addObject:annotation];			}		}		cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];	}	else if(indexPath.section == 1)	{		for(iCodeBlogAnnotation *annotation in [mapView annotations])		{			if([annotation annotationType] == iCodeBlogAnnotationTypeEDU)			{				[annotations addObject:annotation];			}		}				cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];	}	else if(indexPath.section == 2)	{		for(iCodeBlogAnnotation *annotation in [mapView annotations])		{			if([annotation annotationType] == iCodeBlogAnnotationTypeTaco)			{				[annotations addObject:annotation];			}		}		cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];	}    return cell;}

Introduction to MapKit on iPhone OS 3.040

Introduction to MapKit on iPhone OS 3.041

iCodeBlogMapViewController.m

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{	for(iCodeBlogAnnotation *annotation in [mapView annotations])	{		if([[[[tableView cellForRowAtIndexPath:indexPath] textLabel] text] isEqualToString:[annotation title]])		{			[mapView setRegion:MKCoordinateRegionMake([annotation coordinate], MKCoordinateSpanMake(.01, .01)) animated:YES];		}	}}

http://ydongyol.springnote.com/pages/472

http://ydongyol.springnote.com/pages/472

http://ydongyol.springnote.com/pages/472

안드로이드 2.0 설치

다운로드

http://java.sun.com/javase/downloads/widget/jdk6.jsp

http://developer.android.com/sdk/download.html?v=android-sdk_r3-windows.zip

http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/galileo/SR1/eclipse-java-galileo-SR1-win32.zip

java jdk 6.0 install

SDK Setup.exe 실행

C:\Documents and Settings\401-4\.android\androidtool.cfg 생성

sdkman.force.http=true

androidtool.cfg

ADaAM.PNG

eclipse 설정

adt plug in 설치

eclipse- help - install new software

add -> available software sites

add

name: Android

Location https://dl-ssl.google.com/android/eclipse

ok

work with --> android

android DDMS , android deverl...tools

Android SDK Setting

windows-Preferences

Android

SDK location : c:\android\android-sdk

applay - ok

run android emulator

Windows - Android SDK and AVD manager

new

name : android_2.0

target : Android 2.0 API

소프트웨어기술경력증이라....

내가 형사 콜롬보도 아니고

거처온 유령회사 사장들을 찾아다야만 해서 포기한 경력이 6년이라는....

그나마 이거라도 건진다는 느낌...

일부 기업들은 고급이상은 쓰지 않겠다는 방침도 있기에 안심?????

이것들이 머라는....



'Computer Science' 카테고리의 다른 글

Introduction to MapKit in iPhone OS 3.0  (0) 2009.12.25
안드로이드 2.0 설치  (0) 2009.12.25
데이터베이스 정규화  (0) 2009.11.07
GTK+ 프로그래밍 기초 자료2  (0) 2009.11.01
GTK+ 프로그래밍 기초 자료  (0) 2009.11.01

서적 "SQL 기초2" 주에서 발최

CHAPTER 3. 주위의 데이터를 테이블로 만든다


3-1. 테이블 설계란 무엇인가?


KEYWORD

* 데이터 정규화

* 비정규화 데이터

* 제1정규화

* 제2정규화

* 제3정규화


테이블 설계란 우리들 주변에 있는 데이터를 어떠한 형식으로 데이터베이스로 보관하면 좋을까를 생각하는 것입니다. 이 설계가 잘 되고 안 됨에 따라, 나중에 데이터의 수정이 간단하게 될지, 복잡하게 될지가 결정됩니다. ‘이렇게 설계를 하면 나중에 수정할 때 이러한 장점이나 단점이 있다’라는 점을 잘 생각하면서 배워 나가도록 합시다.

테이블 설계를 할 때에는 정규화라는 개념을 알아두어야 합니다. 어렵게 생각할 필요는 없습니다. 우리들 자신이 가지고 있는 데이터를 데이터베이스로 원활하게 운용할 수 있도록 잘게 부수는 것이라고 생각하면 됩니다. 여기에서는 신문을 예로 들어 봅니다. 기사를 쓰는 쪽(기자)를 인간으로, 기사를 읽는 쪽(독자)를 데이터베이스로 바꾸어 생각해 봅니다.

신문의 1페이지 전면이 모두 한자로 쓰여 있다고 상상해 봅니다. 전달하고자 하는 것들을 모두 적었다 하더라도, ‘독자로서는 이해하기 어려운 것’이 자명합니다. 좀 더 알기 쉽게 하려면 한글을 섞어서 쓰도록 합니다. 또 더욱 효과적인 방법으로는 문장 부호를 추가하거나 지면을 여러 틀로 나누어서 각각의 틀 안에 기사를 쓰면 좋을 것입니다. 단락을 나누어서 쓰는 것도 이해하기 쉬워질 것입니다. 이렇게 하면 지면 전체를 한자로 쓴 것에 비하여 훨씬 알기쉬운 신문이 될 것입니다.

이와 같이 인간과 데이터베이스 사이에서 진행해 나가는 것을 정규화라고 부릅니다. 앞의 예에서는 ‘전면을 한자로 쓴다’ → ‘한글을 섞어 쓴다’ → ‘문장 부호를 추가한다’ → ‘지면을 분할한다’ → ‘단락을 나눈다’라는 형태로 한자 데이터를 편집해 나감으로써 좀 더 이해하기 쉬운 데이터 구조로 만드는 방법을 설명하였습니다. 이 내용을 인간이 취급하는 데이터와 데이터베이스의 관계에도 적용시켜 봅니다. 인간이 취급하는 데이터를 ‘비정규화 데이터’라고 부릅니다. 여기에서부터 진행하는 테이블 설계의 절차는 다음과 같습니다.


비정규화 데이터 → 제1정규화 → 제2정규화 → 제3정규화

실제로는 제4정규화, 제5정규화 등도 있지만 일반적으로는 제3정규화까지 진행합니다. 신문의 예에서는, ‘한글을 섞어서 쓰고 문장 부호가 있으면 이해하기 쉽다’라는 것이 제3정규화입니다. 이처럼 사람들이 이해하기 쉬운 데이터 구조를 RDBMS가 이해하기 쉬운(관리하기 쉬운) 구조로 바꾸어 나가기 위해서 정규화가 필요합니다. 각각의 정규형에 관해서 살펴보도록 합니다.



3-2 테이블 작성 방법과 비정규형


KEYWORD

* 분석

* 비정규형


다음의 예로 테이블을 작성해 봅니다. 여기에서는 학교 성적 관리에 관해서 생각해 보기로 합니다. 다음과 같은 시험 성적표가 있습니다.


시험 성적표

이름 : 최문석

학년 : 2

반 : A

교실 : 본관2층

== 시험 결과 ==

과목 점수 교사

국어 80 이경욱

수학 70 최용호

물리 92 배정훈

사회 48 조범식

과목수 : 4

평균점수 : 72.5



이처럼 개인 정보를 데이터베이스를 사용하여 관리한다고 가정합니다.

전교생의 시험 성적표를 각 교사가 기록하고 이것을 학교 컴퓨터에 입력합니다. 물론 이 성적표를 바로 테이블로 만들 수도 있으나, 데이터베이스에는 바람직한 방법이 아닙니다. 어떠한 형식이 적합할지를 생각해 봅니다. 테이블을 설계하기 전에 시트를 잘 관찰하여 테이블 구조를 확정해야 하는데 이 작업을 분석이라고 부릅니다. 데이터의 분석 방법은 여러 가지가 있겠지만 여기에서는 이에 관해서는 언급을 하지 않습니다. 그러나 어떠한 분석 방법을 사용하든지, 테이블 설계의 첫 걸음은 어떠한 열이 있으면 이것에 데이터를 관리할 수 있을까를 고려하는 것입니다. 위의 표를 보고 어떠한 열이 있으면 좋을까를 생각해 봅니다. 표를 보면 다음과 같이 데이터를 분석할 수 있습니다.


시험 성적표 → 테이블 이름

최문석 → 이름

2 → 학년

A → 학급

본관2층 → 교실

== 시험 결과 == → 테이블 구분

국어 → 과목

80 → 점수

이경욱 → 교사

4 → 과목수

72.5 → 평균점수


이 정보들을 자세히 보길 바랍니다. 동시에 테이블을 머리 속에 그려 봅니다. 어떠한 열이 필요할까요? 이것을 테이블로 만든다고 생각할 때 다음과 같은 열이 필요합니다.



1. 테이블 이름

2. 이름

3. 학급

4. 교실

5. 테이블 구분

6. 과목

7. 점수

8. 교사

9. 과목수

10. 평균점수


이들 열을 사용하여, 바로 CREATE TABLE문을 사용해도 되지만, 여기에서 다시 한번 생각해 봅니다. 위에 들고 있는 열 후보 중에서 필요 없는 열은 없을까요?

먼저 눈에 띄는 것은 ‘1. 테이블 이름’과 ‘5. 테이블 구분’입니다. 이 항목은 인쇄상 보기 편하기 하기 위한 것이므로 데이터로는 아무 의미가 없습니다.

그리고 잘 생각해 보면, 필요 없는 열이 또 있습니다. 다른 값에 의해 계산할 수 있는 항목입니다. SELECT문이 계산이 가능하다는 것은 이미 아는 사실입니다. (예: SELECT 1+2 FROM DUAL;) 그렇기 때문에 계산에 의해 산출할 수 있는 것은 굳이 데이터로 입력할 필요가 없습니다. 오히려 같은 데이터를 여러 개 갖게 되므로 데이터가 중복됩니다. 예를 들어, 과목수는 과목을 세어보면 알 수 있고 평균 점수는 각 점수를 더해서 과목수로 나누면 됩니다. 이처럼 계산할 수 있는 데이터는 필요없는 데이터입니다. RDBMS 설계에서 중요한 것은 중복 데이터를 가지지 않고 데이터의 모순 없이 쉽게 변경하는 것입니다. 따라서, 다른 데이터에서 계산하여 얻을 수 있는 값은 테이블 설계 단계에서 제외합니다. 여기에서는 ‘9.과목수’와 ‘10.평균점수’가 해당됩니다. 이러한 관점에서 필요한 열을 다시 추려 보면 다음과 같습니다.


1. 이름

2. 학급

3. 교실

4. 과목

5. 점수

6. 교사



열이 반 정도로 줄었습니다. 그러나 결코 정보가 빠져 있지는 않습니다. 이들 데이터 정도만 알면 본래의 표 데이터는 복원될 수 있습니다. 테이블 설계에서 중요한 것은 반드시 테이블에 보관해야 하는 데이터와 다른 데이터에서 도출 할 수 있는 데이터를 가려내는 것입니다. 표에 씌여 있는 데이터는 하나의 표현에 지나지 않으므로, 그대로 모두 테이블로 가져오면 안 된다는 점을 주의하길 바랍니다.

그러면 이제 가려낸 열을 사용하여 다음과 같은 테이블을 작성해 봅니다.



이름

학급

교실

과목

점수

교사

최문석

A

본관2층

국어

80

이경욱

수학

70

최용호

물리

92

배정훈

사회

48

조범식


한 명의 학생에 대한 정보는 이 정도입니다. 다른 학생의 정보도 입력해 봅니다.


? 테이블1: 성적(비정규형)

이름

학급

교실

과목

점수

교사

최문석

A

본관2층

국어

80

이경욱

수학

70

최용호

물리

92

배정훈

사회

48

조범식

이원석

B

별관3층

국어

80

이경욱

수학

55

최용호

가정

96

도희정

문장원

B

본관3층

예술

72

이수정

사회

87

조범식



이렇게 작성된 테이블을 비정규형 테이블이라고 부릅니다. 비정규형 테이블은 인간에게는 보기 편하지만 효율성 있는 데이터 관리를 위해서는 적합하지 않습니다. 예를 들어 2번째 행의 데이터는 어느 학생의 성적인가를 보여주지 않습니다. 그리고 앞서 테이블에는 키 열이 존재한다고 설명한 것을 기억할 것입니다. 키 열에는 반드시 값이 있어야 합니다. 앞의 테이블은 학생의 성적을 보관하는 테이블이므로 어느 한 행을 특정 짓기 위해서는 학생 이름이 필요합니다. 그러나 학생 이름 열에 값이 들어가 있지 않는 행이 여러 개 존재하고 있습니다. 이런 이유로 이 테이블을 이대로는 RDBMS 안의 테이블에 보관 할 수 없습니다. 여기서 비정규형 테이블을 제1정규형으로 변환해 봅니다.



3-3 제1정규형


KEYWORD

* 제1정규형


제1정규형으로 변환하는 작업은 테이블 안에서 반복되는 항목을 배재하는 것입니다. 따라서 테이블 안에 반복되는 항목이 없는 테이블을 제1정규형 테이블이라고 합니다.

그러면 비정규형 테이블을 제1정규형 테이블로 변환해 봅니다. ‘테이블1’에서 반복하는 항목은 무엇인가? ‘테이블1’의 2행, 3행과 4행에는 아무것도 입력되어 있지 않지만 실제로는 1행의 데이터와 같은 것이 들어 있다고 할 수 있습니다. 즉, ‘이름’열에서 ‘교실’열까지는 반복이 존재하는 열입니다.

테이블1은 아래와 같이 표현되기도 합니다.


이름

학급

교실

과목

점수

교사

최문석

A

본관2층

국어

80

이경욱

최문석

A

본관2층

수학

70

최용호

최문석

A

본관2층

물리

92

배정훈

최문석

A

본관2층

사회

48

조범식

이원석

B

별관3층

국어

80

이경욱

이원석

B

별관3층

수학

55

최용호

이원석

B

별관3층

가정

96

도희정

문장원

B

본관3층

예술

72

이수정

문장원

B

본관3층

사회

87

조범식


그러나 너무 복잡해 보기가 어려우므로 일반적으로 반복되는 항목을 생략하고 ‘테이블1’과 같이 만듭니다.

이러한 이유로 ‘테이블1’에서 반복되는 항목은 ‘이름’열에서 ‘교실’열까지라는 것을 알 수 있습니다. 지금부터 ‘테이블1’을 제1정규형으로 분해해 나가겠습니다. 이때에 주의해야 할 것이 있습니다. 그것은 분해한 2개의 테이블에서 원래의 테이블을 반드시 복원할 수 있도록 분해해야 한다는 것입니다. 기계를 분해한 후 다시 조립을 못하면 큰일나듯이 테이블도 마찬가지로 분해한 테이블을 반드시 원래의 테이블로 복원할 수 있어야 합니다.

그러면 어떻게 해야 할까요? 테이블을 분해할 때는 약간의 고려를 해 볼 필요가 있습니다. 실제로 고려해야 하는 것은 어느 열의 값이 있으면, 어느 행을 구분 지을 수 있을까라는 점입니다. 테이블1에서는 ‘이름’열과 ‘과목’열이 해당됩니다. 이 2개의 열이 있으면 특정 행을 식별 할 수 있습니다.

다음과 같이 비정규형 테이블을 2개로 나우어 봅니다.



학생(이름, 학급, 교실)

시험(이름, 과목, 점수, 교사)


여기서 밑줄이 그어져 있는 열은 키 열로 그 항목이 결정되면 행이 구분지어진다는 것을 나타냅니다. 방금 ‘테이블1’을 2개의 테이블로 분할하였습니다. 그럼, 상세하게 보기로 합니다.

먼저, ‘테이블2’입니다. ‘이름’이 키로 되어 있어 이름이 구분됨에 따라 특정한 1행을 식별할 수 있습니다.


? 테이블2: 학생

이름

학급

교실

최문석

A

본관2층

이원석

B

별관3층

문장원

B

별관3층



또 하나는 ‘테이블3’입니다. 밑줄로 나타낸 것처럼 이 테이블은 ‘이름’열과 ‘과목’열의 값을 한 조로 하여 하나의 행을 식별할 수 있습니다.

다시 말해, ‘테이블1’을 단지 2개로 나누는 것이 아니라 분해한 것에 키 열을 추가한 후 다시 하나의 테이블로 만드는 것입니다.


? 테이블3: 시험

이름

과목

점수

교사

최문석

국어

80

이경욱

최문석

수학

70

최용호

최문석

물리

92

배정훈

최문석

사회

48

조범식

이원석

국어

80

이경욱

이원석

수학

55

최용호

이원석

가정

96

도희정

문장원

예술

72

이수정

문장원

사회

87

조범식


테이블2와 테이블3을 주의해서 보시길 바랍니다. 양쪽 테이블에 포함되어 있는 열은 ‘이름’열입니다. 이 열이 양쪽에 있기 때문에 ‘테이블2’와 ‘테이블3’에서 ‘테이블1’이 복원될 수 있습니다(이것은 RDBMS의 기본!).

이렇게 제1정규형으로 변환되었습니다.






3-4 제2정규형


KEYWORD

* 제2정규형


제2정규형이란 연결 키가 있는 테이블을 찾아내어 연결 키의 일부 열에만 존재하고 있는 열을 도출하는 것을 말합니다. 연결 키가 없는(하나의 열만으로 기본 키를 만들고 있는) 테이블은 대상에서 제외됩니다.


앞의 ‘테이블2’는 기본 키가 하나인 ‘이름’열만으로 구성되어 있으므로 이미 제2정규형의 조건을 만족하고 있습니다. 그렇기 때문에 ‘테이블2’를 제2정규형으로 바꿔줄 필요가 없습니다.

연결 키의 일부 열에만 존재하고 있는 열이란 어떤 것일까요? 예를 들어, 다음의 ‘소프트 아이스크림’테이블을 살펴봅니다.


? 소프트 아이스크림

용기

주원료

가격

딸기맛

딸기

2,000

딸기맛

딸기

2,500

메론맛

메론

4,000

메론맛

메론

4,500

초콜릿맛

초콜릿

1,000

초콜릿맛

초콜릿

1,500

바나나맛

바나나

1,000

바나나맛

바나나

1,500


‘소프트 아이스크림’ 테이블은 연결 키를 가지고 있어서 용기와 맛이 결정되면 특정행이 도출되는 테이블입니다. 이 테이블을 잘 보면 ‘주원료’열의 값(딸기, 메론, 초콜릿, 바나나)은‘맛’ 열의 값(딸기맛, 메론맛, 초콜릿맛, 바나나맛)에는 존재하고, ‘용기’ 열 (컵, 콘)에는 존재하지 않습니다.

다시 말해, 연결 키를 구성하는 열(맛, 용기)의 일부인 열(맛)에만 존재하는 열(주원료)을 도출해내는 작업이 제2정규화입니다.

‘가격’열은 연결 키를 구성하는 열(맛,용기) 모두에 존재하므로 도출하려는 열의 대상이 되지 않습니다. 그렇기 때문에 제2정규화로 도출하려는 열은 ‘소프트 아이스크림’ 테이블 열에서 ‘주원료’열이 됩니다.

그러면 ‘테이블3’을 살펴봅니다. ‘테이블3’은 연결 키(‘이름’ 열, ‘과목’ 열)를 가지고 있는 테이블이므로 제2정규형으로 변형할 필요가 있는지를 음미할 대상이 됩니다.

‘점수’ 열은 무엇에 의해 구분되는가를 생각해 보면, ‘이름’열과 ‘과목’열이라는 것을 알 수 있습니다. 즉, ‘점수’열은 ‘학생’열과 ‘과목’열의 양쪽(연결 키의 전체 열)에 종속되어 있으므로 어떠한 작업도 할 필요가 없습니다.

다음로 ‘교사’열을 생각해 봅니다. 교사가 어디에 종속되어 있는지 생각해 볼 때 과목이 결정되면 대응하는 교사가 자동으로 결정된다는 것을 알 수 있습니다. 학생이 누구인지에는 관계없습니다. 곧 ‘교사’열의 값은 ‘과목’열의 값(연결 키의 일부 열)에만 종속되어 있으므로 분해할 필요가 있다는 것을 알 수 있습니다. 다음고 같이 분해해 봅니다.



? 테이블4: 시험2

이름

과목

점수

최문석

국어

80

최문석

수학

70

최문석

물리

92

최문석

사회

48

이원석

국어

80

이원석

수학

55

이원석

가정

96

문장원

예술

72

문장원

사회

87


‘점수’열은 그대로 남김니다.


? 테이블5: 교사

과목

교사

국어

이경욱

수학

최용호

물리

배정훈

사회

조범식

가정

도희정

예술

이수정


이와 같이, 교사는 과목이 결정되면 자동으로 구분됩니다. ‘테이블4’와 ‘테이블5’를 잘 살펴봅니다. ‘과목’열이 양쪽 테이블에 들어 있으므로 ‘테이블4’와 ‘테이블5’에서 ‘테이블3’을 복원할 수 있습니다.















3-5 제3정규형


KEYWORD

* 제3정규형


제3정규형은 기본 키 항목 이외의 열에 종속되어 있는 열을 도출하는 것입니다. 즉, 기본 키 열 이외의 열에 종속되어 있는 열이 없는 테이블입니다.

‘테이블4’의 ‘점수’열을 봅니다. ‘점수’열은 기본 키 열(‘이름’열, ‘과목’열)에 종속(기본 키 열이 결정되면 자동으로 결정됩니다)되므로 이미 제3정규형이 되어 있습니다. 다음으로 ‘테이블5’를 봅니다. 기본 키 이외의 열은 ‘교사’열입니다. 그러나 ‘교사’열은 기본 키 열(과목)에 종속되므로 ‘테이블5’도 이미 제3정규형이 되어 있습니다.

앞의 ‘테이블2’를 다시 살펴봅시다.


? 테이블2: 학생

이름

학급

교실

최문석

A

본관2층

이원석

B

별관3층

문장원

B

별관3층



‘학급’열을 보면, ‘학급’열의 값은 기본 키 열(이름)이 결정됩니다. 그럼 ‘교실’ 열은 어떤가요? ‘교실’열은 학급이 결정되면 자동으로 결정됩니다. 즉, 기본 키 이외의 열에 종속되어 있다는 것을 알 수 있습니다. ‘테이블2’를 제3정규형으로 분해해 보면 아래와 같이 됩니다.


? 테이블6: 학생

이름

학급

최문석

A

이원석

B

문장원

B


? 테이블7: 위치

학급

교실

A

본관2층

B

별관3층


이렇게 해서, 기본 키가 아닌 모든 열은 기본 키에만 종속된 형이 되어 제3정규형이 되었습니다. ‘테이블6’, ‘테이블7’은 양쪽에 ‘학급’열이 들어 있으므로 이 2개의 테이블에서 ‘테이블2’를 복원할 수 있습니다.


‘테이블6’, ‘테이블7’은 다음과 같이 될 수도 있습니다.

이름

교실

최문석

본관2층

이원석

별관3층

문장원

별관3층


교실

학급

본관2층

A

별관3층

B



상호 어느 쪽에도 속해있다고 말할 수 없을 때는 어느 것이든 분해할 수 있습니다.

그럼 지금까지의 분해를 정리해 봅시다.



비정규형

제1정규형

제2정규형

제3정규형

‘성적’테이블

‘학생’테이블

‘학급’테이블

‘위치’테이블

‘시험’테이블

‘시험2’테이블

‘교사’테이블



처음으로 비정규형 테이블을 2개로 분해해 보았습니다. 위의 그림은 ‘학생’테이블의 분해와 동시에 제2정규형 조건을 충족하는 테이블이 되었다는 것을 나타냅니다. ‘시험’테이블은 제1정규형이므로, 제2정규형 분해를 진행하여 ‘시험2’테이블과 ‘교사’테이블로 분해했다는 것을 보여줍니다. ‘시험2’테이블과 ‘교사’테이블은 제2정규형으로 분해됨과 동시에 제3정규형의 조건을 충족하는 테이블이 되었다는 것을 알 수 있습니다.

다음은 4개의 테이블 정의를 정리해 본 것입니다.


시험2(이름, 과목, 점수)

교사(과목, 교사)

학급(이름, 학급)

위치(학급, 교실)


이들의 테이블 관계를 도식으로 표현하면, 아래와 같습니다.



















여기에서 CREATE TABLE문을 작성하면 다음과 같습니다.

CREATE TABLE 시험2

(

이름 VARCHAR2(20) CONSTRAINT PK_NAME PRIMARY KEY,

과목 VARCHAR2(20) CONSTRAINT FK_CLASS REFERENCES 학급(이름),

점수 NUMBER(3) CONSTRAINT NN_POINT NOT NULL

);

CREATE TABLE 학급

(

이름 VARCHAR2(20) CONSTRAINT PK_CLASS PRIMARY KEY,

학급 VARCHAR2(2) CONSTRAINT FK_SITE REFERENCES 위치(학급)

);

CREATE TABLE 위치

(

학급 VARCHAR2(24) CONSTRAINT PK_NAME PRIMARY KEY,

교실 VARCHAR2(100)

);

CREATE TABLE 교사

(

과목 VARCHAR2(20) CONSTRAINT PK_COURSE PRIMARY KEY

교사 VARCHAR2(20)

);



단, 이들 정의는 예제일 뿐이므로 실제로는 애플리케이션에 맞추어 적용하면 됩니다. 애플리케이션의 예로 NOT NULL 제약을 엄밀하게 설정하고, 문자열에 기본 키를 붙이지 않고, 테이블에 'ID'열을 추가하고 테이터에 관리용 ID(학생 번호, 학급 번호, 직원 번호 등)를 부여해 이것을 기본 키 또는 참조 키로 할 수 있습니다.

이렇게 ‘성적’테이블을 4개의 제3정규형 테이블로 분해할 수 있습니다. 그리고 이들 4개의 테이블을 조합하면, ‘성적’테이블로 복원 할 수 있습니다. 이처럼 기본 키 열과 기본 키에만 종속되어 있는 열로만 구성되어 있는 테이블로 분해함으로써, 중복되는 데이터가 없는 효율적인 테이블을 완성할 수 있습니다.

이렇게 테이블의 CREATE TABLE문은 여러 가지로 생각할 수 있습니다. 우리 주위에 있는 데이터를 분석하고 비정규형으로 정리하여 정규화를 진행시키고 CREATE TABLE문을 작성할 수 있을 때까지 위 과정들을 체험합니다.


앞서 말했듯이 제4정규형, 제5정규형 등 좀 더 정밀한 정규형이 있으나, 일반적으로 제3정규형까지 정규형화하면 충분하다고 할 수 있습니다. 그리고 경우에 따라서 시스템의 효율성을 고려하여 제3정규형을 없애고 일부러 제2정규형으로 돌아가기도 합니다.

좀더 자세한 내용은 다른 책을 참조하도록 하고, 여기서는 다음 내용을 기억하기를 바랍니다.


1. 우리들 주변에 있는 데이터는 비정규형인 것이 많으므로 바로 테이블화 해서는 안 된다.

2. 꼭 보관할 필요가 있는 데이터가 무엇인지를 생각한다(계산으로 나오는 값은 열로 만들지 않는다 등).

3. 열 상호간의 종속 관계를 충분히 고려한다.

4. 정규형의 조건에 따라서 차근차근 데이터를 제3정규형으로 분해해 나간다.

5. 분해할 때에는 원래의 테이블을 복원할 수 있는지를 고려한다.

6. CREATE TABLE문을 생각할 때에 새로운 열(ID열)을 도입하면 설계가 편하고 보기좋게 될 수 있다.


그리고 각각의 정규화는 다음과 같은 관계에 놓여 있습니다. 제3정규형은 제2정규형 조건을 충족하고, 제2정규형은 제1정규형 조건을 충족합니다. 테이블 설계나 작성시에 이들의 관계를 잘 이해하도록 합니다.


GTK+ 프로그래밍 기초 자료2

1257069526_lf-2004_03-0332.pdf

GTK+ 프로그래밍 기초 자료

1257069392_gtk.pdf

[출처] http://ccnga.uwaterloo.ca/~jscouria/GSM/gsmreport.html

Overview of the Global System for Mobile Communications

John Scourias
jscouria@www.shoshin.uwaterloo.ca


Table of Contents

1. History of GSM
2. Services provided by GSM
3. Architecture of the GSM network

4. Radio link aspects

5. Network aspects

6. Conclusion and comments


History of GSM

During the early 1980s, analog cellular telephone systems were experiencing rapid growth in Europe, particularly in Scandinavia and the United Kingdom, but also in France and Germany. Each country developed its own system, which was incompatible with everyone else's in equipment and operation. This was an undesirable situation, because not only was the mobile equipment limited to operation within national boundaries, which in a unified Europe were increasingly unimportant, but there was also a very limited market for each type of equipment, so economies of scale and the subsequent savings could not be realized.

The Europeans realized this early on, and in 1982 the Conference of European Posts and Telegraphs (CEPT) formed a study group called the Groupe Spécial Mobile (GSM) to study and develop a pan-European public land mobile system. The proposed system had to meet certain criteria:

  • Good subjective speech quality
  • Low terminal and service cost
  • Support for international roaming
  • Ability to support handheld terminals
  • Support for range of new services and facilities
  • Spectral efficiency
  • ISDN compatibility
In 1989, GSM responsibility was transferred to the European Telecommunication Standards Institute (ETSI), and phase I of the GSM specifications were published in 1990. Commercial service was started in mid-1991, and by 1993 there were 36 GSM networks in 22 countries [6]. Although standardized in Europe, GSM is not only a European standard. Over 200 GSM networks (including DCS1800 and PCS1900) are operational in 110 countries around the world. In the beginning of 1994, there were 1.3 million subscribers worldwide [18], which had grown to more than 55 million by October 1997. With North America making a delayed entry into the GSM field with a derivative of GSM called PCS1900, GSM systems exist on every continent, and the acronym GSM now aptly stands for Global System for Mobile communications.

The developers of GSM chose an unproven (at the time) digital system, as opposed to the then-standard analog cellular systems like AMPS in the United States and TACS in the United Kingdom. They had faith that advancements in compression algorithms and digital signal processors would allow the fulfillment of the original criteria and the continual improvement of the system in terms of quality and cost. The over 8000 pages of GSM recommendations try to allow flexibility and competitive innovation among suppliers, but provide enough standardization to guarantee proper interworking between the components of the system. This is done by providing functional and interface descriptions for each of the functional entities defined in the system.

Services provided by GSM

From the beginning, the planners of GSM wanted ISDN compatibility in terms of the services offered and the control signalling used. However, radio transmission limitations, in terms of bandwidth and cost, do not allow the standard ISDN B-channel bit rate of 64 kbps to be practically achieved.

Using the ITU-T definitions, telecommunication services can be divided into bearer services, teleservices, and supplementary services. The most basic teleservice supported by GSM is telephony. As with all other communications, speech is digitally encoded and transmitted through the GSM network as a digital stream. There is also an emergency service, where the nearest emergency-service provider is notified by dialing three digits (similar to 911).

A variety of data services is offered. GSM users can send and receive data, at rates up to 9600 bps, to users on POTS (Plain Old Telephone Service), ISDN, Packet Switched Public Data Networks, and Circuit Switched Public Data Networks using a variety of access methods and protocols, such as X.25 or X.32. Since GSM is a digital network, a modem is not required between the user and GSM network, although an audio modem is required inside the GSM network to interwork with POTS.

Other data services include Group 3 facsimile, as described in ITU-T recommendation T.30, which is supported by use of an appropriate fax adaptor. A unique feature of GSM, not found in older analog systems, is the Short Message Service (SMS). SMS is a bidirectional service for short alphanumeric (up to 160 bytes) messages. Messages are transported in a store-and-forward fashion. For point-to-point SMS, a message can be sent to another subscriber to the service, and an acknowledgement of receipt is provided to the sender. SMS can also be used in a cell-broadcast mode, for sending messages such as traffic updates or news updates. Messages can also be stored in the SIM card for later retrieval [2].

Supplementary services are provided on top of teleservices or bearer services. In the current (Phase I) specifications, they include several forms of call forward (such as call forwarding when the mobile subscriber is unreachable by the network), and call barring of outgoing or incoming calls, for example when roaming in another country. Many additional supplementary services will be provided in the Phase 2 specifications, such as caller identification, call waiting, multi-party conversations.

Architecture of the GSM network

A GSM network is composed of several functional entities, whose functions and interfaces are specified. Figure 1 shows the layout of a generic GSM network. The GSM network can be divided into three broad parts. The Mobile Station is carried by the subscriber. The Base Station Subsystem controls the radio link with the Mobile Station. The Network Subsystem, the main part of which is the Mobile services Switching Center (MSC), performs the switching of calls between the mobile users, and between mobile and fixed network users. The MSC also handles the mobility management operations. Not shown is the Operations and Maintenance Center, which oversees the proper operation and setup of the network. The Mobile Station and the Base Station Subsystem communicate across the Um interface, also known as the air interface or radio link. The Base Station Subsystem communicates with the Mobile services Switching Center across the A interface.

Figure 1. General architecture of a GSM network

Mobile Station

The mobile station (MS) consists of the mobile equipment (the terminal) and a smart card called the Subscriber Identity Module (SIM). The SIM provides personal mobility, so that the user can have access to subscribed services irrespective of a specific terminal. By inserting the SIM card into another GSM terminal, the user is able to receive calls at that terminal, make calls from that terminal, and receive other subscribed services.

The mobile equipment is uniquely identified by the International Mobile Equipment Identity (IMEI). The SIM card contains the International Mobile Subscriber Identity (IMSI) used to identify the subscriber to the system, a secret key for authentication, and other information. The IMEI and the IMSI are independent, thereby allowing personal mobility. The SIM card may be protected against unauthorized use by a password or personal identity number.

Base Station Subsystem

The Base Station Subsystem is composed of two parts, the Base Transceiver Station (BTS) and the Base Station Controller (BSC). These communicate across the standardized Abis interface, allowing (as in the rest of the system) operation between components made by different suppliers.

The Base Transceiver Station houses the radio tranceivers that define a cell and handles the radio-link protocols with the Mobile Station. In a large urban area, there will potentially be a large number of BTSs deployed, thus the requirements for a BTS are ruggedness, reliability, portability, and minimum cost.

The Base Station Controller manages the radio resources for one or more BTSs. It handles radio-channel setup, frequency hopping, and handovers, as described below. The BSC is the connection between the mobile station and the Mobile service Switching Center (MSC).

Network Subsystem

The central component of the Network Subsystem is the Mobile services Switching Center (MSC). It acts like a normal switching node of the PSTN or ISDN, and additionally provides all the functionality needed to handle a mobile subscriber, such as registration, authentication, location updating, handovers, and call routing to a roaming subscriber. These services are provided in conjuction with several functional entities, which together form the Network Subsystem. The MSC provides the connection to the fixed networks (such as the PSTN or ISDN). Signalling between functional entities in the Network Subsystem uses Signalling System Number 7 (SS7), used for trunk signalling in ISDN and widely used in current public networks.

The Home Location Register (HLR) and Visitor Location Register (VLR), together with the MSC, provide the call-routing and roaming capabilities of GSM. The HLR contains all the administrative information of each subscriber registered in the corresponding GSM network, along with the current location of the mobile. The location of the mobile is typically in the form of the signalling address of the VLR associated with the mobile station. The actual routing procedure will be described later. There is logically one HLR per GSM network, although it may be implemented as a distributed database.

The Visitor Location Register (VLR) contains selected administrative information from the HLR, necessary for call control and provision of the subscribed services, for each mobile currently located in the geographical area controlled by the VLR. Although each functional entity can be implemented as an independent unit, all manufacturers of switching equipment to date implement the VLR together with the MSC, so that the geographical area controlled by the MSC corresponds to that controlled by the VLR, thus simplifying the signalling required. Note that the MSC contains no information about particular mobile stations --- this information is stored in the location registers.

The other two registers are used for authentication and security purposes. The Equipment Identity Register (EIR) is a database that contains a list of all valid mobile equipment on the network, where each mobile station is identified by its International Mobile Equipment Identity (IMEI). An IMEI is marked as invalid if it has been reported stolen or is not type approved. The Authentication Center (AuC) is a protected database that stores a copy of the secret key stored in each subscriber's SIM card, which is used for authentication and encryption over the radio channel.

Radio link aspects

The International Telecommunication Union (ITU), which manages the international allocation of radio spectrum (among many other functions), allocated the bands 890-915 MHz for the uplink (mobile station to base station) and 935-960 MHz for the downlink (base station to mobile station) for mobile networks in Europe. Since this range was already being used in the early 1980s by the analog systems of the day, the CEPT had the foresight to reserve the top 10 MHz of each band for the GSM network that was still being developed. Eventually, GSM will be allocated the entire 2x25 MHz bandwidth.

Multiple access and channel structure

Since radio spectrum is a limited resource shared by all users, a method must be devised to divide up the bandwidth among as many users as possible. The method chosen by GSM is a combination of Time- and Frequency-Division Multiple Access (TDMA/FDMA). The FDMA part involves the division by frequency of the (maximum) 25 MHz bandwidth into 124 carrier frequencies spaced 200 kHz apart. One or more carrier frequencies are assigned to each base station. Each of these carrier frequencies is then divided in time, using a TDMA scheme. The fundamental unit of time in this TDMA scheme is called a burst period and it lasts 15/26 ms (or approx. 0.577 ms). Eight burst periods are grouped into a TDMA frame (120/26 ms, or approx. 4.615 ms), which forms the basic unit for the definition of logical channels. One physical channel is one burst period per TDMA frame.

Channels are defined by the number and position of their corresponding burst periods. All these definitions are cyclic, and the entire pattern repeats approximately every 3 hours. Channels can be divided into dedicated channels, which are allocated to a mobile station, and common channels, which are used by mobile stations in idle mode.

Traffic channels

A traffic channel (TCH) is used to carry speech and data traffic. Traffic channels are defined using a 26-frame multiframe, or group of 26 TDMA frames. The length of a 26-frame multiframe is 120 ms, which is how the length of a burst period is defined (120 ms divided by 26 frames divided by 8 burst periods per frame). Out of the 26 frames, 24 are used for traffic, 1 is used for the Slow Associated Control Channel (SACCH) and 1 is currently unused (see Figure 2). TCHs for the uplink and downlink are separated in time by 3 burst periods, so that the mobile station does not have to transmit and receive simultaneously, thus simplifying the electronics.

In addition to these full-rate TCHs, there are also half-rate TCHs defined, although they are not yet implemented. Half-rate TCHs will effectively double the capacity of a system once half-rate speech coders are specified (i.e., speech coding at around 7 kbps, instead of 13 kbps). Eighth-rate TCHs are also specified, and are used for signalling. In the recommendations, they are called Stand-alone Dedicated Control Channels (SDCCH).

Figure 2. Organization of bursts, TDMA frames, and multiframes for speech and data

Control channels

Common channels can be accessed both by idle mode and dedicated mode mobiles. The common channels are used by idle mode mobiles to exchange the signalling information required to change to dedicated mode. Mobiles already in dedicated mode monitor the surrounding base stations for handover and other information. The common channels are defined within a 51-frame multiframe, so that dedicated mobiles using the 26-frame multiframe TCH structure can still monitor control channels. The common channels include:
Broadcast Control Channel (BCCH)
Continually broadcasts, on the downlink, information including base station identity, frequency allocations, and frequency-hopping sequences.
Frequency Correction Channel (FCCH) and Synchronisation Channel (SCH)
Used to synchronise the mobile to the time slot structure of a cell by defining the boundaries of burst periods, and the time slot numbering. Every cell in a GSM network broadcasts exactly one FCCH and one SCH, which are by definition on time slot number 0 (within a TDMA frame).
Random Access Channel (RACH)
Slotted Aloha channel used by the mobile to request access to the network.
Paging Channel (PCH)
Used to alert the mobile station of an incoming call.
Access Grant Channel (AGCH)
Used to allocate an SDCCH to a mobile for signalling (in order to obtain a dedicated channel), following a request on the RACH.

Burst structure

There are four different types of bursts used for transmission in GSM [16]. The normal burst is used to carry data and most signalling. It has a total length of 156.25 bits, made up of two 57 bit information bits, a 26 bit training sequence used for equalization, 1 stealing bit for each information block (used for FACCH), 3 tail bits at each end, and an 8.25 bit guard sequence, as shown in Figure 2. The 156.25 bits are transmitted in 0.577 ms, giving a gross bit rate of 270.833 kbps.

The F burst, used on the FCCH, and the S burst, used on the SCH, have the same length as a normal burst, but a different internal structure, which differentiates them from normal bursts (thus allowing synchronization). The access burst is shorter than the normal burst, and is used only on the RACH.

Speech coding

GSM is a digital system, so speech which is inherently analog, has to be digitized. The method employed by ISDN, and by current telephone systems for multiplexing voice lines over high speed trunks and optical fiber lines, is Pulse Coded Modulation (PCM). The output stream from PCM is 64 kbps, too high a rate to be feasible over a radio link. The 64 kbps signal, although simple to implement, contains much redundancy. The GSM group studied several speech coding algorithms on the basis of subjective speech quality and complexity (which is related to cost, processing delay, and power consumption once implemented) before arriving at the choice of a Regular Pulse Excited -- Linear Predictive Coder (RPE--LPC) with a Long Term Predictor loop. Basically, information from previous samples, which does not change very quickly, is used to predict the current sample. The coefficients of the linear combination of the previous samples, plus an encoded form of the residual, the difference between the predicted and actual sample, represent the signal. Speech is divided into 20 millisecond samples, each of which is encoded as 260 bits, giving a total bit rate of 13 kbps. This is the so-called Full-Rate speech coding. Recently, an Enhanced Full-Rate (EFR) speech coding algorithm has been implemented by some North American GSM1900 operators. This is said to provide improved speech quality using the existing 13 kbps bit rate.

Channel coding and modulation

Because of natural and man-made electromagnetic interference, the encoded speech or data signal transmitted over the radio interface must be protected from errors. GSM uses convolutional encoding and block interleaving to achieve this protection. The exact algorithms used differ for speech and for different data rates. The method used for speech blocks will be described below.

Recall that the speech codec produces a 260 bit block for every 20 ms speech sample. From subjective testing, it was found that some bits of this block were more important for perceived speech quality than others. The bits are thus divided into three classes:

  • Class Ia 50 bits - most sensitive to bit errors
  • Class Ib 132 bits - moderately sensitive to bit errors
  • Class II 78 bits - least sensitive to bit errors
Class Ia bits have a 3 bit Cyclic Redundancy Code added for error detection. If an error is detected, the frame is judged too damaged to be comprehensible and it is discarded. It is replaced by a slightly attenuated version of the previous correctly received frame. These 53 bits, together with the 132 Class Ib bits and a 4 bit tail sequence (a total of 189 bits), are input into a 1/2 rate convolutional encoder of constraint length 4. Each input bit is encoded as two output bits, based on a combination of the previous 4 input bits. The convolutional encoder thus outputs 378 bits, to which are added the 78 remaining Class II bits, which are unprotected. Thus every 20 ms speech sample is encoded as 456 bits, giving a bit rate of 22.8 kbps.

To further protect against the burst errors common to the radio interface, each sample is interleaved. The 456 bits output by the convolutional encoder are divided into 8 blocks of 57 bits, and these blocks are transmitted in eight consecutive time-slot bursts. Since each time-slot burst can carry two 57 bit blocks, each burst carries traffic from two different speech samples.

Recall that each time-slot burst is transmitted at a gross bit rate of 270.833 kbps. This digital signal is modulated onto the analog carrier frequency using Gaussian-filtered Minimum Shift Keying (GMSK). GMSK was selected over other modulation schemes as a compromise between spectral efficiency, complexity of the transmitter, and limited spurious emissions. The complexity of the transmitter is related to power consumption, which should be minimized for the mobile station. The spurious radio emissions, outside of the allotted bandwidth, must be strictly controlled so as to limit adjacent channel interference, and allow for the co-existence of GSM and the older analog systems (at least for the time being).

Multipath equalization

At the 900 MHz range, radio waves bounce off everything - buildings, hills, cars, airplanes, etc. Thus many reflected signals, each with a different phase, can reach an antenna. Equalization is used to extract the desired signal from the unwanted reflections. It works by finding out how a known transmitted signal is modified by multipath fading, and constructing an inverse filter to extract the rest of the desired signal. This known signal is the 26-bit training sequence transmitted in the middle of every time-slot burst. The actual implementation of the equalizer is not specified in the GSM specifications.

Frequency hopping

The mobile station already has to be frequency agile, meaning it can move between a transmit, receive, and monitor time slot within one TDMA frame, which normally are on different frequencies. GSM makes use of this inherent frequency agility to implement slow frequency hopping, where the mobile and BTS transmit each TDMA frame on a different carrier frequency. The frequency hopping algorithm is broadcast on the Broadcast Control Channel. Since multipath fading is dependent on carrier frequency, slow frequency hopping helps alleviate the problem. In addition, co-channel interference is in effect randomized.

Discontinuous transmission

Minimizing co-channel interference is a goal in any cellular system, since it allows better service for a given cell size, or the use of smaller cells, thus increasing the overall capacity of the system. Discontinuous transmission (DTX) is a method that takes advantage of the fact that a person speaks less that 40 percent of the time in normal conversation [22], by turning the transmitter off during silence periods. An added benefit of DTX is that power is conserved at the mobile unit.

The most important component of DTX is, of course, Voice Activity Detection. It must distinguish between voice and noise inputs, a task that is not as trivial as it appears, considering background noise. If a voice signal is misinterpreted as noise, the transmitter is turned off and a very annoying effect called clipping is heard at the receiving end. If, on the other hand, noise is misinterpreted as a voice signal too often, the efficiency of DTX is dramatically decreased. Another factor to consider is that when the transmitter is turned off, there is total silence heard at the receiving end, due to the digital nature of GSM. To assure the receiver that the connection is not dead, comfort noise is created at the receiving end by trying to match the characteristics of the transmitting end's background noise.

Discontinuous reception

Another method used to conserve power at the mobile station is discontinuous reception. The paging channel, used by the base station to signal an incoming call, is structured into sub-channels. Each mobile station needs to listen only to its own sub-channel. In the time between successive paging sub-channels, the mobile can go into sleep mode, when almost no power is used.

Power control

There are five classes of mobile stations defined, according to their peak transmitter power, rated at 20, 8, 5, 2, and 0.8 watts. To minimize co-channel interference and to conserve power, both the mobiles and the Base Transceiver Stations operate at the lowest power level that will maintain an acceptable signal quality. Power levels can be stepped up or down in steps of 2 dB from the peak power for the class down to a minimum of 13 dBm (20 milliwatts).

The mobile station measures the signal strength or signal quality (based on the Bit Error Ratio), and passes the information to the Base Station Controller, which ultimately decides if and when the power level should be changed. Power control should be handled carefully, since there is the possibility of instability. This arises from having mobiles in co-channel cells alternatingly increase their power in response to increased co-channel interference caused by the other mobile increasing its power. This in unlikely to occur in practice but it is (or was as of 1991) under study.

Network aspects

Ensuring the transmission of voice or data of a given quality over the radio link is only part of the function of a cellular mobile network. A GSM mobile can seamlessly roam nationally and internationally, which requires that registration, authentication, call routing and location updating functions exist and are standardized in GSM networks. In addition, the fact that the geographical area covered by the network is divided into cells necessitates the implementation of a handover mechanism. These functions are performed by the Network Subsystem, mainly using the Mobile Application Part (MAP) built on top of the Signalling System No. 7 protocol.

Figure 3. Signalling protocol structure in GSM

The signalling protocol in GSM is structured into three general layers [1], [19], depending on the interface, as shown in Figure 3. Layer 1 is the physical layer, which uses the channel structures discussed above over the air interface. Layer 2 is the data link layer. Across the Um interface, the data link layer is a modified version of the LAPD protocol used in ISDN, called LAPDm. Across the A interface, the Message Transfer Part layer 2 of Signalling System Number 7 is used. Layer 3 of the GSM signalling protocol is itself divided into 3 sublayers.

Radio Resources Management
Controls the setup, maintenance, and termination of radio and fixed channels, including handovers.
Mobility Management
Manages the location updating and registration procedures, as well as security and authentication.
Connection Management
Handles general call control, similar to CCITT Recommendation Q.931, and manages Supplementary Services and the Short Message Service.
Signalling between the different entities in the fixed part of the network, such as between the HLR and VLR, is accomplished throught the Mobile Application Part (MAP). MAP is built on top of the Transaction Capabilities Application Part (TCAP, the top layer of Signalling System Number 7. The specification of the MAP is quite complex, and at over 500 pages, it is one of the longest d0cuments in the GSM recommendations [16].

Radio resources management

The radio resources management (RR) layer oversees the establishment of a link, both radio and fixed, between the mobile station and the MSC. The main functional components involved are the mobile station, and the Base Station Subsystem, as well as the MSC. The RR layer is concerned with the management of an RR-session [16], which is the time that a mobile is in dedicated mode, as well as the configuration of radio channels including the allocation of dedicated channels.

An RR-session is always initiated by a mobile station through the access procedure, either for an outgoing call, or in response to a paging message. The details of the access and paging procedures, such as when a dedicated channel is actually assigned to the mobile, and the paging sub-channel structure, are handled in the RR layer. In addition, it handles the management of radio features such as power control, discontinuous transmission and reception, and timing advance.

Handover

In a cellular network, the radio and fixed links required are not permanently allocated for the duration of a call. Handover, or handoff as it is called in North America, is the switching of an on-going call to a different channel or cell. The execution and measurements required for handover form one of basic functions of the RR layer.

There are four different types of handover in the GSM system, which involve transferring a call between:

  • Channels (time slots) in the same cell
  • Cells (Base Transceiver Stations) under the control of the same Base Station Controller (BSC),
  • Cells under the control of different BSCs, but belonging to the same Mobile services Switching Center (MSC), and
  • Cells under the control of different MSCs.
The first two types of handover, called internal handovers, involve only one Base Station Controller (BSC). To save signalling bandwidth, they are managed by the BSC without involving the Mobile services Switching Center (MSC), except to notify it at the completion of the handover. The last two types of handover, called external handovers, are handled by the MSCs involved. An important aspect of GSM is that the original MSC, the anchor MSC, remains responsible for most call-related functions, with the exception of subsequent inter-BSC handovers under the control of the new MSC, called the relay MSC.

Handovers can be initiated by either the mobile or the MSC (as a means of traffic load balancing). During its idle time slots, the mobile scans the Broadcast Control Channel of up to 16 neighboring cells, and forms a list of the six best candidates for possible handover, based on the received signal strength. This information is passed to the BSC and MSC, at least once per second, and is used by the handover algorithm.

The algorithm for when a handover decision should be taken is not specified in the GSM recommendations. There are two basic algorithms used, both closely tied in with power control. This is because the BSC usually does not know whether the poor signal quality is due to multipath fading or to the mobile having moved to another cell. This is especially true in small urban cells.

The 'minimum acceptable performance' algorithm [3] gives precedence to power control over handover, so that when the signal degrades beyond a certain point, the power level of the mobile is increased. If further power increases do not improve the signal, then a handover is considered. This is the simpler and more common method, but it creates 'smeared' cell boundaries when a mobile transmitting at peak power goes some distance beyond its original cell boundaries into another cell.

The 'power budget' method [3] uses handover to try to maintain or improve a certain level of signal quality at the same or lower power level. It thus gives precedence to handover over power control. It avoids the 'smeared' cell boundary problem and reduces co-channel interference, but it is quite complicated.

Mobility management

The Mobility Management layer (MM) is built on top of the RR layer, and handles the functions that arise from the mobility of the subscriber, as well as the authentication and security aspects. Location management is concerned with the procedures that enable the system to know the current location of a powered-on mobile station so that incoming call routing can be completed.

Location updating

A powered-on mobile is informed of an incoming call by a paging message sent over the PAGCH channel of a cell. One extreme would be to page every cell in the network for each call, which is obviously a waste of radio bandwidth. The other extreme would be for the mobile to notify the system, via location updating messages, of its current location at the individual cell level. This would require paging messages to be sent to exactly one cell, but would be very wasteful due to the large number of location updating messages. A compromise solution used in GSM is to group cells into location areas. Updating messages are required when moving between location areas, and mobile stations are paged in the cells of their current location area.

The location updating procedures, and subsequent call routing, use the MSC and two location registers: the Home Location Register (HLR) and the Visitor Location Register (VLR). When a mobile station is switched on in a new location area, or it moves to a new location area or different operator's PLMN, it must register with the network to indicate its current location. In the normal case, a location update message is sent to the new MSC/VLR, which records the location area information, and then sends the location information to the subscriber's HLR. The information sent to the HLR is normally the SS7 address of the new VLR, although it may be a routing number. The reason a routing number is not normally assigned, even though it would reduce signalling, is that there is only a limited number of routing numbers available in the new MSC/VLR and they are allocated on demand for incoming calls. If the subscriber is entitled to service, the HLR sends a subset of the subscriber information, needed for call control, to the new MSC/VLR, and sends a message to the old MSC/VLR to cancel the old registration.

For reliability reasons, GSM also has a periodic location updating procedure. If an HLR or MSC/VLR fails, to have each mobile register simultaneously to bring the database up to date would cause overloading. Therefore, the database is updated as location updating events occur. The enabling of periodic updating, and the time period between periodic updates, is controlled by the operator, and is a trade-off between signalling traffic and speed of recovery. If a mobile does not register after the updating time period, it is deregistered.

A procedure related to location updating is the IMSI attach and detach. A detach lets the network know that the mobile station is unreachable, and avoids having to needlessly allocate channels and send paging messages. An attach is similar to a location update, and informs the system that the mobile is reachable again. The activation of IMSI attach/detach is up to the operator on an individual cell basis.

Authentication and security

Since the radio medium can be accessed by anyone, authentication of users to prove that they are who they claim to be, is a very important element of a mobile network. Authentication involves two functional entities, the SIM card in the mobile, and the Authentication Center (AuC). Each subscriber is given a secret key, one copy of which is stored in the SIM card and the other in the AuC. During authentication, the AuC generates a random number that it sends to the mobile. Both the mobile and the AuC then use the random number, in conjuction with the subscriber's secret key and a ciphering algorithm called A3, to generate a signed response (SRES) that is sent back to the AuC. If the number sent by the mobile is the same as the one calculated by the AuC, the subscriber is authenticated [16].

The same initial random number and subscriber key are also used to compute the ciphering key using an algorithm called A8. This ciphering key, together with the TDMA frame number, use the A5 algorithm to create a 114 bit sequence that is XORed with the 114 bits of a burst (the two 57 bit blocks). Enciphering is an option for the fairly paranoid, since the signal is already coded, interleaved, and transmitted in a TDMA manner, thus providing protection from all but the most persistent and dedicated eavesdroppers.

Another level of security is performed on the mobile equipment itself, as opposed to the mobile subscriber. As mentioned earlier, each GSM terminal is identified by a unique International Mobile Equipment Identity (IMEI) number. A list of IMEIs in the network is stored in the Equipment Identity Register (EIR). The status returned in response to an IMEI query to the EIR is one of the following:

White-listed
The terminal is allowed to connect to the network.
Grey-listed
The terminal is under observation from the network for possible problems.
Black-listed
The terminal has either been reported stolen, or is not type approved (the correct type of terminal for a GSM network). The terminal is not allowed to connect to the network.

Communication management

The Communication Management layer (CM) is responsible for Call Control (CC), supplementary service management, and short message service management. Each of these may be considered as a separate sublayer within the CM layer. Call control attempts to follow the ISDN procedures specified in Q.931, although routing to a roaming mobile subscriber is obviously unique to GSM. Other functions of the CC sublayer include call establishment, selection of the type of service (including alternating between services during a call), and call release.

Call routing

Unlike routing in the fixed network, where a terminal is semi-permanently wired to a central office, a GSM user can roam nationally and even internationally. The directory number dialed to reach a mobile subscriber is called the Mobile Subscriber ISDN (MSISDN), which is defined by the E.164 numbering plan. This number includes a country code and a National Destination Code which identifies the subscriber's operator. The first few digits of the remaining subscriber number may identify the subscriber's HLR within the home PLMN.

An incoming mobile terminating call is directed to the Gateway MSC (GMSC) function. The GMSC is basically a switch which is able to interrogate the subscriber's HLR to obtain routing information, and thus contains a table linking MSISDNs to their corresponding HLR. A simplification is to have a GSMC handle one specific PLMN. It should be noted that the GMSC function is distinct from the MSC function, but is usually implemented in an MSC.

The routing information that is returned to the GMSC is the Mobile Station Roaming Number (MSRN), which is also defined by the E.164 numbering plan. MSRNs are related to the geographical numbering plan, and not assigned to subscribers, nor are they visible to subscribers.

The most general routing procedure begins with the GMSC querying the called subscriber's HLR for an MSRN. The HLR typically stores only the SS7 address of the subscriber's current VLR, and does not have the MSRN (see the location updating section). The HLR must therefore query the subscriber's current VLR, which will temporarily allocate an MSRN from its pool for the call. This MSRN is returned to the HLR and back to the GMSC, which can then route the call to the new MSC. At the new MSC, the IMSI corresponding to the MSRN is looked up, and the mobile is paged in its current location area (see Figure 4).

Figure 4. Call routing for a mobile terminating call

Conclusion and comments

In this paper I have tried to give an overview of the GSM system. As with any overview, and especially one covering a standard 6000 pages long, there are many details missing. I believe, however, that I gave the general flavor of GSM and the philosophy behind its design. It was a monumental task that the original GSM committee undertook, and one that has proven a success, showing that international cooperation on such projects between academia, industry, and government can succeed. It is a standard that ensures interoperability without stifling competition and innovation among suppliers, to the benefit of the public both in terms of cost and service quality. For example, by using Very Large Scale Integration (VLSI) microprocessor technology, many functions of the mobile station can be built on one chipset, resulting in lighter, more compact, and more energy-efficient terminals.

Telecommunications are evolving towards personal communication networks, whose objective can be stated as the availability of all communication services anytime, anywhere, to anyone, by a single identity number and a pocketable communication terminal [25]. Having a multitude of incompatible systems throughout the world moves us farther away from this ideal. The economies of scale created by a unified system are enough to justify its implementation, not to mention the convenience to people of carrying just one communication terminal anywhere they go, regardless of national boundaries.

The GSM system, and its sibling systems operating at 1.8 GHz (called DCS1800) and 1.9 GHz (called GSM1900 or PCS1900, and operating in North America), are a first approach at a true personal communication system. The SIM card is a novel approach that implements personal mobility in addition to terminal mobility. Together with international roaming, and support for a variety of services such as telephony, data transfer, fax, Short Message Service, and supplementary services, GSM comes close to fulfilling the requirements for a personal communication system: close enough that it is being used as a basis for the next generation of mobile communication technology in Europe, the Universal Mobile Telecommunication System (UMTS).

Another point where GSM has shown its commitment to openness, standards and interoperability is the compatibility with the Integrated Services Digital Network (ISDN) that is evolving in most industrialized countries, and Europe in particular (the so-called Euro-ISDN). GSM is also the first system to make extensive use of the Intelligent Networking concept, in in which services like 800 numbers are concentrated and handled from a few centralized service centers, instead of being distributed over every switch in the country. This is the concept behind the use of the various registers such as the HLR. In addition, the signalling between these functional entities uses Signalling System Number 7, an international standard already deployed in many countries and specified as the backbone signalling network for ISDN.

GSM is a very complex standard, but that is probably the price that must be paid to achieve the level of integrated service and quality offered while subject to the rather severe restrictions imposed by the radio environment.

References

[1]
Jan A. Audestad. Network aspects of the GSM system. In EUROCON 88, June 1988.

[2]
D. M. Balston. The pan-European system: GSM. In D. M. Balston and R.C.V. Macario, editors, Cellular Radio Systems. Artech House, Boston, 1993.

[3]
David M. Balston. The pan-European cellular technology. In R.C.V. Macario, editor, Personal and Mobile Radio Systems. Peter Peregrinus, London, 1991.

[4]
M. Bezler et al. GSM base station system. Electrical Communication, 2nd Quarter 1993.

[5]
David Cheeseman. The pan-European cellular mobile radio system. In R.C.V. Macario, editor, Personal and Mobile Radio Systems. Peter Peregrinus, London, 1991.

[6]
C. Déchaux and R. Scheller. What are GSM and DCS. Electrical Communication, 2nd Quarter 1993.

[7]
M. Feldmann and J. P. Rissen. GSM network systems and overall system integration. Electrical Communication, 2nd Quarter 1993.

[8]
John M. Griffiths. ISDN Explained: Worldwide Network and Applications Technology. John Wiley &Sons, Chichester, 2nd edition, 1992.

[9]
I. Harris. Data in the GSM cellular network. In D. M. Balston and R.C.V. Macario, editors, Cellular Radio Systems. Artech House, Boston, 1993.

[10]
I. Harris. Facsimile over cellular radio. In D. M. Balston and R.C.V. Macario, editors, Cellular Radio Systems. Artech House, Boston, 1993.

[11]
Thomas Haug. Overview of the GSM project. In EUROCON 88, June 1988.

[12]
Josef-Franz Huber. Advanced equipment for an advanced network. Telcom Report International, 15(3-4), 1992.

[13]
Hans Lobensommer and Helmut Mahner. GSM - a European mobile radio standard for the world market. Telcom Report International, 15(3-4), 1992.

[14]
Bernard J. T. Mallinder. Specification methodology applied to the GSM system. In EUROCON 88, June 1988.

[15]
Seshadri Mohan and Ravi Jain. Two user location strategies for personal communication services. IEEE Personal Communications, 1(1), 1994.

[16]
Michel Mouly and Marie-Bernadette Pautet. The GSM System for Mobile Communications. Published by the authors, 1992.

[17]
Jon E. Natvig, Stein Hansen, and Jorge de Brito. Speech processing in the pan-European digital mobile radio system (GSM) - system overview. In IEEE GLOBECOM 1989, November 1989.

[18]
Torbjorn Nilsson. Toward a new era in mobile communications. http://193.78.100.33/ (Ericsson WWW server).

[19]
Moe Rahnema. Overview of the GSM system and protocol architecture. IEEE Communications Magazine, April 1993.

[20]
E. H. Schmid and M. Kähler. GSM operation and maintenance. Electrical Communication, 2nd Quarter 1993.

[21]
Marko Silventoinen. Personal email, quoted from European Mobile Communications Business and Technology Report, March 1995, and December 1995.

[22]
C. B. Southcott et al. Voice control of the pan-European digital mobile radio system. In IEEE GLOBECOM 1989, November 1989.

[23]
P. Vary et al. Speech codec for the European mobile radio system. In IEEE GLOBECOM 1989, November 1989.

[24]
C. Watson. Radio equipment for GSM. In D. M. Balston and R.C.V. Macario, editors, Cellular Radio Systems. Artech House, Boston, 1993.

[25]
Robert G. Winch. Telecommunication Transmission Systems. McGraw-Hill, New York, 1993.

Copyright © John Scourias 1996-1999
Written by John Scourias
Last modified October 14, 1997.

하드웨어적 관점에서 접근한
휴대폰 개발 프로세스

휴대폰 개발은 다른 임베디드 시스템 이상으로 방대한 특성 탓에 각 분야마다 많은 전문 인력이 투입되어 개발이 진행된다. 이 글에서는 하드웨어를 중심으로 휴대폰 개발의 개괄적인 현황과 개발 프로세스를 설명하고, 다른 임베디드 시스템 개발에도 적용될 수 있는 소프트웨어 기법 몇 가지를 추가로 소개한다.

박찬민 eacs@hanback.co.kr

먼저 프로토콜, 플랫폼 등을 기준으로 휴대폰의 변화 과정을 설명하면서 개발 프로세스를 이해하는 데 필요한 기본 지식을 점검해 본다.

프로토콜에 따른 구분

먼저 프로토콜에 따라 휴대폰 서비스를 구분해 보면 다음과 같다.

CDMA와 GSM

무선 구간에서 기지국과 단말기 사이의 신호 전송방식은 동기식과 비동기식으로 구분되는데 북미 방식인 동기식은 기지국에서 GPS(Global Positioning System)의 시간과 위치정보를 이용하고, 유럽방식인 비동기식은 GPS를 사용하지 않는다. CDMA (Code Division Multiple Access)로 대표되는 동기식의 경우 IS-95 프로토콜을 포함한 cdmaOne과, IS-2000 프로토콜을 근간으로 한 cdma2000이 있으며, 비동기식은 GSM(Global Service for Mobile Telecommunication)과 이를 기반으로 한 UMTS가 있다. cdma2000과 UMTS는 IMT-2000의 규격에 부합되는 프로토콜이다.

IMT-2000

1996년 5월 10월 TG8/1 회의에서 승인된 IMT-2000은 CDMA와 GSM으로 양분되어 국제로밍이 어려웠던 점을 극복하고자 전 세계적으로 동일한 주파수(2GHz) 대역을 사용해 로밍할 수 있게 하는 방식이다. 유럽방식인 비동기식 CDMA와 북미방식인 동기식 CDMA로 구분되며 비동기식 CDMA를 W-CDMA(Wideband CDMA), 동기식 CDMA를 MC-CDMA(Multi Carrier CDMA)라고 한다. 음성통화 중심의 2G (Generation)에서는 전 세계 80% 이상이 GSM을 사용하고 있으므로 고속 데이터 서비스를 포함해 부가 서비스가 강화된 3G는 대부분의 국가가 유럽방식인 W-CDMA를 채택하고 있다.

W-CDMA와 HSDPA

영상통화와 VOD, VoIP, UCC, 내비게이션에 이르기까지 무선 인터넷 기반의 새로운 서비스를 제공하는 IMT-2000은 CDMA와 GSM으로부터 진화했다. CDMA에서 출발한 동기식은 주파수 효율과 데이터 서비스 속도를 개선해 CDMA2000 1x, CDMA2000 1x EVDO를 거쳐 CDMA2000 1x EVDO Revision A로 진화하고 있으며, GSM을 기반으로 한 비동기식은 WCDMA, HSDPA를 거쳐 HSUPA로 진화하고 있다. HSDPA는 다운로드 속도에 비해 업로드 속도가 제한적이었으나 HSUPA에서는 업로드 속도까지 함께 개선되어 영상통화를 비롯한 본격적인 양방향 초고속 데이터 서비스 시대를 열고 있다.

플랫폼에 따른 구분

이어서 플랫폼을 이용한 구분을 살펴보면 다음과 같다.

휴대폰 플랫폼

휴대폰 플랫폼은 타깃에 따라 Value, Multi media, Enhanced, Convergence로 나눌 수 있는데 휴대폰 기능에 충실한 Value는 아프리카나 동남아, 중국과 같은 저가 시장을 목표로 하고, 최상위 플랫폼인 Convergence는 휴대폰용 프로세서의 비약적인 발전에 힘입어 PC 성능을 접목한 지능적인 휴대폰을 목표로 한다.

지금까지의 휴대폰 플랫폼은 디지털 카메라나 MP3 플레이어, 휴대용 TV, 내비게이션, 게임기 등의 융합에 필요한 멀티미디어 처리 능력의 향상에 주력해 왔다. 하지만 최근에는 PC에서 수행하던 업무들을 이동 중에도 수행할 수 있도록 휴먼 인터페이스를 포함한 대화면 터치스크린, HSDPA/HSUPA 고속 데이터 서비스, WiFi를 결합한 MID(Mobile Internet Device) 형태의 Convergence 플랫폼으로 발전하고 있다. 또 다른 측면에서는 RFID나 각종 센서와 결합해 모바일 RFID나 홈 네트워크, 헬스케어와 같은 특수 분야까지 진출하기도 한다.

<그림1> 프로토콜에 따른 구분

모바일 프로세서

기능성과 이동성이 강조된 휴대용 플랫폼에 대한 수요가 급증함에 따라 스마트폰을 중심으로 한 MID 제품군에 많은 관심이 집중되고 있는데, 기존 휴대폰에 채용된 ARM9 코어에 모뎀 제어와 2D 그래픽 처리용 DSP가 결합된 형태로는 한계에 부딪힐 수밖에 없다. 이를 해결하기 위해 최근 인텔은 1.8GHz 성능을 제공하는 CISC 기반의 초소형 기기용 프로세서인 Atom을 출시한 바 있고, ARM 역시 ARM11을 비롯해 1GHz의 성능과 밀리와트(mW) 급 전력 소모를 나타내는 Cortex-A8을 공급하고 있다. 특히 MID에서 자유로운 인터넷 환경을 구축하기 위해서는 고성능 프로세서와 함께 향상된 그래픽 구현 시스템이 제공되어야 하는데 ARM의 경우 Mali GPU를 통해 모바일 시스템 개발에 필요한 대부분의 기능을 제공하고 있다. Mali GPU는 CPU와 별도로 동작할 수 있는 3D 엔진 소프트웨어로 OpenGL ES와 OpenVG를 지원한다.

스마트폰

PDA에 이동전화 기능이 포함된 PDA폰과 달리 스마트폰은 이동전화에 인터넷 기능을 포함한 것으로 SMS뿐만 아니라 PIMS(Personal Information Management System), MMS(Multimedia Messaging Service), 이메일 전송, MPEG 및 MP3 플레이어 등이 구현됨에 따라 사용자들이 스마트폰에서도 PC에 버금가는 기능들을 체험할 수 있게 되었다. 최근 관심을 끌고 있는 스마트폰 운영체제로는 심비안, 블랙베리, OS X 포터블, 윈도우 모바일, 안드로이드 등을 꼽을 수 있으며 이중 심비안과 윈도우 모바일, 안드로이드가 리더 그룹을 형성하며 경쟁을 펼치고 있다.

휴대폰 개발 프로세스

휴대폰은 프로세서가 무선 프로토콜 처리 기능이 포함된 베이스밴드 프로세서(Baseband Processor)라는 점을 제외하면 모바일 게임기나 내비게이션과 마찬가지로 프로세서와 메모리, LCD, 사운드 칩, 키패드 등이 결합된 디지털 전자제품으로 볼 수 있다. 하지만 이동통신 장비의 특성상 기지국 장비와 RF 신호를 주고받으므로 전파 및 프로토콜과 관련된 까다로운 인증 절차가 따른다.

휴대폰 개발 프로세스는 일반적인 전자제품과 유사하다. 먼저 시장과 고객층을 분석하고 소프트웨어와 하드웨어의 사양 및 가격, 출시 시점을 결정하는 제품기획 단계를 수행한다. 이어서 하드웨어와 소프트웨어, 그리고 기구물 개발 단계를 거쳐 기능과 성능 및 인증 테스트 단계를 통과하면 최종적으로 양산에 들어간다.

제품 기획

제품 기획 단계에는 기획자 외에 하드웨어, 소프트웨어 개발자 및 디자이너가 참여하게 되는데 하드웨어 개발자는 원하는 기능을 구현하기 위해 적절한 부품을 찾아보고 사용 가능성, 납기, 가격 등을 확인한다. 소프트웨어 개발자는 구현하려는 기능에 대한 검토와 더불어 선정한 기능이 하드웨어에서 지원하는지를 하드웨어 개발자와 협의한다. 디자이너는 기구물 형태, 재질 등이 하드웨어 부품 배치와 전파 감도에 영향을 미치지 않는지를 하드웨어 개발자와 협의하고 실물 형상을 검토하기 위해 목업(Mock up)을 제작한다.

하드웨어 설계 및 제작

하드웨어의 설계 및 제작은 회로 설계, 보드 제작, 검토, 완료로 세분화된다. 회로 설계 단계에서는 RF 엔지니어와 베이스밴드 엔지니어로 분류된 하드웨어 개발자에 의해 베이스밴드 프로세서 제조사에서 제공하는 레퍼런스 회로도를 참조해 <화면 1>의 EDA 툴 같은 전문 설계 툴로 회로도를 작성한 후 보드 제작을 위해 PCB Artwork 담당자에게 전달한다. PCB Artwork 담당자는 PCB 제작을 위해 RF 성능을 고려해 부품의 배치와 연결선의 경로를 결정하는 Artwork 작업을 수행한다.

<화면1> PowerPCB를 이용한 PCB 설계

이후 PCB가 완성되면 부품과 함께 SMT(Surface Mount tech/nology) 업체에 전달해 PCB 위에 부품을 납땜함으로써 보드를 완성한다. SMT 작업은 PCB 위에 납 분말을 도포한 후 부품을 올려놓고 뜨거운 열풍으로 납땜하는 방법으로 이뤄진다. SMT 작업이 완료되면 육안검사와 더불어 전원을 인가해 쇼트나 단락의 문제가 없는지를 확인한다. 소프트웨어 개발자는 보드의 검증을 위해 부트로더를 이용해 부품을 테스트하는 코드를 작성함으로써 테스트를 수행한다.

소프트웨어 개발 및 테스트

소프트웨어 개발자는 베이스밴드 칩 제조업체에서 소스 코드 형태로 제공하는 레퍼런스 보드에 대한 소프트웨어 패키지를 이용해 필요한 기능을 구현한다. 베이스밴드 칩 제조사에서 권장하는 레퍼런스 보드와 유사한 방법으로 하드웨어를 설계한 경우에는 GPIO 및 메모리 매핑 부분과 LCD 드라이버만 수정하면 초기화면을 띄울 수 있다. 휴대폰 UI의 경우 BREW나 WIPI와 같은 표준 미들웨어를 이용하기도 하지만 대부분 독자적인 UI 시스템을 개발해 사용한다. WAP 브라우저나 게임과 같은 콘텐츠들은 써드파티 업체에서 라이선스를 받아 장착하는데 소스 코드가 제공되지 않으므로 상호 인터페이스를 잘 정의하고 긴밀한 협의를 거쳐 진행된다.

개발 단계에서는 테스트를 전담하는 인력에 의해 수많은 검증 과정을 거쳐 소프트웨어 안정성과 신뢰성을 검증한다. 가이드북에 따라 모든 항목을 반복 테스트한 후 결과를 개발자에게 전달해 오류나 버그가 수정될 수 있게 한다. RF 프로토콜과 Call에 관련된 소프트웨어 기능들은 공인 인증기관들에 의해 정해진 규격에 따라 인증절차를 거치게 된다. 휴대폰이 사용되는 지역의 통신사업자들도 자체적인 인증규격을 가지고 있으므로 최종적으로는 사업자의 인증과정을 다시 한 번 거쳐야 한다.

기구물 제작

케이스로 대표되는 기구물은 키패드, 버튼, 커버 등으로 구성된다. 기구물은 고객이 상품을 평가하는 첫 번째 요소이므로 제품의 상품성을 높이기 위해 최근에는 외부의 검증된 상품 디자이너를 참여시켜는 등 품질 향상에 노력하고 있다. ID(Industrial Design)는 손으로 그린 스케치를 2D 이미지로 변환하고 최종적으로는 3D로 렌더링한 디자인 프로파일을 얻어 최종 휴대폰 디자인을 결정하는 작업이다. ID 작업에 대한 실물 검토를 위해 목업 업체에 시안을 의뢰하기도 하는데 이 과정에서 ID 결과물을 플라스틱 등으로 제작해 디자인의 완성도를 실물로 확인할 수 있다.

기구 설계 작업이 끝나면 결과물을 가지고 대량 생산을 할 수 있도록 금형 설계를 진행하는데 금형 설계자는 품질을 고려해 금형을 설계한다.

제품 검증

휴대폰은 특성상 작은 하자에도 큰 문제를 발생시킬 수 있으므로 기능 테스트와 성능 테스트, 신뢰성 테스트, 인증으로 이어지는 매우 철저한 검증 작업이 요구된다. 이중 가장 먼저 수행하는 기능 테스트는 제품의 정상 동작 여부를 확인하는 과정으로 기능 테스트를 통과하면 제품의 성능을 확인하고 이를 극대화시키는 성능 테스트를 수행한다. 제품을 사용하는 소비자의 다양한 실제 환경을 고려한 신뢰성 테스트까지 마치면 공인 인증기관을 통해 CDG-1, CDG-2, CDG-3 인증을 의뢰한다. 여기서 CDG-1은 하드웨어 성능에 대한 인증이고 CDG-2는 통신 프로토콜과 같은 소프트웨어 성능에 대한 인증이며 CDG-3은 기지국 장비 연동 성능에 대한 인증이다.

양산

제품 검증까지 완료되면 개발 제품을 대량으로 생산하는 양산을 진행한다. 양산이 시작되기 전에 개발팀과 협력해 품질 관리에 걸림돌이 되는 부분을 수정하는데, 양산 전에 미처 발견하지 못한 문제점들에 대해서는 양산을 진행하면서 빠른 시간 안에 수정 또는 개선하는 작업을 병행해 진행한다. 대부분 소프트웨어와 관련된 수정이므로 제작사 홈페이지나 AS센터를 통해 무상 업그레이드를 진행한다.

휴대폰 개발 기술

휴대폰 개발 기술은 빠르게 진화하고 있으며 제품 라이프 사이클도 6개월 이내로 짧아지고 있다. 모든 제조업체들은 가장 성능이 좋으면서 가격 경쟁력이 있는 부품을 선택하고자 노력하고 있으며 초대형 부품 회사들이 모든 휴대폰 제조사를 상대로 부품을 공급하고 있으므로 경쟁사들의 최신 휴대폰 성능이나 사양은 크게 차이나지 않는 것이다.

베이스밴드 프로세서

휴대폰의 가장 핵심 부품인 베이스밴드 프로세서는 전 세계 시장의 95% 이상이 ARM 코어를 기반으로 DSP를 내장한 ASIC 형태의 제품이다. ARM 코어는 ARM9이 주로 사용되었으며, 최근에는 ARM11과 ARM9이 듀얼로 결합한 Conversions용 제품의 출시가 늘고 있다. 함께 포함된 DSP는 주로 2D나 3D 처리와 같은 그래픽 프로세서의 역할과 이동통신 프로토콜 처리를 담당하는 모뎀 역할을 수행한다. 내부 버스나 외부 버스 구조는 일반적인 ARM 아키텍처와 동일하다.

메모리

휴대폰에서는 공간 집적도를 높이기 위해 PSRAM(Pseude-SRAM), SDRAM(Synchronous-DRAM), NAND Flash를 결합해 하나의 패키지로 구성한 MCP(Multi-Chip Package) 메모리를 사용한다. 이중 PSRAM은 NAND Flash 기반의 부팅 과정에서 복사된 커널 이미지를 실행하는 용도로 사용되는데 DRAM에 충전회로를 하나의 패키지로 결합해 SRAM처럼 만들었다고 해서 PSRAM이라 부른다. NOR Flash보다 값이 저렴해 많이 채택되는 NAND Flash는 읽기 시간이 상대적으로 길다는 단점이 있으나 쓰기 효율은 좋은 편이므로 카메라 사진이나 동영상 데이터, MP3와 같은 데이터를 저장하는 용도로 많이 사용한다.

표준 DRAM에 비해 4배 이상 빠른 속도로 동작하는 SDRAM은 행 주소와 열 주소로 나눠 진 Matrix 형태의 주소 방식을 사용한다. 따라서 한 주소를 접근하려면 2회에 걸쳐 어드레싱해야 하므로 타이밍이 복잡한 회로가 되지만, 주소 개수를 절반 가까이 줄일 수 있어 칩의 핀 개수가 줄어드는 이점이 있다. 그 밖에 SDRAM은 Interleaved Cell 뱅크와 Burst 모드를 제공하는데 Interleaved Cell은 두 개로 분리된 셀 뱅크가 동시에 동작할 수 있다. 그러므로 연속되는 정보의 흐름이 뱅크 사이에서 변화하면서 진행될 수 있어 전체 메모리 사이클을 줄이고 전송 속도를 높일 수 있다. Burst 모드는 프로세서가 시작 주소만 지정하면 자동으로 연속적인 나머지 주소 공간을 접근할 수 있게 하는 기능이다. 따라서 메모리 접근 사이클에서 주소 지정에 따른 주소 로딩 시간을 단축시켜 대용량 데이터의 고속 전송이 이뤄질 수 있다.

LCD 모듈 인터페이스

LCD는 LDI(LCD Driver ID)를 통해 프로세서와 연결되는데 LDI는 프로세서가 보내는 데이터를 LCD 패널에 뿌려주는 기능을 수행한다. 프로세서는 LDI에 데이터와 명령을 보내는 방식으로 원하는 화면을 출력하는데, 일반적으로 프로세서와 LDI 사이에 데이터나 명령을 송수신하는 방법에는 CPU 인터페이스와 RGB 인터페이스가 적용된다.

먼저 CPU 인터페이스 방식에서는 LDI에 포함된 프레임 버퍼에 데이터를 전송하면 LDI가 그 안에 저장된 이미지 데이터를 주기적으로 LCD 패널에 뿌려 주므로 프로세서 입장에서는 LCD에 표시되는 그림을 변경하고 싶을 경우에만 LDI에 새로운 이미지 데이터를 보내 주면 된다. 따라서 LCD 화면을 관리하는 데 그다지 큰 부하가 발행하지 않는다. 그에 반해 RGB 인터페이스 방식은 프로세서가 프레임 버퍼를 만들어 두고 그 안에 저장된 이미지를 주기적으로 LDI로 전달해야 한다. 따라서 LCD 화면에 보이는 그림이 변하지 않는 상황에서도 동일한 데이터를 LDI로 주기적으로 전송해야 하는 탓에 부하가 많이 걸린다. 일반적으로 RGB 인터페이스 방식은 LCD 컨트롤러를 내장한 고속 프로세서에서 사용되므로 동영상 디스플레이와 같이 빠르게 변화하는 화면을 LCD로 출력하는 경우에 적합하다.

카메라

CIS(Camera Image Sensor), ISP(Image Signal Processor), 컨트롤러로 구성된 카메라 모듈은 이미 휴대폰의 필수 디바이스로 자리 잡았다. CIS는 렌즈로 입사된 이미지를 디지털 데이터로 변환하는 센서로 인간의 망막과 같은 역할을 한다. ISP는 CIS에서 변환한 디지털 데이터에 여러 가지 연산을 수행하는데 명도, 채도, 조도 등을 조작해 인간의 눈에 비치는 것과 가장 유사한 이미지를 만들어 낸다. 최근에는 카메라 컨트롤러에 ISP가 포함되기도 한다. 캡처, JPEG 압축과 변환, 확대, 축소, 오버레이 등 카메라 기능을 제어하고 LCD로 이미지를 출력하는 기능은 카메라 컨트롤러가 수행하는데 이 역시 베이스밴드 프로세서에 포함되기도 한다. 하지만 별도의 컨트롤러를 사용하는 것이 카메라의 성능을 더 높일 수 있으므로 외부에 별도로 장착하는 경우가 많다.

카메라 컨트롤러는 카메라 기능이 사용되지 않는 동안에는 프로세서에서 전송한 이미지가 그대로 LCD에 출력되도록 By-pass 모드로 설정되며, 카메라가 동작할 때에는 카메라 모듈로부터 입력된 데이터를 LCD로 출력하는 캡처, 프리뷰, OSD(On Screen Display) 모드 중 하나의 상태로 설정된다. 캡처 모드는 사진 촬영에 사용되는데 ISP로부터 전송 받은 데이터를 JPEG로 인코딩해 베이스밴드 프로세서로 보낸다. 프리뷰 모드는 카메라 렌즈에 잡힌 모습을 그대로 LCD로 보내며, OSD는 배경 그림을 놓고 촬영한 것과 같은 오버레이 기능이 필요할 때 사용한다.

오디오

휴대폰 환경에서 사운드 포맷은 음성 통화를 위한 음성 코덱인 보코더(Vocoder)와 MP3나 AAC(Advanced Audio Coding)와 같은 일반적인 사운드를 처리하는 오디오 코덱, 그리고 MIDI와 같이 음을 만들어 내는 합성음(synthetic audio) 코덱으로 구분된다. 음성 코덱으로는 QCELP(QualComm Code Excited Linear Predictive Coding)와 AMR(Adaptive Multi Rate)이 대표적이다. AAC는 MPEG-2의 오디오 레이어를 가리키는 96Kbps 정도의 가변 비트율을 지원하므로 고정 비트율인 MP3의 128Kbps보다 압축률이 높은 편이다. 전자악기의 연주 정보 등을 상호 전달하기 위해 정해진 하드웨어 및 통신 프로토콜의 국제적 표준규격인 MIDI는 악기 종류, 음색 수, 음색 번호, 음의 길이나 세기, 효과음 등의 여러 가지 요소를 디지털화함으로써 전자음악의 보급에 많은 기여를 했으며 전자악기, 컴퓨터, 휴대폰 등에서 광범위하게 사용되고 있다.

안테나

최근의 휴대폰 디자인은 더 얇고 가벼우며 작은 형태를 지향하고 있다. 기존의 Stubby 안테나와 같은 돌출형 구조는 휴대폰의 디자인에 많은 제약을 줄 수 있어 최근에 출시되는 대부분의 신형 휴대폰은 내장형 안테나(Intenna)를 장착해 출시되고 있다. 특히 휴대폰의 두께가 10mm 이하로 얇아지면서 안테나의 소형화는 더욱 중요한 이슈가 되었다.

최근에는 DMB, GPS, WLAN 등의 서로 다른 주파수 대역의 통신 서비스를 모두 지원하는 휴대폰까지 등장하고 있다. 따라서 하나의 휴대폰에 여러 개의 안테나가 장착되거나, 동시에 여러 주파수 대역을 다룰 수 있는 멀티밴드(Multiband) 안테나를 적용하고 있다.

윈도우 모바일 아키텍처

퀄컴은 MSM7xxx 베이스밴드 프로세서에 ARM11과 ARM9을 듀얼로 집적해 윈도우 모바일이나 임베디드 리눅스를 응용 운영체제로 추가 설치할 수 있게 지원한다. <그림 2>에서 보는 것처럼 기존의 휴대폰 소프트웨어들은 ARM9과 가상화 운영체제 상에서 레거시 운영체제 에뮬레이션을 통해 동작하고, 응용프로그램은 ARM11 기반의 응용 운영체제 상에서 동작하는 형태다.

윈도우 모바일의 경우는 디바이스 드라이버를 포함한 주요 휴대폰 서비스 부분은 퀄컴에서, 윈도우 커널을 포함한 응용 부분은 마이크로소프트에서 각각 제공하고 있다.

<그림2> MSM7xxx 윈도우 모바일 아키텍처

심비안

심비안은 마이크로소프트를 견제하기 위해 사이온, 모토롤라, 노키아, 파나소닉, 소니, 에릭슨, 삼성전자, 지멘스 등의 8개 업체가 공동으로 설립한 기업의 이름이자 운영체제의 이름으로 사이온이 현재 최대 주주이다. 객체지향 개념으로 설계된 심비안은 휴대폰 서비스에 최적화된 스마트폰 플랫폼으로 C++로 구현되어 있다. 마이크로 커널 아키텍처 기반으로 디바이스 드라이버 계층은 윈도우 모바일과 같이 물리 계층과 논리 계층으로 구분되어 있으며, 우수한 32비트 RTOS 능력을 갖춰 창을 여러 개 띄워 놓고 편집 작업을 할 수 있다. 특히 메모리나 저장장치 등의 리소스가 부족하거나 통신이 불안정한 환경에서도 신속하게 사용자 데이터로의 접근이 가능하도록 지원한다.

<그림3> 심비안 아키텍처

파일시스템을 배제한 GUI 개발

임베디드 리눅스나 윈도우 모바일과 같은 스마트폰 환경과 달리 일반적인 휴대폰 환경은 파일시스템을 사용하지 않고 소스 코드 상에 BMP나 WAV, 심지어 DSP 펌웨어까지 C 언어의 배열 형태로 변환해 사용하는 경우가 있다. 이러한 방법은 파일시스템에 대한 접근을 필요로 하지 않으므로 빠른 결과를 얻을 수 있고, 부팅시 파일시스템이 초기화되지 않은 상태에서도 효과음 처리나 LCD에 관련 이미지를 출력하는 등의 작업을 할 수 있다는 장점을 지닌다. 단 커널 사이즈가 커지는 것이 단점이다.

BMP 이미지 적용

일반적으로 스마트폰에서는 GUI를 만들 때 그림 이미지인 BMP 파일을 이용해 버튼이나 대화상자를 만든다. 하지만 BMP 파일을 C 언어의 배열 형태로 변환해 커널 이미지에 포함하면 파일시스템에 대한 접근 없이 빠르게 LCD로 해당 이미지를 출력할 수 있어 성능을 중요시하는 영역에서는 효과적이다. LCD가 5:6:5 포맷을 사용하는 16비트 컬러를 사용한다면 기존 BMP 이미지에서 그림을 나타내는 부분을 워드(16비트) 단위로 읽어 16진수로 변환하는 프로그램을 사용하면 된다. 이런 프로그램은 인터넷에서 무료로 구할 수 있으므로 직접 작성할 필요가 없다. <리스트 1>은 <화면 2>를 C 언어 배열로 변환한 결과이다.

<화면2> BMP 이미지

<리스트 1> BMP 이미지를 C 배열로 변환한 결과

unsight char logo[1024] =
{
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF,
0xFF , 0xFF , 0xC0 , 0x5D , 0x4B , 0x42 , 0xB0 , 0x88
//중략
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
};

WAV 적용

휴대폰 부팅 과정에 효과음을 넣기 위해 WAV 포맷을 많이 사용하며, WAV 파일도 C 언어 배열로 변환해 사용할 수 있다. 일반적으로 WAV 포맷의 경우 ARM 코어에서 코덱을 제공하므로 I2S(Inter IC Sound)를 사용해 WAV 데이터를 DAM Transfer로 전송하면 된다. WAV 파일 변환 역시 BMP 파일 변환과 동일하다.

폰트 적용

GUI에서 글자를 출력하려면 폰트 파일이 필요하다. 일반적으로 폰트 파일은 상업용 파일을 많이 사용하므로 제품 개수당 로열티가 있다. 또한 사용하는 언어에 따라 수 KB에서 수십 MB 정도의 용량을 가지므로 필요한 폰트만 선택할 필요가 있다. 보통 .ttf 확장자를 갖는 트루타입 폰트를 BMP 파일 변환과 유사한 방법으로 변환해 사용한다.

최근 지식경제부는 ‘지식·혁신 주도형 산업 강국으로의 전환’을 비전으로 모바일 산업을 초일류 주력산업으로 선정하고, 5대 주력 기간산업과 IT 융합을 위한 기술 개발을 통해 경쟁력을 지속적으로 확보하겠다는 전략을 발표했다. 이미 세계 시장과 산업은 급변하고 있으며 세계 모바일 시장에서 모바일 산업의 지속적인 경쟁력을 유지하고 우위를 확보하기 위해서는 모바일 분야 개발자들의 선택과 집중이 어느 때보다 절실한 시점이다.

제공 : DB포탈사이트 DBguide.net

출처명 : 한국마이크로소프트 [2008년 5월호]

+ Recent posts