Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(719)

Side by Side Diff: device/bluetooth/bluetooth_device_experimental_chromeos.cc

Issue 13927010: Bluetooth: implement BlueZ 5 backend for Chrome OS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix review comment Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/bluetooth/bluetooth_device_experimental_chromeos.h"
6
7 #include "base/bind.h"
8 #include "chromeos/dbus/dbus_thread_manager.h"
9 #include "chromeos/dbus/experimental_bluetooth_adapter_client.h"
10 #include "chromeos/dbus/experimental_bluetooth_agent_manager_client.h"
11 #include "chromeos/dbus/experimental_bluetooth_agent_service_provider.h"
12 #include "chromeos/dbus/experimental_bluetooth_device_client.h"
13 #include "dbus/bus.h"
14 #include "device/bluetooth/bluetooth_adapter_experimental_chromeos.h"
15 #include "device/bluetooth/bluetooth_socket.h"
16 #include "third_party/cros_system_api/dbus/service_constants.h"
17
18 using device::BluetoothDevice;
19
20 namespace {
21
22 // The agent path is relatively meaningless since BlueZ only supports one
23 // at time and will fail in an attempt to register another with "Already Exists"
24 // (which we fail in OnRegisterAgentError with ERROR_INPROGRESS).
25 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
26
27 } // namespace
28
29 namespace chromeos {
30
31 BluetoothDeviceExperimentalChromeOS::BluetoothDeviceExperimentalChromeOS(
32 BluetoothAdapterExperimentalChromeOS* adapter,
33 const dbus::ObjectPath& object_path)
34 : adapter_(adapter),
35 object_path_(object_path),
36 num_connecting_calls_(0),
37 pairing_delegate_(NULL),
38 weak_ptr_factory_(this) {
39 }
40
41 BluetoothDeviceExperimentalChromeOS::~BluetoothDeviceExperimentalChromeOS() {
42 }
43
44 uint32 BluetoothDeviceExperimentalChromeOS::GetBluetoothClass() const {
45 ExperimentalBluetoothDeviceClient::Properties* properties =
46 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
47 GetProperties(object_path_);
48 DCHECK(properties);
49
50 return properties->bluetooth_class.value();
51 }
52
53 std::string BluetoothDeviceExperimentalChromeOS::GetDeviceName() const {
54 ExperimentalBluetoothDeviceClient::Properties* properties =
55 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
56 GetProperties(object_path_);
57 DCHECK(properties);
58
59 return properties->alias.value();
60 }
61
62 std::string BluetoothDeviceExperimentalChromeOS::GetAddress() const {
63 ExperimentalBluetoothDeviceClient::Properties* properties =
64 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
65 GetProperties(object_path_);
66 DCHECK(properties);
67
68 return properties->address.value();
69 }
70
71 bool BluetoothDeviceExperimentalChromeOS::IsPaired() const {
72 ExperimentalBluetoothDeviceClient::Properties* properties =
73 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
74 GetProperties(object_path_);
75 DCHECK(properties);
76
77 return properties->paired.value();
78 }
79
80 bool BluetoothDeviceExperimentalChromeOS::IsConnected() const {
81 ExperimentalBluetoothDeviceClient::Properties* properties =
82 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
83 GetProperties(object_path_);
84 DCHECK(properties);
85
86 return properties->connected.value();
87 }
88
89 bool BluetoothDeviceExperimentalChromeOS::IsConnectable() const {
90 // TODO(deymo): implement
91 return false;
92 }
93
94 bool BluetoothDeviceExperimentalChromeOS::IsConnecting() const {
95 return num_connecting_calls_ > 0;
96 }
97
98 BluetoothDeviceExperimentalChromeOS::ServiceList
99 BluetoothDeviceExperimentalChromeOS::GetServices() const {
100 ExperimentalBluetoothDeviceClient::Properties* properties =
101 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
102 GetProperties(object_path_);
103 DCHECK(properties);
104
105 return properties->uuids.value();
106 }
107
108 void BluetoothDeviceExperimentalChromeOS::GetServiceRecords(
109 const ServiceRecordsCallback& callback,
110 const ErrorCallback& error_callback) {
111 // TODO(keybuk): not implemented; remove
112 error_callback.Run();
113 }
114
115 void BluetoothDeviceExperimentalChromeOS::ProvidesServiceWithName(
116 const std::string& name,
117 const ProvidesServiceCallback& callback) {
118 // TODO(keybuk): not implemented; remove
119 callback.Run(false);
120 }
121
122 bool BluetoothDeviceExperimentalChromeOS::ExpectingPinCode() const {
123 return !pincode_callback_.is_null();
124 }
125
126 bool BluetoothDeviceExperimentalChromeOS::ExpectingPasskey() const {
127 return !passkey_callback_.is_null();
128 }
129
130 bool BluetoothDeviceExperimentalChromeOS::ExpectingConfirmation() const {
131 return !confirmation_callback_.is_null();
132 }
133
134 void BluetoothDeviceExperimentalChromeOS::Connect(
135 BluetoothDevice::PairingDelegate* pairing_delegate,
136 const base::Closure& callback,
137 const ConnectErrorCallback& error_callback) {
138 ++num_connecting_calls_;
139 VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_
140 << " in progress";
141
142 if (IsPaired() || IsConnected() || !pairing_delegate) {
143 // No need to pair, skip straight to connection.
144 ConnectInternal(callback, error_callback);
145 } else {
146 // Initiate high-security connection with pairing.
147 DCHECK(!pairing_delegate_);
148 DCHECK(agent_.get() == NULL);
149
150 pairing_delegate_ = pairing_delegate;
151
152 // The agent path is relatively meaningless since BlueZ only supports
153 // one per application at a time.
154 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
155 agent_.reset(ExperimentalBluetoothAgentServiceProvider::Create(
156 system_bus, dbus::ObjectPath(kAgentPath), this));
157 DCHECK(agent_.get());
158
159 VLOG(1) << object_path_.value() << ": Registering agent for pairing";
160 DBusThreadManager::Get()->GetExperimentalBluetoothAgentManagerClient()->
161 RegisterAgent(
162 dbus::ObjectPath(kAgentPath),
163 bluetooth_agent_manager::kKeyboardDisplayCapability,
164 base::Bind(
165 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgent,
166 weak_ptr_factory_.GetWeakPtr(),
167 callback,
168 error_callback),
169 base::Bind(
170 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgentError,
171 weak_ptr_factory_.GetWeakPtr(),
172 error_callback));
173 }
174 }
175
176 void BluetoothDeviceExperimentalChromeOS::SetPinCode(
177 const std::string& pincode) {
178 if (!agent_.get() || pincode_callback_.is_null())
179 return;
180
181 pincode_callback_.Run(SUCCESS, pincode);
182 pincode_callback_.Reset();
183 }
184
185 void BluetoothDeviceExperimentalChromeOS::SetPasskey(uint32 passkey) {
186 if (!agent_.get() || passkey_callback_.is_null())
187 return;
188
189 passkey_callback_.Run(SUCCESS, passkey);
190 passkey_callback_.Reset();
191 }
192
193 void BluetoothDeviceExperimentalChromeOS::ConfirmPairing() {
194 if (!agent_.get() || confirmation_callback_.is_null())
195 return;
196
197 confirmation_callback_.Run(SUCCESS);
198 confirmation_callback_.Reset();
199 }
200
201 void BluetoothDeviceExperimentalChromeOS::RejectPairing() {
202 RunPairingCallbacks(REJECTED);
203 }
204
205 void BluetoothDeviceExperimentalChromeOS::CancelPairing() {
206 // If there wasn't a callback in progress that we can reply to then we
207 // have to send a CancelPairing() to the device instead.
208 if (!RunPairingCallbacks(CANCELLED)) {
209 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
210 CancelPairing(
211 object_path_,
212 base::Bind(&base::DoNothing),
213 base::Bind(
214 &BluetoothDeviceExperimentalChromeOS::OnCancelPairingError,
215 weak_ptr_factory_.GetWeakPtr()));
216 }
217 }
218
219 void BluetoothDeviceExperimentalChromeOS::Disconnect(
220 const base::Closure& callback,
221 const ErrorCallback& error_callback) {
222 VLOG(1) << object_path_.value() << ": Disconnecting";
223 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
224 Disconnect(
225 object_path_,
226 base::Bind(
227 &BluetoothDeviceExperimentalChromeOS::OnDisconnect,
228 weak_ptr_factory_.GetWeakPtr(),
229 callback),
230 base::Bind(
231 &BluetoothDeviceExperimentalChromeOS::OnDisconnectError,
232 weak_ptr_factory_.GetWeakPtr(),
233 error_callback));
234 }
235
236 void BluetoothDeviceExperimentalChromeOS::Forget(
237 const ErrorCallback& error_callback) {
238 VLOG(1) << object_path_.value() << ": Removing device";
239 DBusThreadManager::Get()->GetExperimentalBluetoothAdapterClient()->
240 RemoveDevice(
241 adapter_->object_path_,
242 object_path_,
243 base::Bind(&base::DoNothing),
244 base::Bind(
245 &BluetoothDeviceExperimentalChromeOS::OnForgetError,
246 weak_ptr_factory_.GetWeakPtr(),
247 error_callback));
248 }
249
250 void BluetoothDeviceExperimentalChromeOS::ConnectToService(
251 const std::string& service_uuid,
252 const SocketCallback& callback) {
253 // TODO(keybuk): implement
254 callback.Run(scoped_refptr<device::BluetoothSocket>());
255 }
256
257 void BluetoothDeviceExperimentalChromeOS::SetOutOfBandPairingData(
258 const device::BluetoothOutOfBandPairingData& data,
259 const base::Closure& callback,
260 const ErrorCallback& error_callback) {
261 // TODO(keybuk): implement
262 error_callback.Run();
263 }
264
265 void BluetoothDeviceExperimentalChromeOS::ClearOutOfBandPairingData(
266 const base::Closure& callback,
267 const ErrorCallback& error_callback) {
268 // TODO(keybuk): implement
269 error_callback.Run();
270 }
271
272
273 void BluetoothDeviceExperimentalChromeOS::Release() {
274 DCHECK(agent_.get());
275 DCHECK(pairing_delegate_);
276 VLOG(1) << object_path_.value() << ": Release";
277
278 pincode_callback_.Reset();
279 passkey_callback_.Reset();
280 confirmation_callback_.Reset();
281
282 UnregisterAgent();
283 }
284
285 void BluetoothDeviceExperimentalChromeOS::RequestPinCode(
286 const dbus::ObjectPath& device_path,
287 const PinCodeCallback& callback) {
288 DCHECK(agent_.get());
289 DCHECK(device_path == object_path_);
290 VLOG(1) << object_path_.value() << ": RequestPinCode";
291
292 DCHECK(pairing_delegate_);
293 DCHECK(pincode_callback_.is_null());
294 pincode_callback_ = callback;
295 pairing_delegate_->RequestPinCode(this);
296 }
297
298 void BluetoothDeviceExperimentalChromeOS::DisplayPinCode(
299 const dbus::ObjectPath& device_path,
300 const std::string& pincode) {
301 DCHECK(agent_.get());
302 DCHECK(device_path == object_path_);
303 VLOG(1) << object_path_.value() << ": DisplayPinCode: " << pincode;
304
305 DCHECK(pairing_delegate_);
306 pairing_delegate_->DisplayPinCode(this, pincode);
307 }
308
309 void BluetoothDeviceExperimentalChromeOS::RequestPasskey(
310 const dbus::ObjectPath& device_path,
311 const PasskeyCallback& callback) {
312 DCHECK(agent_.get());
313 DCHECK(device_path == object_path_);
314 VLOG(1) << object_path_.value() << ": RequestPasskey";
315
316 DCHECK(pairing_delegate_);
317 DCHECK(passkey_callback_.is_null());
318 passkey_callback_ = callback;
319 pairing_delegate_->RequestPasskey(this);
320 }
321
322 void BluetoothDeviceExperimentalChromeOS::DisplayPasskey(
323 const dbus::ObjectPath& device_path,
324 uint32 passkey, int16 entered) {
325 DCHECK(agent_.get());
326 DCHECK(device_path == object_path_);
327 VLOG(1) << object_path_.value() << ": DisplayPasskey: " << passkey
328 << " (" << entered << " entered)";
329
330 // TODO(keybuk): disambiguate entered vs display
331 if (entered > 0)
332 return;
333
334 DCHECK(pairing_delegate_);
335 pairing_delegate_->DisplayPasskey(this, passkey);
336 }
337
338 void BluetoothDeviceExperimentalChromeOS::RequestConfirmation(
339 const dbus::ObjectPath& device_path,
340 uint32 passkey,
341 const ConfirmationCallback& callback) {
342 DCHECK(agent_.get());
343 DCHECK(device_path == object_path_);
344 VLOG(1) << object_path_.value() << ": RequestConfirmation: " << passkey;
345
346 DCHECK(pairing_delegate_);
347 DCHECK(confirmation_callback_.is_null());
348 confirmation_callback_ = callback;
349 pairing_delegate_->ConfirmPasskey(this, passkey);
350 }
351
352 void BluetoothDeviceExperimentalChromeOS::RequestAuthorization(
353 const dbus::ObjectPath& device_path,
354 const ConfirmationCallback& callback) {
355 // TODO(keybuk): implement
356 callback.Run(CANCELLED);
357 }
358
359 void BluetoothDeviceExperimentalChromeOS::AuthorizeService(
360 const dbus::ObjectPath& device_path,
361 const std::string& uuid,
362 const ConfirmationCallback& callback) {
363 // TODO(keybuk): implement
364 callback.Run(CANCELLED);
365 }
366
367 void BluetoothDeviceExperimentalChromeOS::Cancel() {
368 DCHECK(agent_.get());
369 VLOG(1) << object_path_.value() << ": Cancel";
370
371 DCHECK(pairing_delegate_);
372 pairing_delegate_->DismissDisplayOrConfirm();
373 }
374
375 void BluetoothDeviceExperimentalChromeOS::ConnectInternal(
376 const base::Closure& callback,
377 const ConnectErrorCallback& error_callback) {
378 VLOG(1) << object_path_.value() << ": Connecting";
379 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
380 Connect(
381 object_path_,
382 base::Bind(
383 &BluetoothDeviceExperimentalChromeOS::OnConnect,
384 weak_ptr_factory_.GetWeakPtr(),
385 callback),
386 base::Bind(
387 &BluetoothDeviceExperimentalChromeOS::OnConnectError,
388 weak_ptr_factory_.GetWeakPtr(),
389 error_callback));
390 }
391
392 void BluetoothDeviceExperimentalChromeOS::OnConnect(
393 const base::Closure& callback) {
394 --num_connecting_calls_;
395 DCHECK(num_connecting_calls_ >= 0);
396 VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_
397 << " still in progress";
398
399 callback.Run();
400 }
401
402 void BluetoothDeviceExperimentalChromeOS::OnConnectError(
403 const ConnectErrorCallback& error_callback,
404 const std::string& error_name,
405 const std::string& error_message) {
406 --num_connecting_calls_;
407 DCHECK(num_connecting_calls_ >= 0);
408 LOG(WARNING) << object_path_.value() << ": Failed to connect device: "
409 << error_name << ": " << error_message;
410 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
411 << " still in progress";
412
413 // Determine the error code from error_name.
414 ConnectErrorCode error_code = ERROR_UNKNOWN;
415 if (error_name == bluetooth_adapter::kErrorFailed) {
416 error_code = ERROR_FAILED;
417 } else if (error_name == bluetooth_adapter::kErrorInProgress) {
418 error_code = ERROR_INPROGRESS;
419 } else if (error_name == bluetooth_adapter::kErrorNotSupported) {
420 error_code = ERROR_UNSUPPORTED_DEVICE;
421 }
422
423 error_callback.Run(error_code);
424 }
425
426 void BluetoothDeviceExperimentalChromeOS::OnRegisterAgent(
427 const base::Closure& callback,
428 const ConnectErrorCallback& error_callback) {
429 VLOG(1) << object_path_.value() << ": Agent registered, now pairing";
430
431 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
432 Pair(object_path_,
433 base::Bind(
434 &BluetoothDeviceExperimentalChromeOS::OnPair,
435 weak_ptr_factory_.GetWeakPtr(),
436 callback, error_callback),
437 base::Bind(
438 &BluetoothDeviceExperimentalChromeOS::OnPairError,
439 weak_ptr_factory_.GetWeakPtr(),
440 error_callback));
441 }
442
443 void BluetoothDeviceExperimentalChromeOS::OnRegisterAgentError(
444 const ConnectErrorCallback& error_callback,
445 const std::string& error_name,
446 const std::string& error_message) {
447 --num_connecting_calls_;
448 DCHECK(num_connecting_calls_ >= 0);
449 LOG(WARNING) << object_path_.value() << ": Failed to register agent: "
450 << error_name << ": " << error_message;
451 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
452 << " still in progress";
453
454 UnregisterAgent();
455
456 // Determine the error code from error_name.
457 ConnectErrorCode error_code = ERROR_UNKNOWN;
458 if (error_name == bluetooth_adapter::kErrorAlreadyExists)
459 error_code = ERROR_INPROGRESS;
460
461 error_callback.Run(error_code);
462 }
463
464 void BluetoothDeviceExperimentalChromeOS::OnPair(
465 const base::Closure& callback,
466 const ConnectErrorCallback& error_callback) {
467 VLOG(1) << object_path_.value() << ": Paired";
468
469 // Now that we're paired, we need to set the device as trusted so that
470 // incoming connections will be accepted. This should only ever fail if
471 // the device is removed mid-pairing, so do it in the background while
472 // we connect and don't worry about errors.
473 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
474 GetProperties(object_path_)->trusted.Set(
475 true,
476 base::Bind(
477 &BluetoothDeviceExperimentalChromeOS::OnSetTrusted,
478 weak_ptr_factory_.GetWeakPtr()));
479
480 UnregisterAgent();
481
482 // Now we can connect to the device!
483 ConnectInternal(callback, error_callback);
484 }
485
486 void BluetoothDeviceExperimentalChromeOS::OnPairError(
487 const ConnectErrorCallback& error_callback,
488 const std::string& error_name,
489 const std::string& error_message) {
490 --num_connecting_calls_;
491 DCHECK(num_connecting_calls_ >= 0);
492 LOG(WARNING) << object_path_.value() << ": Failed to pair device: "
493 << error_name << ": " << error_message;
494 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
495 << " still in progress";
496
497 UnregisterAgent();
498
499 // Determine the error code from error_name.
500 ConnectErrorCode error_code = ERROR_UNKNOWN;
501 if (error_name == bluetooth_adapter::kErrorConnectionAttemptFailed) {
502 error_code = ERROR_FAILED;
503 } else if (error_name == bluetooth_adapter::kErrorAuthenticationFailed) {
504 error_code = ERROR_AUTH_FAILED;
505 } else if (error_name == bluetooth_adapter::kErrorAuthenticationCanceled) {
506 error_code = ERROR_AUTH_CANCELED;
507 } else if (error_name == bluetooth_adapter::kErrorAuthenticationRejected) {
508 error_code = ERROR_AUTH_REJECTED;
509 } else if (error_name == bluetooth_adapter::kErrorAuthenticationTimeout) {
510 error_code = ERROR_AUTH_TIMEOUT;
511 }
512
513 error_callback.Run(error_code);
514 }
515
516 void BluetoothDeviceExperimentalChromeOS::OnCancelPairingError(
517 const std::string& error_name,
518 const std::string& error_message) {
519 LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: "
520 << error_name << ": " << error_message;
521 }
522
523 void BluetoothDeviceExperimentalChromeOS::OnSetTrusted(bool success) {
524 LOG_IF(WARNING, !success) << object_path_.value()
525 << ": Failed to set device as trusted";
526 }
527
528 void BluetoothDeviceExperimentalChromeOS::UnregisterAgent() {
529 DCHECK(agent_.get());
530 DCHECK(pairing_delegate_);
531
532 DCHECK(pincode_callback_.is_null());
533 DCHECK(passkey_callback_.is_null());
534 DCHECK(confirmation_callback_.is_null());
535
536 pairing_delegate_->DismissDisplayOrConfirm();
537 pairing_delegate_ = NULL;
538
539 agent_.reset();
540
541 // Clean up after ourselves.
542 VLOG(1) << object_path_.value() << ": Unregistering pairing agent";
543 DBusThreadManager::Get()->GetExperimentalBluetoothAgentManagerClient()->
544 UnregisterAgent(
545 dbus::ObjectPath(kAgentPath),
546 base::Bind(&base::DoNothing),
547 base::Bind(
548 &BluetoothDeviceExperimentalChromeOS::OnUnregisterAgentError,
549 weak_ptr_factory_.GetWeakPtr()));
550 }
551
552 void BluetoothDeviceExperimentalChromeOS::OnUnregisterAgentError(
553 const std::string& error_name,
554 const std::string& error_message) {
555 LOG(WARNING) << object_path_.value() << ": Failed to unregister agent: "
556 << error_name << ": " << error_message;
557 }
558
559 void BluetoothDeviceExperimentalChromeOS::OnDisconnect(
560 const base::Closure& callback) {
561 VLOG(1) << object_path_.value() << ": Disconnected";
562 callback.Run();
563 }
564
565 void BluetoothDeviceExperimentalChromeOS::OnDisconnectError(
566 const ErrorCallback& error_callback,
567 const std::string& error_name,
568 const std::string& error_message) {
569 LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: "
570 << error_name << ": " << error_message;
571 error_callback.Run();
572 }
573
574 void BluetoothDeviceExperimentalChromeOS::OnForgetError(
575 const ErrorCallback& error_callback,
576 const std::string& error_name,
577 const std::string& error_message) {
578 LOG(WARNING) << object_path_.value() << ": Failed to remove device: "
579 << error_name << ": " << error_message;
580 error_callback.Run();
581 }
582
583 bool BluetoothDeviceExperimentalChromeOS::RunPairingCallbacks(Status status) {
584 if (!agent_.get())
585 return false;
586
587 bool callback_run = false;
588 if (!pincode_callback_.is_null()) {
589 pincode_callback_.Run(status, "");
590 pincode_callback_.Reset();
591 callback_run = true;
592 }
593
594 if (!passkey_callback_.is_null()) {
595 passkey_callback_.Run(status, 0);
596 passkey_callback_.Reset();
597 callback_run = true;
598 }
599
600 if (!confirmation_callback_.is_null()) {
601 confirmation_callback_.Run(status);
602 confirmation_callback_.Reset();
603 callback_run = true;
604 }
605
606 return callback_run;
607 }
608
609 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698