@protyze/web_pen_sdk
v0.6.13
Published
Neosmartpen typescript library
Downloads
1
Readme
Neo smartpen SDK for Web Platform
Web Pen SDK
This document is written to be used the web_pen_sdk for NeoSmartPen.
Installation
# web_pen_sdk setting
$ npm install web_pen_sdk
$ yarn add web_pen_sdk
Description
PenHelper
scanPen, connectDevice, serviceBinding_16, serviceBinding_128, characteristicBinding, disconnect, dotCallback, handleDot, messageCallback, handleMessage, ncodeToScreen, ncodeToScreen_smartPlate, isSamePage
[펜 연결 설정/해제]
1-1. scanPen
블루투스 펜 연결을 위해 디바이스를 스캔하는 로직입니다.
/** This function scans the device for bluetooth pen connection. */
scanPen = async () => { ... }
// Usage with react hook
const scanPen = () => {
PenHelper.scanPen();
};
<Button onClick={scanPen}></Button>
1-2. connectDevice
실제 블루투스 장비와의 연결을 시도합니다.
connectDevice = async (device: any) => { ... }
1-3. serviceBinding_16, serviceBinding_128
블루투스 service를 16bit/128bit UUID로 binding 합니다.
serviceBinding_16 = async (service: any, device: any) => { ... }
serviceBinding_128 = async (service: any, device: any) => { ... }
1-4. characteristicBinding
블루투스 펜 장비의 연결이 완료된 후 발생되는 펜 event를 처리하기 위해 PenController를 설정합니다. 연결된 펜의 정보, Dot 처리 등 모든 펜 event는 PenController를 통해 처리됩니다. 해당 penController는 PenHelper.pens[] 안에 저장됩니다.
characteristicBinding = (read: any, write: any, device: any) => { ... }
// PenHelper.ts
this.pens = [penController, penController, ...];
// penController 사용씬 2-1 참조
1-5. disconnect
블루투스 장비 연결을 해제합니다.
disconnect = (penController: any) => { ... }
// Usage with react hook
const disconnectPen = () => {
PenHelper.disconnect(controller);
}
[펜 이벤트 정보]
2-1. messageCallback, handleMessage
블루투스 펜의 이벤트를 처리합니다.
handleMessage = (controller: any, type: any, args: any) => { ... }
| Type (Hex) | Title | Description | | |-----------|-------|-------------| - | | 1 (0x01) | PEN_AUTHORIZED | 펜 인증성공 | - | | 2 (0x02) | PEN_PASSWORD_REQUEST | 비밀번호 요청 | - | | 4 (0x04) | PEN_DISCONNECTED | 펜 연결해제 | - | | 6 (0x06) | PEN_CONNECTION_SUCCESS | 펜 연결 성공 | - | | 17 (0x11) | PEN_SETTING_INFO | 펜의 상태정보(배터리, 메모리 등) | 펜 충전시 배터리정보 -> 128 | | 18 (0x12) | PEN_SETUP_SUCCESS | 펜 설정 변경 성공 | - | | 19 (0x13) | PEN_SETUP_FAILURE | 펜 설정 변경 실패 | - | | 26 (0x1a) | PEN_USING_NOTE_SET_RESULT | 실시간 필기 데이터 요청 결과 | - | | 82 (0x52) | PASSWORD_SETUP_SUCCESS | 패스워드 설정 성공 | - | | 83 (0x53) | PASSWORD_SETUP_FAILURE | 패스워드 설정 실패 | - | | 84 (0x54) | PEN_ILLEGAL_PASSWORD_0000 | 신규 패스워드 0000 제한 | - | | 99 (0x63) | EVENT_LOW_BATTERY | 배터리 잔량 부족시 이벤트 | - | | 100 (0x64) | EVENT_POWER_OFF | 전원 OFF 이벤트 | - | | 34 (0x22) | PEN_FW_UPGRADE_STATUS | 펜 펌웨어 업그레이드 상태 | - | | 35 (0x23) | PEN_FW_UPGRADE_SUCCESS | 펜 펌웨어 업그레이드 성공 | - | | 36 (0x24) | PEN_FW_UPGRADE_FAILURE | 펜 펌웨어 업드레이드 실패 | 1=동일버전/2=공간부족/3=실패/4=압축지원X | | 37 (0x25) | PEN_FW_UPGRADE_SUSPEND | 펜 펌웨어 업그레이드 중단 | - | | 48 (0x30) | OFFLINE_DATA_NOTE_LIST | 오프라인 데이터 노트 리스트 | - | | 49 (0x31) | OFFLINE_DATA_PAGE_LIST | 오프라인 데이터 페이지 리스트 | - | | 50 (0x32) | OFFLINE_DATA_SEND_START | 오프라인 데이터 보내기 시작 | - | | 51 (0x33) | OFFLINE_DATA_SEND_STATUS | 오프라인 데이터 보내는 상태 | - | | 52 (0x34) | OFFLINE_DATA_SEND_SUCCESS | 오프라인 데이터 보내기 성공 | - | | 53 (0x35) | OFFLINE_DATA_SEND_FAILURE | 오프라인 데이터 보내기 실패 | - | | 165 (0xa5) | OFFLINE_DATA_DELETE_RESPONSE | 오프라인 데이터 삭제 상태 | - | | 84 (0x54) | PEN_CONNECTION_FAILURE_BTDUPLICATE | 중복되는 블루투스 펜 연결 시도시 실패 | - | | 193 (0xc1) | PEN_PROFILE | 펜의 프로필 | - | | 115 (0x73) | RES_PDS | 펜 PDS | - | | 104 (0x68) | EVENT_DOT_ERROR | 펜 Dot 이벤트 에러 | - | | 105 (0x69) | EVENT_DOT_PUI | 펜 Dot PUI 정보 | - | | 244 (0xf4) | RES_LOG_INFO | 펜 로그 정보 | - | | 245 (0xf5) | RES_LOG_DATA | 펜 로그 데이터 | - |
// Usage with react hook
const [controller, setController] = useState();
const [penVersionInfo, setPenVersionInfo] = useState();
const [battery, setBattery] = useState();
useEffect(() => {
PenHelper.messageCallback = async (mac, type, args) => {
messageProcess(mac, type, args);
}
});
const messageProcess = (mac, type, args) => {
switch(type) {
case PenMessageType.PEN_SETTING_INFO:
const _controller = PenHelper.pens.filter((c) => c.info.MacAddress === mac)[0];
setController(_controller); // 해당 펜의 controller를 등록해준다.
setBattery(args.Battery); // 배터리 상태정보를 저장 -> 충전중일 때 128로 표시
...
case PenMessageType.PEN_DISCONNECTED: // 펜 연결해제시 모든 상태값 초기화
setController(null);
setPenInfo(null);
setBattery(null);
case PenMessageType.PEN_PASSWORD_REQUEST: ... // 패스워드 요청시 처리
onPasswordRequired(args);
case PenMessageType.PEN_SETUP_SUCCESS: // 팬 연결 성공시 처리
if (controller) {
setPenVersionInfo(controller.info);
}
...
}
}
...
const onPasswordRequired = (args: any) => {
const password = input();
...
if (args.RetryCount >= 10) {
alert('펜의 모든정보가 초기화 됩니다.');
}
...
controller.InputPassword(password); // 등록된 펜 controller를 사용하여 비밀번호를 전달한다.
}
...
[펜 Dot 처리]
3-1. dotCallback, handleDot
펜에서 넘어온 dot 데이터는 penController에 등록된 callback 함수인 handleDot을 통해 처리됩니다.
handleDot = (controller: any, args: any) => { ... }
3-2. ncodeToScreen
일반적인 ncode dot 좌표값을 view에 보여지게 하기 위하여 view size에 맞춰 변환시키는 로직입니다.
/**
* This function is to convert the general ncode dot coordinate values according to the view size in order to be shown in the view.
*
* @param {Dot} dot
* @param {View} view
* @param {PaperSize} paperSize
* @returns {ScreenDot}
*/
ncodeToScreen = (dot: Dot, view: View, paperSize: PaperSize) => {
...
}
3-3. ncodeToScreen_smartPlate
SmartPlate의 ncode dot 좌표값을 view에 보여지게 하기 위하여 view size에 맞춰 변환시키는 로직입니다.
/**
* This function is to convert the SmartPlate ncode dot coordinate values according to the view size in order to be shown in the view.
*
* @param {Dot} dot
* @param {View} view
* @param {number} angle - possible angle value [0', 90', 180', 270']
* @param {PaperSize} paperSize
* @returns {ScreenDot}
*/
ncodeToScreen_smartPlate = (dot: Dot, view: View, angle: number, paperSize: PaperSize) => {
...
}
// Usage with react hook
useEffect(() => {
PenHelper.dotCallback = async (mac, dot) => {
strokeProcess(dot);
}
});
const strokeProcess = (dot: Dot) => {
...
const view = { width: canvasFb.width, height: canvasFb.height };
let screenDot: ScreenDot;
if (PenHelper.isSamePage(dot.pageInfo, PlateNcode_3)) { // SmartPlate
screenDot = PenHelper.ncodeToScreen_smartPlate(dot, view, angle, paperSize);
} else { // Default
screenDot = PenHelper.ncodeToScreen(dot, view, paperSize);
}
...
}
[Additional]
4. isSamePage
서로 다른 ncode 페이지 정보(SOBP)를 바탕으로 같은 페이지인지 구별하기 위한 로직입니다. SOBP는 페이지를 구별하기 위한 정보로서, Section/Owner/Book/Page의 줄임말입니다.
/**
* This function is to distinguish whether it is the same page based on different ncode page information (SOBP).
*
* @param {PageInfo} page1
* @param {PageInfo} page2
* @returns {boolean}
*/
isSamePage = (page1: PageInfo, page2: PageInfo) => {
...
}
NoteServer
extractMarginInfo, getNoteImage
1. extractMarginInfo
펜으로부터 받은 페이지 정보(SOBP)를 바탕으로 nproj로 부터 해당 ncode 페이지의 margin info를 추출하는 로직입니다.
/**
* This function is to extract the margin info of the ncode page from nproj based on pageInfo.
*
* @param {PageInfo} pageInfo
* @returns {PaperSize}
*/
const extractMarginInfo = async (pageInfo: PageInfo) => {
...
}
2. getNoteImage
펜으로부터 받은 페이지 정보(SOBP)를 바탕으로 노트의 이미지를 받아오기 위한 로직입니다.
/**
* This function is to get the note image based on pageInfo.
*
* @param {PageInfo} pageInfo
* @param {React.dispatch} setImageBlobUrl
* @returns {boolean} - success -> setImageBlobUrl(imageBlobUrl)
*/
const getNoteImage = async (pageInfo: PageInfo, setImageBlobUrl: any) => {
...
}
// Usage with react hook
const [imageBlobUrl, setImageBlobUrl] = useState<string>();
const [paperSize, setPaperSize] = useState<PaperSize>();
useEffect(() => {
async function getNoteImageUsingAPI(pageInfo) {
await NoteServer.getNoteImage(pageInfo, setImageBlobUrl);
const paperSize: PaperSize = await NoteServer.extractMarginInfo(pageInfo);
setPaperSize(paperSize);
}
if (pageInfo) {
getNoteImageUsingAPI(pageInfo);
}
}, [pageInfo]);
PenController
RequestVersionInfo, SetPassword, InputPassword, RequestPenStatus, SetRtcTime, SetAutoPowerOffTime, SetPenCapPowerOnOffEnable, SetAutoPowerOnEnable, SetBeepSoundEnable, SetHoverEnable, SetOfflineDataEnable, SetColor, RequestAvailableNotes, RequestOfflineNoteList, RequestOfflinePageList, RequestOfflineData, RequestOfflineDelete, RequestFirmwareInstallation, RequestFirmwareUpload, RequestProfileInfo.., RequestProfileReadValue..
| Methods | Parameters |Description | | --- | --- |--- | | RequestVersionInfo | | 펜의 현재 버전을 요청 | | SetPassword | oldone: string, newone: string | 펜에 설정된 비밀번호를 변경 요청 | | InputPassword | password: string | 펜에 비밀번호를 전송 | | RequestPenStatus | | 펜의 각종 설정 확인을 요청 | | SetRtcTime | | 펜에 설정된 시각을 현재 시각으로 변경 요청 | | SetAutoPowerOffTime | minute: number | 펜에 설정된 자동종료 시간을 변경 요청 ( 최대 3600 분 ) | | SetPenCapPowerOnOffEnable | enable: boolean | 펜에 설정된 펜 뚜껑을 이용한 전원 ON/OFF 기능 변경 요청 | | SetAutoPowerOnEnable | enable: boolean | 펜에 설정된 펜 뚜껑 혹은 필기를 이용한 전원 ON 기능 변경 요청 | | SetBeepSoundEnable | enable: boolean | 펜에 설정된 비프음 기능 변경 요청 | | SetHoverEnable | enable: boolean | 펜에 설정된 호버 기능 변경 요청 ( 호버 : 필기 위치 가늠을 위한 시각적 Dot 표시 기능) | | SetOfflineDataEnable | enable: boolean | 펜에 설정된 오프라인 필기 데이터 저장 기능 변경 요청 | | SetColor | color: number | 펜에 설정된 LED 색상 변경 요청 ( argb ) | | RequestAvailableNotes | sections: number[ ], owners: number[ ], notes: number[ ] | null| 펜에 실시간 필기 데이터에 대한 전송을 요청 ( notes 가 null 일 경우 노트 구분 없이 요청 ) | | RequestOfflineNoteList | section: number, owner: number | 펜에 저장된 오프라인 필기 데이터의 페이지 정보(book)를 요청 ( SO 가 0 일 경우 모든 note 리스트 반환 ) | | RequestOfflinePageList | section: number, owner: number, note: number | 펜에 저장된 오프라인 필기 데이터의 페이지 정보(page)를 요청 ( SOB 가 일치하는 한 노트의 page ) | | RequestOfflineData | section: number, owner: number, note: number, deleteOnFinished: boolean, pages: number[ ] | 펜에 저장된 오프라인 필기 데이터를 요청 ( P 가 빈 배열일 경우 노트 내 모든 page 요청 ) ( deleteOnFinished 가 true일 경우 전송 완료된 데이터 삭제 )| | RequestOfflineDelete | section: number, owner: number, notes: number[ ] | 펜에 저장된 오프라인 필기 데이터에 대한 삭제를 요청 | | RequestFirmwareInstallation | file: file, version: string, isCompressed: boolean | 펜에 설치된 펌웨어를 업그레이드하기 위한 질의 | | RequestFirmwareUpload | offset: number, data: Uint8Array, status: number | 펜에 펌웨어 데이터를 업로드 | | RequestProfileCreate | name: string, password: string | 펜에 프로파일 생성을 요청 | | ReqeustProfileDelete | name: string, password: string | 펜에 설정된 프로파일 제거 요청 | | RequestProfileInfo | name: string | 펜에 설정된 프로파일 정보 요청 | | RequestProfileWriteValue | name: string, passsword: string, data: { [key: string]: any } | 펜에 설정된 프로파일 내 데이터 작성 요청 | | RequestProfileReadValue | name: string, keys: string[ ] | 펜에 설정된 프로파일 내 데이터 정보 요청 | | RequestProfileDeleteValue | name: string, password: string, keys: string [ ] | 펜에 설정된 프로파일 내 데이터 제거 요청 |
전체적인 Flow
Library Set
import { PenHelper, NoteServer, PenMessageType } from 'web_pen_sdk';
Step1: PenHelper.scanPen()을 사용하여 pen 연결을 합니다.
/** Connect SmartPen to Web service */
PenHelper.scanPen();
Step2: 펜에 발생되는 이벤트(연결, 배터리정보 등)를 처리합니다.
useEffect(() => {
PenHelper.messageCallback = async (mac, type, args) => {
messageProcess(mac, type, args)
}
});
const messageProcess = (mac, type, args) => {
switch(type) {
case PenMessageType.x:
...
}
}
Step3: 펜으로부터 실시간 dot data를 받아옵니다.
/** Data Parsing from SmartPen */
PenHelper.dotCallback = (mac, dot) => {
strokeProcess(dot);
}
const strokeProcess = (dot: Dot) => {
...
}
Step4: NoteServer.extractMarginInfo()를 사용하여 ncode paper의 size 정보를 받아옵니다.
/** Use NoteServer.extractMarginInfo() function to get size information of the ncode paper. */
const [paperSize, setPaperSize] = useState<PaperSize>();
const paperSize: PaperSize = await NoteServer.extractMarginInfo(pageInfo);
Step5: NoteServer.getNoteImage()를 사용하여 note의 image url을 받아옵니다.
/** Use NoteServer.getNoteImage() function to get image url of the note. */
const [imageBlobUrl, setImageBlobUrl] = useState<string>();
await NoteServer.getNoteImage(pageInfo, setImageBlobUrl);
Step6: 스마트펜으로부터 받은 ncode dot 데이터를 view 사이즈에 맞게 변환하여 사용합니다.
/**
* Draw on Canvas with SmartPen
* Coordinate Transformation with ncode_dot based on view_size, ncode_size
*/
const strokeProcess = (dot: Dot) => {
const view = { width: canvasFb.width, height: canvasFb.height };
// case Default:
const screenDot = PenHelper.ncodeToScreen(dot, view, paperSize);
// case SmartPlate:
const screenDot = PenHelper.ncodeToScreen_smartPlate(dot, view, angle, paperSize)
/** Create path data using screenDot */
const path = new Path(screenDot.x, screenDot.y);
}
🐾 Sample Page
https://github.com/MHCHOI3/web-sdk-sample2
📑 web_pen_sdk 공식문서
Google Docs
📜 License
Copyright(c) 2022, NeoLAB Convergence INC. No license allowed.
Release Note
~2022. 05. 05. (MHCHOI)
Updates
- web_pen_sdk 패키지 배포
- Sample page 구성
2022. 05. 06. (MHCHOI)
New Features
- Pen Event Handler - 펜에서 발생되는 이벤트(연결, 해제, 패스워드 요구 등)를 처리하는 로직 추가
Updates
- Pen Event Handler 추가에 따른 readme 업데이트
- Sample Page에 펜 연결해제 기능 추가, 배터리 정보 표시될 수 있도록 업데이트
- 펜 충전시 배터리 상태정보는 128을 가진다. -> 추가 설명 업데이트
2022. 05. 09. (WONHO)
New Features
- SettingInfo, VersionInfo type declaration
Updates
- SettingInfo, VersionInfo type 정의에 따른 코드 수정
- PenHelper 안에 정의된 any type 수정
2022. 05. 13. (WONHO, ver.0.5.2)
New Features
- DotErrorInfo type declaration
- Dot Event 시 비정상 TimeStamp 시 Error 처리
Updates
- 펜 비밀번호 설정, 변경, 해제 관련 messageType 추가 및 수정
- 오프라인 및 실시간 데이터 관련 messageType 추가 및 수정
- hover를 제외한 모든 Dot는 DotFilter 거치도록 수정
- Packet Escape 로직 수정
2022. 05. 16. (WONHO, ver.0.5.3)
Updates
- SupportedProtocolVersion 수정
2022. 05. 17. (WONHO, ver.0.5.4)
New Features
- PEN_CONNECTION_SUCCESS MessageType declaration
- ONLINE_PEN_HOVER_EVENT - v2.18 용 펜 hover 이벤트 로직 추가
Updates
- SupportedProtocolVersion 수정
2022. 05. 18. (WONHO, ver.0.5.5)
Updates
- SDK 내에서 자동으로 setHover 안하도록 수정
2022. 05. 31. (WONHO, ver.0.5.6)
New Features
- Profile Feature - 펜 프로파일의 생성, 삭제, 조회 및 프로파일 항목의 생성, 삭제, 조회 로직 추가
- Firmware Feature - 펌웨어 업데이트 로직 추가
- PenDisk Init - 펜 디스크 초기화 요청 추가
Updates
- 과밀한 통신 상태에서 블루투스 쓰기 진행 시 중첩연결에 따른 에러 방지 위한 코드 추가
2022. 06. 27. (WONHO, ver.0.5.7)
New Features
- PUI Feature - 펜으로 스마트클래스킷 (부기보드) PUI 클릭 시, 메시지 출력 로직 추가
2022. 07. 04. (WONHO, ver.0.6.6)
New Features
- PUI Feature - PUI 좌표 하드코딩으로 수정
2022. 07. 05. (WONHO, ver.0.6.7)
New Features
- PUI Feature - PUI 좌표 nproj를 json으로 컨버팅해서 사용하도록 수정