1/*
2 * Copyright 2007-2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include <bluetooth/DeviceClass.h>
7#include <bluetooth/debug.h>
8
9#include <Catalog.h>
10#include <Locale.h>
11
12
13#undef B_TRANSLATION_CONTEXT
14#define B_TRANSLATION_CONTEXT "DeviceClass"
15
16
17namespace Bluetooth {
18
19void
20DeviceClass::GetServiceClass(BString& serviceClass)
21{
22	CALLED();
23	static const char *services[] = {
24		B_TRANSLATE_MARK("Positioning"),
25		B_TRANSLATE_MARK("Networking"),
26		B_TRANSLATE_MARK("Rendering"),
27		B_TRANSLATE_MARK("Capturing"),
28		B_TRANSLATE_MARK("Object transfer"),
29		B_TRANSLATE_MARK("Audio"),
30		B_TRANSLATE_MARK("Telephony"),
31		B_TRANSLATE_MARK("Information")
32	};
33
34	if (ServiceClass() != 0) {
35		bool first = true;
36
37		for (uint s = 0; s < (sizeof(services) / sizeof(*services)); s++) {
38			if (ServiceClass() & (1 << s)) {
39				if (first) {
40					first = false;
41					serviceClass << services[s];
42				} else {
43					serviceClass << ", " << services[s];
44				}
45
46			}
47		}
48
49	} else
50		serviceClass << B_TRANSLATE("Unspecified");
51}
52
53
54void
55DeviceClass::GetMajorDeviceClass(BString& majorClass)
56{
57	CALLED();
58	static const char *major_devices[] = {
59		B_TRANSLATE_MARK("Miscellaneous"),
60		B_TRANSLATE_MARK("Computer"),
61		B_TRANSLATE_MARK("Phone"),
62		B_TRANSLATE_MARK("LAN access"),
63		B_TRANSLATE_MARK("Audio/Video"),
64		B_TRANSLATE_MARK("Peripheral"),
65		B_TRANSLATE_MARK("Imaging"),
66		B_TRANSLATE_MARK("Uncategorized")
67	};
68
69	if (MajorDeviceClass() >= sizeof(major_devices) / sizeof(*major_devices))
70		majorClass << B_TRANSLATE("Invalid device class!\n");
71	else
72		majorClass << major_devices[MajorDeviceClass()];
73
74}
75
76
77void
78DeviceClass::GetMinorDeviceClass(BString& minorClass)
79{
80	CALLED();
81	uint major = MajorDeviceClass();
82	uint minor = MinorDeviceClass();
83
84	switch (major) {
85		case 0:	/* misc */
86			minorClass << " -";
87			break;
88		case 1:	/* computer */
89			switch(minor) {
90				case 0:
91					minorClass << B_TRANSLATE("Uncategorized");
92					break;
93				case 1:
94					minorClass << B_TRANSLATE("Desktop workstation");
95					break;
96				case 2:
97					minorClass << B_TRANSLATE("Server");
98					break;
99				case 3:
100					minorClass << B_TRANSLATE("Laptop");
101					break;
102				case 4:
103					minorClass << B_TRANSLATE("Handheld");
104					break;
105				case 5:
106					minorClass << B_TRANSLATE_COMMENT("Palm",
107						"A palm-held device");
108					break;
109				case 6:
110					minorClass << B_TRANSLATE_COMMENT("Wearable",
111						"A wearable computer");
112					break;
113				}
114			break;
115		case 2:	/* phone */
116			switch(minor) {
117				case 0:
118					minorClass << B_TRANSLATE("Uncategorized");
119					break;
120				case 1:
121					minorClass << B_TRANSLATE("Cellular");
122					break;
123				case 2:
124					minorClass << B_TRANSLATE("Cordless");
125					break;
126				case 3:
127					minorClass << B_TRANSLATE("Smart phone");
128					break;
129				case 4:
130					minorClass << B_TRANSLATE("Wired modem or voice gateway");
131					break;
132				case 5:
133					minorClass << B_TRANSLATE("Common ISDN access");
134					break;
135				case 6:
136					minorClass << B_TRANSLATE("SIM card reader");
137					break;
138			}
139			break;
140		case 3:	/* lan access */
141			if (minor == 0) {
142				minorClass << B_TRANSLATE("Uncategorized");
143				break;
144			}
145			switch(minor / 8) {
146				case 0:
147					minorClass << B_TRANSLATE("Fully available");
148					break;
149				case 1:
150					minorClass << B_TRANSLATE("1-17% utilized");
151					break;
152				case 2:
153					minorClass << B_TRANSLATE("17-33% utilized");
154					break;
155				case 3:
156					minorClass << B_TRANSLATE("33-50% utilized");
157					break;
158				case 4:
159					minorClass << B_TRANSLATE("50-67% utilized");
160					break;
161				case 5:
162					minorClass << B_TRANSLATE("67-83% utilized");
163					break;
164				case 6:
165					minorClass << B_TRANSLATE("83-99% utilized");
166					break;
167				case 7:
168					minorClass << B_TRANSLATE("No service available");
169					break;
170			}
171			break;
172		case 4:	/* audio/video */
173			switch(minor) {
174				case 0:
175					minorClass << B_TRANSLATE("Uncategorized");
176					break;
177				case 1:
178					minorClass << B_TRANSLATE("Device conforms to the headset profile");
179					break;
180				case 2:
181					minorClass << B_TRANSLATE("Hands-free");
182					break;
183					/* 3 is reserved */
184				case 4:
185					minorClass << B_TRANSLATE("Microphone");
186					break;
187				case 5:
188					minorClass << B_TRANSLATE("Loudspeaker");
189					break;
190				case 6:
191					minorClass << B_TRANSLATE("Headphones");
192					break;
193				case 7:
194					minorClass << B_TRANSLATE("Portable audio");
195					break;
196				case 8:
197					minorClass << B_TRANSLATE("Car audio");
198					break;
199				case 9:
200					minorClass << B_TRANSLATE("Set-top box");
201					break;
202				case 10:
203					minorClass << B_TRANSLATE("HiFi audio device");
204					break;
205				case 11:
206					minorClass << B_TRANSLATE("VCR");
207					break;
208				case 12:
209					minorClass << B_TRANSLATE("Video camera");
210					break;
211				case 13:
212					minorClass << B_TRANSLATE("Camcorder");
213					break;
214				case 14:
215					minorClass << B_TRANSLATE("Video monitor");
216					break;
217				case 15:
218					minorClass << B_TRANSLATE("Video display and loudspeaker");
219					break;
220				case 16:
221					minorClass << B_TRANSLATE("Video conferencing");
222					break;
223					/* 17 is reserved */
224				case 18:
225					minorClass << B_TRANSLATE("Gaming/Toy");
226					break;
227			}
228			break;
229		case 5:	/* peripheral */
230		{
231			switch(minor & 48) {
232				case 16:
233					minorClass << B_TRANSLATE("Keyboard");
234					if (minor & 15)
235						minorClass << "/";
236					break;
237				case 32:
238					minorClass << B_TRANSLATE("Pointing device");
239					if (minor & 15)
240						minorClass << "/";
241					break;
242				case 48:
243					minorClass << B_TRANSLATE("Combo keyboard/pointing device");
244					if (minor & 15)
245						minorClass << "/";
246					break;
247			}
248
249			switch(minor & 15) {
250				case 0:
251					break;
252				case 1:
253					minorClass << B_TRANSLATE("Joystick");
254					break;
255				case 2:
256					minorClass << B_TRANSLATE("Gamepad");
257					break;
258				case 3:
259					minorClass << B_TRANSLATE("Remote control");
260					break;
261				case 4:
262					minorClass << B_TRANSLATE("Sensing device");
263					break;
264				case 5:
265					minorClass << B_TRANSLATE("Digitizer tablet");
266					break;
267				case 6:
268					minorClass << B_TRANSLATE("Card reader");
269					break;
270				default:
271					minorClass << B_TRANSLATE("(reserved)");
272					break;
273			}
274			break;
275		}
276		case 6:	/* imaging */
277			if (minor & 4)
278				minorClass << B_TRANSLATE("Display");
279			if (minor & 8)
280				minorClass << B_TRANSLATE("Camera");
281			if (minor & 16)
282				minorClass << B_TRANSLATE("Scanner");
283			if (minor & 32)
284				minorClass << B_TRANSLATE("Printer");
285			break;
286		case 7: /* wearable */
287			switch(minor) {
288				case 1:
289					minorClass << B_TRANSLATE("Wrist watch");
290					break;
291				case 2:
292					minorClass << B_TRANSLATE_COMMENT("Pager",
293					"A small radio device to receive short text messages");
294					break;
295				case 3:
296					minorClass << B_TRANSLATE("Jacket");
297					break;
298				case 4:
299					minorClass << B_TRANSLATE("Helmet");
300					break;
301				case 5:
302					minorClass << B_TRANSLATE("Glasses");
303					break;
304			}
305			break;
306		case 8: /* toy */
307			switch(minor) {
308				case 1:
309					minorClass << B_TRANSLATE("Robot");
310					break;
311				case 2:
312					minorClass << B_TRANSLATE("Vehicle");
313					break;
314				case 3:
315					minorClass << B_TRANSLATE("Doll/Action figure");
316					break;
317				case 4:
318					minorClass << B_TRANSLATE("Controller");
319					break;
320				case 5:
321					minorClass << B_TRANSLATE("Game");
322					break;
323			}
324			break;
325		case 63:	/* uncategorised */
326			minorClass << "";
327			break;
328		default:
329			minorClass << B_TRANSLATE("Unknown (reserved) minor device class");
330			break;
331	}
332}
333
334
335void
336DeviceClass::DumpDeviceClass(BString& string)
337{
338	CALLED();
339	string << B_TRANSLATE("Service classes: ");
340	GetServiceClass(string);
341	string << " | ";
342	string << B_TRANSLATE("Major class: ");
343	GetMajorDeviceClass(string);
344	string << " | ";
345	string << B_TRANSLATE("Minor class: ");
346	GetMinorDeviceClass(string);
347	string << ".";
348}
349
350
351void
352DeviceClass::Draw(BView* view, const BPoint& point)
353{
354	CALLED();
355	rgb_color	kBlack = { 0,0,0,0 };
356	rgb_color	kBlue = { 28,110,157,0 };
357	rgb_color	kWhite = { 255,255,255,0 };
358
359
360	view->SetHighColor(kBlue);
361	view->FillRoundRect(BRect(point.x + IconInsets, point.y + IconInsets,
362		point.x + IconInsets + PixelsForIcon, point.y + IconInsets + PixelsForIcon), 5, 5);
363
364	view->SetHighColor(kWhite);
365
366	switch (MajorDeviceClass()) {
367
368		case 2: // phone
369			view->StrokeRoundRect(BRect(point.x + IconInsets + uint(PixelsForIcon/4),
370				 point.y + IconInsets + 6,
371				 point.x + IconInsets + uint(PixelsForIcon*3/4),
372			 	 point.y + IconInsets + PixelsForIcon - 2), 2, 2);
373			view->StrokeRect(BRect(point.x + IconInsets + uint(PixelsForIcon/4) + 4,
374			 	 point.y + IconInsets + 10,
375				 point.x + IconInsets + uint(PixelsForIcon*3/4) - 4,
376			 	 point.y + IconInsets + uint(PixelsForIcon*3/4)));
377			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/4) + 4,
378				 point.y + IconInsets + PixelsForIcon - 6),
379				 BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4) - 4,
380				 point.y + IconInsets + PixelsForIcon - 6));
381			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/4) + 4,
382				 point.y + IconInsets + PixelsForIcon - 4),
383				 BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4) - 4,
384				 point.y + IconInsets + PixelsForIcon - 4));
385			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/4) + 4,
386				 point.y + IconInsets + 2),
387				 BPoint(point.x + IconInsets + uint(PixelsForIcon/4) + 4,
388				 point.y + IconInsets + 6));
389			break;
390		case 3: // LAN
391			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/4),
392				 point.y + IconInsets + uint(PixelsForIcon*3/8)),
393				BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4),
394				 point.y + IconInsets + uint(PixelsForIcon*3/8)));
395			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon*5/8),
396				 point.y + IconInsets + uint(PixelsForIcon/8)));
397			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4),
398				 point.y + IconInsets + uint(PixelsForIcon*5/8)),
399				BPoint(point.x + IconInsets + uint(PixelsForIcon/4),
400				 point.y + IconInsets + uint(PixelsForIcon*5/8)));
401			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon*3/8),
402				 point.y + IconInsets + uint(PixelsForIcon*7/8)));
403			break;
404		case 4: // audio/video
405			view->StrokeRect(BRect(point.x + IconInsets + uint(PixelsForIcon/4),
406				 point.y + IconInsets + uint(PixelsForIcon*3/8),
407				 point.x + IconInsets + uint(PixelsForIcon*3/8),
408			 	 point.y + IconInsets + uint(PixelsForIcon*5/8)));
409			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon*3/8),
410				 point.y + IconInsets + uint(PixelsForIcon*3/8)),
411				BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4),
412				 point.y + IconInsets + uint(PixelsForIcon/8)));
413			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4),
414				 point.y + IconInsets + uint(PixelsForIcon*7/8)));
415			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon*3/8),
416				 point.y + IconInsets + uint(PixelsForIcon*5/8)));
417			break;
418		default: // Bluetooth Logo
419			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/4),
420				 point.y + IconInsets + uint(PixelsForIcon*3/4)),
421				BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4),
422				 point.y + IconInsets + uint(PixelsForIcon/4)));
423			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/2),
424				 point.y + IconInsets +2));
425			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/2),
426				 point.y + IconInsets + PixelsForIcon - 2));
427			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon*3/4),
428				 point.y + IconInsets + uint(PixelsForIcon*3/4)));
429			view->StrokeLine(BPoint(point.x + IconInsets + uint(PixelsForIcon/4),
430				point.y + IconInsets + uint(PixelsForIcon/4)));
431			break;
432	}
433	view->SetHighColor(kBlack);
434}
435
436}
437